UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines • 19.4 kB
{"version":3,"file":"tenant.mjs","names":["UI_REMOTE_ENTRY_FILENAME","UI_REMOTE_SERVER_ENTRY_FILENAME"],"sources":["../../src/ui/tenant.ts"],"sourcesContent":["/**\n * Tenant helpers shared by every ui workspace.\n *\n * Two halves of the tenant surface live here:\n * - origin construction (`buildTenantUrl`, `tenantLabel`, `gatewayForAccount`)\n * - the pure helpers for the org node-config editor: a validated draft of the\n * fields a tenant may customize in its published bos.config.json, prefilled\n * from the currently published config, diffed against it, and an in-browser\n * sha384 preflight so a wrong UI bundle cannot brick the tenant site.\n */\n\nimport { z } from \"zod\";\nimport type { ClientRuntimeConfig } from \"../types\";\nimport { UI_REMOTE_ENTRY_FILENAME, UI_REMOTE_SERVER_ENTRY_FILENAME } from \"./manifest\";\nimport { getRuntimeConfig } from \"./runtime\";\n\nconst LOCALHOST_SUFFIX = \".localhost\";\n\nexport function isLocalHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase();\n return (\n normalized === \"localhost\" ||\n normalized === \"127.0.0.1\" ||\n normalized === \"[::1]\" ||\n normalized.endsWith(LOCALHOST_SUFFIX)\n );\n}\n\n/** Strips a `<label>.<gatewayId>` hostname (or a bare label) down to its label. */\nexport function tenantLabel(hostnameOrLabel: string, gatewayId?: string): string {\n const normalized = hostnameOrLabel.trim().toLowerCase().replace(/\\/+$/, \"\");\n if (!normalized) return \"\";\n const gateway = gatewayId?.trim().toLowerCase();\n if (gateway && normalized.endsWith(`.${gateway}`)) {\n return normalized.slice(0, -(gateway.length + 1));\n }\n if (normalized.endsWith(LOCALHOST_SUFFIX)) {\n return normalized.slice(0, -LOCALHOST_SUFFIX.length);\n }\n return normalized.split(\".\")[0] ?? \"\";\n}\n\nexport interface BuildTenantUrlOptions {\n /** Current browser origin hostname. Defaults to `window.location.hostname`. */\n currentHostname?: string;\n /** Current browser origin port. Defaults to `window.location.port`. */\n currentPort?: string;\n /** Appended to the origin, e.g. `/stake`. */\n path?: string;\n}\n\n/**\n * Builds the absolute origin for a tenant, dev-aware.\n *\n * `buildTenantUrl(\"chicago\", \"citynode.app\")`\n * -> `https://chicago.citynode.app` in production\n * -> `http://chicago.localhost:3000` when served from localhost\n */\nexport function buildTenantUrl(\n hostnameOrLabel: string,\n gatewayId: string,\n options: BuildTenantUrlOptions = {},\n): string | null {\n const label = tenantLabel(hostnameOrLabel, gatewayId);\n if (!label) return null;\n\n const path = options.path ?? \"\";\n const currentHostname =\n options.currentHostname ??\n (typeof window === \"undefined\" ? undefined : window.location.hostname);\n\n if (currentHostname && isLocalHostname(currentHostname)) {\n const currentPort =\n options.currentPort ?? (typeof window === \"undefined\" ? \"\" : window.location.port);\n const port = currentPort ? `:${currentPort}` : \"\";\n return `http://${label}${LOCALHOST_SUFFIX}${port}${path}`;\n }\n\n const gateway = gatewayId.trim().toLowerCase();\n if (!gateway) return null;\n return `https://${label}.${gateway}${path}`;\n}\n\n/**\n * The gateway a slug should publish under for the given owner account,\n * derived from the runtime config instead of hardcoded per-network domains.\n *\n * When the account lives on the same network as the runtime, the current\n * runtime's gateway id is the answer. When the networks differ, the runtime\n * config carries no gateway for that other network, so null is returned and\n * the caller surfaces it rather than guessing a domain.\n */\nexport function gatewayForAccount(\n accountId: string,\n config: Pick<ClientRuntimeConfig, \"networkId\" | \"runtime\"> = getRuntimeConfig(),\n): string | null {\n const gatewayId = config.runtime?.gatewayId;\n if (!gatewayId) return null;\n const testnetAccount = accountId.trim().toLowerCase().endsWith(\".testnet\");\n return testnetAccount === (config.networkId === \"testnet\") ? gatewayId : null;\n}\n\nexport interface TenantUiOverride {\n production: string;\n /** direct entry SRI — only for genuinely fixed-name bundles without a pin */\n integrity?: string;\n /** version-manifest pin — the deploy unit for hashed, atomic deploys */\n pin?: { manifest: string; integrity: string };\n ssr?: string;\n ssrIntegrity?: string;\n}\n\nexport const INTEGRITY_PATTERN = /^sha384-[A-Za-z0-9+/=]+$/;\n\nexport const defaultTenantConfigDraftMessages = {\n url: \"must be a valid URL\",\n integrity: \"must look like sha384-… (base64)\",\n manifest: \"must look like versions/<version-id>.json\",\n title: \"title is required\",\n description: \"description is required\",\n uiPair: \"a UI bundle needs both its URL and its integrity (direct hash or manifest pin)\",\n integrityMode:\n \"choose one integrity mode — a direct entry hash or a version-manifest pin, not both\",\n pinPair: \"a version-manifest pin needs both the manifest filename and its integrity\",\n ssrPair: \"an SSR bundle needs both its URL and its integrity hash\",\n};\n\nexport function createTenantConfigDraftSchema(\n messages: Partial<typeof defaultTenantConfigDraftMessages> = {},\n) {\n const copy = { ...defaultTenantConfigDraftMessages, ...messages };\n const optionalUrl = z\n .string()\n .trim()\n .url(copy.url)\n .or(z.literal(\"\"))\n .transform((value) => value.trim());\n const optionalIntegrity = z\n .string()\n .trim()\n .regex(INTEGRITY_PATTERN, copy.integrity)\n .or(z.literal(\"\"));\n const optionalManifestName = z\n .string()\n .trim()\n .regex(/^versions\\/[0-9a-f]{16}\\.json$/, copy.manifest)\n .or(z.literal(\"\"));\n return z\n .object({\n title: z.string().trim().min(1, copy.title),\n description: z.string().trim().min(1, copy.description),\n repository: optionalUrl,\n uiProduction: optionalUrl,\n uiIntegrity: optionalIntegrity,\n uiManifest: optionalManifestName,\n uiPinIntegrity: optionalIntegrity,\n ssrUrl: optionalUrl,\n ssrIntegrity: optionalIntegrity,\n })\n .refine((draft) => !!draft.uiProduction === !!(draft.uiIntegrity || draft.uiManifest), {\n message: copy.uiPair,\n path: [\"uiIntegrity\"],\n })\n .refine((draft) => !draft.uiIntegrity || !draft.uiManifest, {\n message: copy.integrityMode,\n path: [\"uiManifest\"],\n })\n .refine((draft) => !!draft.uiManifest === !!draft.uiPinIntegrity, {\n message: copy.pinPair,\n path: [\"uiPinIntegrity\"],\n })\n .refine((draft) => !!draft.ssrUrl === !!draft.ssrIntegrity, {\n message: copy.ssrPair,\n path: [\"ssrIntegrity\"],\n });\n}\nexport const tenantConfigDraftSchema = createTenantConfigDraftSchema();\n\nexport type TenantConfigDraft = z.infer<typeof tenantConfigDraftSchema>;\n\nexport const emptyTenantConfigDraft: TenantConfigDraft = {\n title: \"\",\n description: \"\",\n repository: \"\",\n uiProduction: \"\",\n uiIntegrity: \"\",\n uiManifest: \"\",\n uiPinIntegrity: \"\",\n ssrUrl: \"\",\n ssrIntegrity: \"\",\n};\n\ninterface ResolvedUiConfig {\n production?: unknown;\n integrity?: unknown;\n pin?: { manifest?: unknown; integrity?: unknown };\n ssr?: unknown;\n ssrIntegrity?: unknown;\n}\n\nfunction readUi(resolvedConfig: Record<string, unknown> | null | undefined): ResolvedUiConfig {\n const app = resolvedConfig?.app as { ui?: ResolvedUiConfig } | undefined;\n return app?.ui ?? {};\n}\n\nconst asString = (value: unknown) => (typeof value === \"string\" ? value : \"\");\n\nexport function buildDraftFromResolvedConfig(\n resolvedConfig: Record<string, unknown> | null | undefined,\n fallback: { title: string },\n): TenantConfigDraft {\n const ui = readUi(resolvedConfig);\n const title = asString(resolvedConfig?.title) || fallback.title;\n return {\n title,\n description: asString(resolvedConfig?.description) || title,\n repository: asString(resolvedConfig?.repository),\n uiProduction: asString(ui.production),\n uiIntegrity: asString(ui.integrity),\n uiManifest: asString(ui.pin?.manifest),\n uiPinIntegrity: asString(ui.pin?.integrity),\n ssrUrl: asString(ui.ssr),\n ssrIntegrity: asString(ui.ssrIntegrity),\n };\n}\n\nexport interface DraftDiffEntry {\n field: string;\n from: string;\n to: string;\n}\n\nexport function diffDraft(\n draft: TenantConfigDraft,\n resolvedConfig: Record<string, unknown> | null | undefined,\n): DraftDiffEntry[] {\n const ui = readUi(resolvedConfig);\n const pairs: [string, string, string][] = [\n [\"title\", asString(resolvedConfig?.title), draft.title],\n [\"description\", asString(resolvedConfig?.description), draft.description],\n [\"repository\", asString(resolvedConfig?.repository), draft.repository],\n [\"ui bundle\", asString(ui.production), draft.uiProduction],\n [\"ui integrity\", asString(ui.integrity), draft.uiIntegrity],\n [\"ui manifest pin\", asString(ui.pin?.manifest), draft.uiManifest],\n [\"ui pin integrity\", asString(ui.pin?.integrity), draft.uiPinIntegrity],\n [\"ssr bundle\", asString(ui.ssr), draft.ssrUrl],\n [\"ssr integrity\", asString(ui.ssrIntegrity), draft.ssrIntegrity],\n ];\n return pairs\n .filter(([, from, to]) => from !== to)\n .map(([field, from, to]) => ({ field, from: from || \"—\", to: to || \"—\" }));\n}\n\n/** The `app` block for the published config, or undefined when no UI override is set. */\nexport function draftUiOverride(draft: TenantConfigDraft): { ui: TenantUiOverride } | undefined {\n if (!draft.uiProduction) return undefined;\n if (draft.uiManifest && draft.uiPinIntegrity) {\n return {\n ui: {\n production: normalizeBundleBaseUrl(draft.uiProduction),\n pin: { manifest: draft.uiManifest, integrity: draft.uiPinIntegrity },\n ...(draft.ssrUrl && draft.ssrIntegrity\n ? { ssr: normalizeBundleBaseUrl(draft.ssrUrl), ssrIntegrity: draft.ssrIntegrity }\n : {}),\n },\n };\n }\n if (!draft.uiIntegrity) return undefined;\n return {\n ui: {\n production: normalizeBundleBaseUrl(draft.uiProduction),\n integrity: draft.uiIntegrity,\n ...(draft.ssrUrl && draft.ssrIntegrity\n ? { ssr: normalizeBundleBaseUrl(draft.ssrUrl), ssrIntegrity: draft.ssrIntegrity }\n : {}),\n },\n };\n}\n\nexport type IntegrityCheckResult =\n | { status: \"match\" }\n | { status: \"mismatch\"; computed: string }\n | { status: \"unverified\"; reason: string };\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = \"\";\n const chunkSize = 0x8000;\n for (let offset = 0; offset < bytes.length; offset += chunkSize) {\n binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));\n }\n return btoa(binary);\n}\n\nexport async function computeSubresourceIntegrity(url: string): Promise<string> {\n const response = await fetch(url, { cache: \"no-store\" });\n if (!response.ok) {\n throw new Error(`fetching the bundle returned ${response.status}`);\n }\n const buffer = await response.arrayBuffer();\n const digest = await crypto.subtle.digest(\"SHA-384\", buffer);\n return `sha384-${toBase64(new Uint8Array(digest))}`;\n}\n\nexport function resolveClientEntryUrl(url: string): string {\n if (/\\/remoteEntry(\\.[a-f0-9]{8,})?\\.js$/.test(url)) return url;\n if (url.endsWith(\"/mf-manifest.json\"))\n return `${url.replace(/\\/mf-manifest\\.json$/, \"\")}/${UI_REMOTE_ENTRY_FILENAME}`;\n return `${url.replace(/\\/$/, \"\")}/${UI_REMOTE_ENTRY_FILENAME}`;\n}\n\nexport function resolveServerEntryUrl(url: string): string {\n return `${url.replace(/\\/$/, \"\")}/${UI_REMOTE_SERVER_ENTRY_FILENAME}`;\n}\n\nexport function normalizeBundleBaseUrl(url: string): string {\n return url\n .trim()\n .replace(/\\/remoteEntry(\\.server)?(\\.[a-f0-9]{8,})?\\.js$/, \"\")\n .replace(/\\/mf-manifest\\.json$/, \"\");\n}\n\nexport async function computeUiEntryIntegrity(baseUrl: string): Promise<string> {\n return computeSubresourceIntegrity(resolveClientEntryUrl(baseUrl.trim()));\n}\n\nexport async function computeSsrEntryIntegrity(baseUrl: string): Promise<string> {\n return computeSubresourceIntegrity(resolveServerEntryUrl(baseUrl.trim()));\n}\n\nasync function verifyEntryIntegrity(\n entryUrl: string,\n expected: string,\n): Promise<IntegrityCheckResult> {\n try {\n const computed = await computeSubresourceIntegrity(entryUrl);\n return computed === expected ? { status: \"match\" } : { status: \"mismatch\", computed };\n } catch (error) {\n return {\n status: \"unverified\",\n reason: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport async function verifyUiIntegrity(\n baseUrl: string,\n expected: string,\n): Promise<IntegrityCheckResult> {\n return verifyEntryIntegrity(resolveClientEntryUrl(baseUrl.trim()), expected);\n}\n\n/**\n * Pin preflight: fetch the pinned version-manifest document and SRI-compare it\n * against the pin — the manifest's own `entryIntegrity` covers the entry bytes\n * at serve time.\n */\nexport async function verifyUiPin(\n baseUrl: string,\n pin: { manifest: string; integrity: string },\n): Promise<IntegrityCheckResult> {\n const manifestUrl = `${baseUrl.trim().replace(/\\/$/, \"\")}/${pin.manifest.replace(/^\\//, \"\")}`;\n return verifyEntryIntegrity(manifestUrl, pin.integrity);\n}\n\nexport async function verifySsrIntegrity(\n baseUrl: string,\n expected: string,\n): Promise<IntegrityCheckResult> {\n return verifyEntryIntegrity(resolveServerEntryUrl(baseUrl.trim()), expected);\n}\n"],"mappings":"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"}