Files
zpan/server/licensing/instance-info.ts
T
saltboandClaude Opus 4.8 53ca110218 feat(about): split runtime into runtime engine + deployment platform
Flatten the instance `runtime` object into two fields: `runtime` (the JS engine,
node | workerd) and `platform` (the deployment host). The About page shows each
as its own row with friendly labels (e.g. "workerd" + "Cloudflare Workers",
"Node.js" + "Docker").

- Detect the platform from the entry file (entry === target): each serverless
  entry declares it; entry-node sniffs Cloud Run (K_SERVICE) / Docker
  (ZPAN_RUNTIME, set in the Dockerfile) / bare node. Cloudflare is detected from
  the D1 binding.
- Decouple the cloud payload: zpan-cloud-sdk fixes runtime { provider, target },
  so CloudInstanceInfo keeps that shape and buildCloudInstanceInfo maps to it;
  buildInstanceInfo serves the richer flat shape to the About API.
- Migrate PostHog instance telemetry to the runtime/platform shape and merge the
  duplicate runtimeInfo in licensing-admin into the shared one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 14:56:29 -04:00

78 lines
2.5 KiB
TypeScript

import { release as osRelease } from 'node:os'
import { eq } from 'drizzle-orm'
import type { InstanceInfo } from '../../shared/types'
import { systemOptions } from '../db/schema'
import type { Database, Platform } from '../platform/interface'
import { getDeployPlatform } from '../runtime-platform'
import type { CloudInstanceInfo } from '../services/licensing-cloud'
import { getAppCommit, getAppVersion } from '../version'
import { getOrCreateInstanceId } from './instance-id'
type RuntimeInfo = Pick<InstanceInfo, 'runtime' | 'platform' | 'server' | 'node'>
export function runtimeInfo(platform: Platform): RuntimeInfo {
if (platform.getBinding('DB')) {
return { runtime: 'workerd', platform: 'cloudflare-workers' }
}
return {
runtime: 'node',
platform: getDeployPlatform() ?? 'node',
server: { os: { platform: process.platform, arch: process.arch, release: osRelease() } },
node: { version: process.version },
}
}
export async function getInstanceDisplayName(db: Database): Promise<string> {
const rows = await db
.select({ value: systemOptions.value })
.from(systemOptions)
.where(eq(systemOptions.key, 'site_title'))
.limit(1)
return rows[0]?.value ?? 'ZPan'
}
// Shown on the admin About page: flat runtime engine + deployment platform.
export async function buildInstanceInfo(
db: Database,
params: { url: string; runtime?: RuntimeInfo },
): Promise<InstanceInfo> {
return {
id: await getOrCreateInstanceId(db),
name: await getInstanceDisplayName(db),
url: params.url,
version: getAppVersion(),
commit: getAppCommit(),
...params.runtime,
}
}
// Reported to ZPan Cloud. The cloud SDK fixes the coarse `runtime { provider,
// target }` shape, so collapse the richer platform back to it here.
function toCloudRuntime(info?: RuntimeInfo): Pick<CloudInstanceInfo, 'runtime' | 'server' | 'node'> {
if (!info?.runtime) return {}
const cloudflare = info.runtime === 'workerd'
return {
runtime: {
provider: cloudflare ? 'cloudflare' : 'node',
target: cloudflare ? 'cloudflare-worker' : 'node/docker',
},
server: info.server,
node: info.node,
}
}
export async function buildCloudInstanceInfo(
db: Database,
params: { url: string; runtime?: RuntimeInfo },
): Promise<CloudInstanceInfo> {
return {
id: await getOrCreateInstanceId(db),
name: await getInstanceDisplayName(db),
url: params.url,
version: getAppVersion(),
commit: getAppCommit(),
...toCloudRuntime(params.runtime),
}
}