everything-dev 2.0.0-rc.8 → 2.0.0-rc.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/upload/src/client.cjs +7 -1
- package/dist/apps/upload/src/client.cjs.map +1 -1
- package/dist/apps/upload/src/client.mjs +7 -1
- package/dist/apps/upload/src/client.mjs.map +1 -1
- package/dist/auth-login.cjs +24 -1
- package/dist/auth-login.cjs.map +1 -1
- package/dist/auth-login.mjs +24 -1
- package/dist/auth-login.mjs.map +1 -1
- package/dist/auth-session.cjs +4 -2
- package/dist/auth-session.cjs.map +1 -1
- package/dist/auth-session.mjs +4 -2
- package/dist/auth-session.mjs.map +1 -1
- package/dist/cdn-deploy.cjs +11 -7
- package/dist/cdn-deploy.cjs.map +1 -1
- package/dist/cdn-deploy.mjs +11 -7
- package/dist/cdn-deploy.mjs.map +1 -1
- package/dist/cli/import.cjs +1140 -0
- package/dist/cli/import.cjs.map +1 -0
- package/dist/cli/import.mjs +1126 -0
- package/dist/cli/import.mjs.map +1 -0
- package/dist/cli/init.cjs +11 -4
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +8 -2
- package/dist/cli/init.d.mts +8 -2
- package/dist/cli/init.mjs +11 -5
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli.cjs +55 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +55 -0
- package/dist/cli.mjs.map +1 -1
- package/dist/commands/import.cjs +49 -0
- package/dist/commands/import.cjs.map +1 -0
- package/dist/commands/import.mjs +46 -0
- package/dist/commands/import.mjs.map +1 -0
- package/dist/commands/keys.cjs +24 -3
- package/dist/commands/keys.cjs.map +1 -1
- package/dist/commands/keys.mjs +24 -3
- package/dist/commands/keys.mjs.map +1 -1
- package/dist/config.d.cts +1 -0
- package/dist/config.d.mts +1 -0
- package/dist/contract.cjs +89 -0
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +190 -1
- package/dist/contract.d.mts +190 -1
- package/dist/contract.meta.cjs +16 -0
- package/dist/contract.meta.cjs.map +1 -1
- package/dist/contract.meta.d.cts +26 -0
- package/dist/contract.meta.d.mts +26 -0
- package/dist/contract.meta.mjs +16 -0
- package/dist/contract.meta.mjs.map +1 -1
- package/dist/contract.mjs +84 -1
- package/dist/contract.mjs.map +1 -1
- package/dist/custody-signer.cjs +70 -0
- package/dist/custody-signer.cjs.map +1 -0
- package/dist/custody-signer.mjs +68 -0
- package/dist/custody-signer.mjs.map +1 -0
- package/dist/descriptor/schema.cjs +8 -5
- package/dist/descriptor/schema.cjs.map +1 -1
- package/dist/descriptor/schema.d.cts +1 -0
- package/dist/descriptor/schema.d.mts +1 -0
- package/dist/descriptor/schema.mjs +8 -5
- package/dist/descriptor/schema.mjs.map +1 -1
- package/dist/descriptor/serialize.cjs +1 -1
- package/dist/descriptor/serialize.cjs.map +1 -1
- package/dist/descriptor/serialize.mjs +1 -1
- package/dist/descriptor/serialize.mjs.map +1 -1
- package/dist/index.cjs +6 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/outlayer-login.cjs +54 -0
- package/dist/outlayer-login.cjs.map +1 -0
- package/dist/outlayer-login.mjs +54 -0
- package/dist/outlayer-login.mjs.map +1 -0
- package/dist/plugin.cjs +2 -0
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +74 -0
- package/dist/plugin.d.mts +74 -0
- package/dist/plugin.mjs +2 -0
- package/dist/plugin.mjs.map +1 -1
- package/dist/publish.cjs +145 -22
- package/dist/publish.cjs.map +1 -1
- package/dist/publish.mjs +147 -24
- package/dist/publish.mjs.map +1 -1
- package/dist/source-archive.cjs +51 -0
- package/dist/source-archive.cjs.map +1 -0
- package/dist/source-archive.mjs +50 -0
- package/dist/source-archive.mjs.map +1 -0
- package/dist/storage-upload.cjs +6 -1
- package/dist/storage-upload.cjs.map +1 -1
- package/dist/storage-upload.mjs +6 -1
- package/dist/storage-upload.mjs.map +1 -1
- package/dist/types.cjs +5 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +2 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +5 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils/workspace-subtree.cjs +37 -0
- package/dist/utils/workspace-subtree.cjs.map +1 -0
- package/dist/utils/workspace-subtree.mjs +36 -0
- package/dist/utils/workspace-subtree.mjs.map +1 -0
- package/dist/version-manifest-deploy.cjs +4 -2
- package/dist/version-manifest-deploy.cjs.map +1 -1
- package/dist/version-manifest-deploy.mjs +4 -2
- package/dist/version-manifest-deploy.mjs.map +1 -1
- package/dist/version-manifest-resolve.cjs +2 -1
- package/dist/version-manifest-resolve.cjs.map +1 -1
- package/dist/version-manifest-resolve.d.cts +3 -0
- package/dist/version-manifest-resolve.d.mts +3 -0
- package/dist/version-manifest-resolve.mjs +2 -1
- package/dist/version-manifest-resolve.mjs.map +1 -1
- package/package.json +3 -2
- package/skills/cli-reference/SKILL.md +17 -1
- package/skills/init-upgrade/SKILL.md +76 -3
package/dist/cdn-deploy.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdn-deploy.cjs","names":[],"sources":["../src/cdn-deploy.ts"],"sourcesContent":["interface SessionCredentialLike {\n apiKey?: string;\n siteUrl?: string;\n accountId?: string | null;\n}\n\nexport interface CdnDeployInputs {\n cdnOrigin: string | undefined;\n storageOrigin: string;\n apiKey: string | undefined;\n warning?: string;\n error?: string;\n}\n\nconst LOCAL_HOSTNAMES = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\", \"0.0.0.0\", \"local\"]);\n\n/** Local/private destinations can never serve production bundles. */\nexport function isLocalOrigin(url: string): boolean {\n try {\n const { hostname, protocol } = new URL(url);\n if (protocol !== \"http:\" && protocol !== \"https:\") return true;\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n return (\n LOCAL_HOSTNAMES.has(host) ||\n host.endsWith(\".localhost\") ||\n host.endsWith(\".local\") ||\n /^127\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^10\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^192\\.168\\.\\d+\\.\\d+$/.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+$/.test(host) ||\n host.startsWith(\"169.254.\") ||\n (host.includes(\":\") &&\n (host.startsWith(\"fe80:\") || host.startsWith(\"fc\") || host.startsWith(\"fd\")))\n );\n } catch {\n return true;\n }\n}\n\n/**\n * Deploy origin resolution (ADR 0020, as amended): the CDN origin comes from\n * the env or the authored `cdn.origin` (inherited via extends) — a hard\n * requirement when uploads are planned, because the host never serves\n * `/bundles` itself. The upload origin is the env, the `bos login` session's\n * siteUrl, or the runtime's own gateway. A session pinned to a local site is\n * a hard error (the origin can only ever be a squatter's port); an env-pinned\n * local origin is deliberate local testing and only warns. Config-only\n * publishes (`uploadsPlanned: false`) ship the committed config verbatim —\n * no origins are resolved and nothing is required.\n */\nexport function resolveCdnDeployInputs(input: {\n env: Record<string, string | undefined>;\n bosConfig: { cdn?: { origin?: string } } | null;\n session: SessionCredentialLike | null;\n account: string;\n gateway: string;\n uploadsPlanned: boolean;\n}): CdnDeployInputs {\n const envCdnOrigin = input.env.BOS_BUNDLE_CDN_ORIGIN?.replace(/\\/$/, \"\");\n const configCdnOrigin = input.bosConfig?.cdn?.origin?.replace(/\\/$/, \"\");\n const storageEnvOrigin = input.env.BOS_STORAGE_ORIGIN?.replace(/\\/$/, \"\");\n const sessionSite = input.session?.siteUrl?.replace(/\\/$/, \"\");\n const apiKey = input.env.BOS_STORAGE_API_KEY ?? input.session?.apiKey;\n const uploadsPlanned = input.uploadsPlanned;\n\n const storageOriginDefault = storageEnvOrigin ?? sessionSite ?? `https://${input.gateway}`;\n\n if (!uploadsPlanned) {\n return { cdnOrigin: undefined, storageOrigin: storageOriginDefault, apiKey };\n }\n\n let cdnOrigin: string | undefined;\n let warning: string | undefined;\n if (envCdnOrigin) {\n cdnOrigin = envCdnOrigin;\n if (isLocalOrigin(envCdnOrigin)) {\n warning = `BOS_BUNDLE_CDN_ORIGIN is a local URL (${envCdnOrigin}) — deploying to a local stack, published bundle URLs will not resolve publicly.`;\n }\n } else if (configCdnOrigin) {\n if (isLocalOrigin(configCdnOrigin)) {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n `the authored config sets cdn.origin to the local URL ${configCdnOrigin} — deploy bundle ` +\n \"origins must be publicly reachable. Set BOS_BUNDLE_CDN_ORIGIN for a local deploy, \" +\n \"or fix cdn.origin (inherited via extends).\",\n };\n }\n cdnOrigin = configCdnOrigin;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n \"CDN deploy requires a bundle origin — set `cdn.origin` in bos.config.json \" +\n \"(children inherit it from the base runtime via extends) or BOS_BUNDLE_CDN_ORIGIN \" +\n \"in the environment.\",\n };\n }\n\n let storageOrigin: string;\n if (storageEnvOrigin) {\n storageOrigin = storageEnvOrigin;\n if (isLocalOrigin(storageEnvOrigin) && !warning) {\n warning = `BOS_STORAGE_ORIGIN is a local URL (${storageEnvOrigin}) — uploading to a local stack.`;\n }\n } else if (sessionSite) {\n if (isLocalOrigin(sessionSite)) {\n return {\n cdnOrigin,\n storageOrigin: sessionSite,\n apiKey,\n error:\n `The CLI session pins uploads to ${sessionSite} — a local site can never receive ` +\n \"production bundles. Re-run `bos login` against the production site, or set \" +\n \"BOS_STORAGE_ORIGIN explicitly.\",\n };\n }\n storageOrigin = sessionSite;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n warning,\n error:\n `Bundle uploads require an upload-service origin — the gateway (${input.gateway}) no longer serves ` +\n \"uploads (ADR 0027: the upload service is standalone at upload.everything.dev). Set BOS_STORAGE_ORIGIN \" +\n \"in the environment (CI) or re-run `bos login` against the production site so the session pins it.\",\n };\n }\n\n if (!apiKey) {\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error:\n \"CDN deploy requires bundle-upload credentials — run `bos login --key` and add the printed key \" +\n \"to GitHub secrets as BOS_STORAGE_API_KEY (or run `bos login` for interactive deploys)\",\n };\n }\n if (input.session?.accountId && input.session.accountId !== input.account) {\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error: `The CLI session was created for ${input.session.accountId}, but the configured account is ${input.account}. Re-run bos login under the matching account.`,\n };\n }\n return { cdnOrigin, storageOrigin, apiKey, warning };\n}\n\n/**\n * Pre-upload probe: the storage origin must actually be the bundle-upload\n * service.\n * `/health` is the primary readiness check, with MCP kept as a compatibility\n * fallback for older fixtures and legacy hosts.\n */\nexport async function probeStorageOrigin(\n storageOrigin: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<string | undefined> {\n const base = storageOrigin.replace(/\\/$/, \"\");\n const healthUrl = `${base}/health`;\n const mcpUrl = `${base}/.well-known/mcp.json`;\n let response: Response;\n try {\n response = await fetchImpl(healthUrl, { headers: { accept: \"text/plain\" } });\n } catch (error) {\n return `unreachable (${String(error instanceof Error ? error.message : error)})`;\n }\n if (response.ok) {\n const body = await response.text().catch(() => \"\");\n if (body.trim() === \"OK\" || body.trim().length === 0) return undefined;\n }\n let mcpResponse: Response;\n try {\n mcpResponse = await fetchImpl(mcpUrl, { headers: { accept: \"application/json\" } });\n } catch {\n return `GET /health responded ${response.status}; fallback /.well-known/mcp.json unreachable`;\n }\n if (!mcpResponse.ok) {\n return `GET /health responded ${response.status}; GET /.well-known/mcp.json responded ${mcpResponse.status}`;\n }\n try {\n const body = await mcpResponse.json();\n if (!body || typeof body !== \"object\") {\n return \"did not return the platform MCP descriptor\";\n }\n return undefined;\n } catch {\n return \"did not return the platform MCP descriptor (non-JSON response)\";\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cdn-deploy.cjs","names":[],"sources":["../src/cdn-deploy.ts"],"sourcesContent":["interface SessionCredentialLike {\n apiKey?: string;\n siteUrl?: string;\n accountId?: string | null;\n}\n\nexport interface CdnDeployInputs {\n cdnOrigin: string | undefined;\n storageOrigin: string;\n apiKey: string | undefined;\n warning?: string;\n error?: string;\n}\n\nconst LOCAL_HOSTNAMES = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\", \"0.0.0.0\", \"local\"]);\n\n/** Local/private destinations can never serve production bundles. */\nexport function isLocalOrigin(url: string): boolean {\n try {\n const { hostname, protocol } = new URL(url);\n if (protocol !== \"http:\" && protocol !== \"https:\") return true;\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n return (\n LOCAL_HOSTNAMES.has(host) ||\n host.endsWith(\".localhost\") ||\n host.endsWith(\".local\") ||\n /^127\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^10\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^192\\.168\\.\\d+\\.\\d+$/.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+$/.test(host) ||\n host.startsWith(\"169.254.\") ||\n (host.includes(\":\") &&\n (host.startsWith(\"fe80:\") || host.startsWith(\"fc\") || host.startsWith(\"fd\")))\n );\n } catch {\n return true;\n }\n}\n\n/**\n * Deploy origin resolution (ADR 0020, as amended): the CDN origin comes from\n * the env or the authored `cdn.origin` (inherited via extends) — a hard\n * requirement when uploads are planned, because the host never serves\n * `/bundles` itself. The upload origin is the env, the `bos login` session's\n * siteUrl, or the runtime's own gateway. A session pinned to a local site is\n * a hard error (the origin can only ever be a squatter's port); an env-pinned\n * local origin is deliberate local testing and only warns. Config-only\n * publishes (`uploadsPlanned: false`) ship the committed config verbatim —\n * no origins are resolved and nothing is required.\n */\nexport function resolveCdnDeployInputs(input: {\n env: Record<string, string | undefined>;\n bosConfig: { cdn?: { origin?: string } } | null;\n session: SessionCredentialLike | null;\n custodyAccount?: string;\n account: string;\n gateway: string;\n uploadsPlanned: boolean;\n}): CdnDeployInputs {\n const envCdnOrigin = input.env.BOS_BUNDLE_CDN_ORIGIN?.replace(/\\/$/, \"\");\n const configCdnOrigin = input.bosConfig?.cdn?.origin?.replace(/\\/$/, \"\");\n const storageEnvOrigin = input.env.BOS_STORAGE_ORIGIN?.replace(/\\/$/, \"\");\n const sessionSite = input.session?.siteUrl?.replace(/\\/$/, \"\");\n const apiKey = input.env.BOS_STORAGE_API_KEY ?? input.session?.apiKey;\n const uploadsPlanned = input.uploadsPlanned;\n\n const storageOriginDefault = storageEnvOrigin ?? sessionSite ?? `https://${input.gateway}`;\n\n if (!uploadsPlanned) {\n return { cdnOrigin: undefined, storageOrigin: storageOriginDefault, apiKey };\n }\n\n let cdnOrigin: string | undefined;\n let warning: string | undefined;\n if (envCdnOrigin) {\n cdnOrigin = envCdnOrigin;\n if (isLocalOrigin(envCdnOrigin)) {\n warning = `BOS_BUNDLE_CDN_ORIGIN is a local URL (${envCdnOrigin}) — deploying to a local stack, published bundle URLs will not resolve publicly.`;\n }\n } else if (configCdnOrigin) {\n if (isLocalOrigin(configCdnOrigin)) {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n `the authored config sets cdn.origin to the local URL ${configCdnOrigin} — deploy bundle ` +\n \"origins must be publicly reachable. Set BOS_BUNDLE_CDN_ORIGIN for a local deploy, \" +\n \"or fix cdn.origin (inherited via extends).\",\n };\n }\n cdnOrigin = configCdnOrigin;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n \"CDN deploy requires a bundle origin — set `cdn.origin` in bos.config.json \" +\n \"(children inherit it from the base runtime via extends) or BOS_BUNDLE_CDN_ORIGIN \" +\n \"in the environment.\",\n };\n }\n\n let storageOrigin: string;\n if (storageEnvOrigin) {\n storageOrigin = storageEnvOrigin;\n if (isLocalOrigin(storageEnvOrigin) && !warning) {\n warning = `BOS_STORAGE_ORIGIN is a local URL (${storageEnvOrigin}) — uploading to a local stack.`;\n }\n } else if (sessionSite) {\n if (isLocalOrigin(sessionSite)) {\n return {\n cdnOrigin,\n storageOrigin: sessionSite,\n apiKey,\n error:\n `The CLI session pins uploads to ${sessionSite} — a local site can never receive ` +\n \"production bundles. Re-run `bos login` against the production site, or set \" +\n \"BOS_STORAGE_ORIGIN explicitly.\",\n };\n }\n storageOrigin = sessionSite;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n warning,\n error:\n `Bundle uploads require an upload-service origin — the gateway (${input.gateway}) no longer serves ` +\n \"uploads (ADR 0027: the upload service is standalone at upload.everything.dev). Set BOS_STORAGE_ORIGIN \" +\n \"in the environment (CI) or re-run `bos login` against the production site so the session pins it.\",\n };\n }\n\n if (!apiKey) {\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error:\n \"CDN deploy requires bundle-upload credentials — run `bos login --key` and add the printed key \" +\n \"to GitHub secrets as BOS_STORAGE_API_KEY (or run `bos login` for interactive deploys)\",\n };\n }\n const uploadIdentities = new Set(\n [input.session?.accountId, input.custodyAccount].filter((id): id is string => !!id),\n );\n if (uploadIdentities.size > 0 && !uploadIdentities.has(input.account)) {\n const sessionAccount = input.session?.accountId;\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error: sessionAccount\n ? `The CLI session was created for ${sessionAccount}, but the configured account is ${input.account}. Re-run bos login under the matching account.`\n : `The configured account is ${input.account}, but the custody publish identity is ${input.custodyAccount}. Set the authored config's account to the custody wallet account.`,\n };\n }\n return { cdnOrigin, storageOrigin, apiKey, warning };\n}\n\n/**\n * Pre-upload probe: the storage origin must actually be the bundle-upload\n * service.\n * `/health` is the primary readiness check, with MCP kept as a compatibility\n * fallback for older fixtures and legacy hosts.\n */\nexport async function probeStorageOrigin(\n storageOrigin: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<string | undefined> {\n const base = storageOrigin.replace(/\\/$/, \"\");\n const healthUrl = `${base}/health`;\n const mcpUrl = `${base}/.well-known/mcp.json`;\n let response: Response;\n try {\n response = await fetchImpl(healthUrl, { headers: { accept: \"text/plain\" } });\n } catch (error) {\n return `unreachable (${String(error instanceof Error ? error.message : error)})`;\n }\n if (response.ok) {\n const body = await response.text().catch(() => \"\");\n if (body.trim() === \"OK\" || body.trim().length === 0) return undefined;\n }\n let mcpResponse: Response;\n try {\n mcpResponse = await fetchImpl(mcpUrl, { headers: { accept: \"application/json\" } });\n } catch {\n return `GET /health responded ${response.status}; fallback /.well-known/mcp.json unreachable`;\n }\n if (!mcpResponse.ok) {\n return `GET /health responded ${response.status}; GET /.well-known/mcp.json responded ${mcpResponse.status}`;\n }\n try {\n const body = await mcpResponse.json();\n if (!body || typeof body !== \"object\") {\n return \"did not return the platform MCP descriptor\";\n }\n return undefined;\n } catch {\n return \"did not return the platform MCP descriptor (non-JSON response)\";\n }\n}\n"],"mappings":"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"}
|
package/dist/cdn-deploy.mjs
CHANGED
|
@@ -87,13 +87,17 @@ function resolveCdnDeployInputs(input) {
|
|
|
87
87
|
warning,
|
|
88
88
|
error: "CDN deploy requires bundle-upload credentials — run `bos login --key` and add the printed key to GitHub secrets as BOS_STORAGE_API_KEY (or run `bos login` for interactive deploys)"
|
|
89
89
|
};
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
const uploadIdentities = new Set([input.session?.accountId, input.custodyAccount].filter((id) => !!id));
|
|
91
|
+
if (uploadIdentities.size > 0 && !uploadIdentities.has(input.account)) {
|
|
92
|
+
const sessionAccount = input.session?.accountId;
|
|
93
|
+
return {
|
|
94
|
+
cdnOrigin,
|
|
95
|
+
storageOrigin,
|
|
96
|
+
apiKey,
|
|
97
|
+
warning,
|
|
98
|
+
error: sessionAccount ? `The CLI session was created for ${sessionAccount}, but the configured account is ${input.account}. Re-run bos login under the matching account.` : `The configured account is ${input.account}, but the custody publish identity is ${input.custodyAccount}. Set the authored config's account to the custody wallet account.`
|
|
99
|
+
};
|
|
100
|
+
}
|
|
97
101
|
return {
|
|
98
102
|
cdnOrigin,
|
|
99
103
|
storageOrigin,
|
package/dist/cdn-deploy.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdn-deploy.mjs","names":[],"sources":["../src/cdn-deploy.ts"],"sourcesContent":["interface SessionCredentialLike {\n apiKey?: string;\n siteUrl?: string;\n accountId?: string | null;\n}\n\nexport interface CdnDeployInputs {\n cdnOrigin: string | undefined;\n storageOrigin: string;\n apiKey: string | undefined;\n warning?: string;\n error?: string;\n}\n\nconst LOCAL_HOSTNAMES = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\", \"0.0.0.0\", \"local\"]);\n\n/** Local/private destinations can never serve production bundles. */\nexport function isLocalOrigin(url: string): boolean {\n try {\n const { hostname, protocol } = new URL(url);\n if (protocol !== \"http:\" && protocol !== \"https:\") return true;\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n return (\n LOCAL_HOSTNAMES.has(host) ||\n host.endsWith(\".localhost\") ||\n host.endsWith(\".local\") ||\n /^127\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^10\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^192\\.168\\.\\d+\\.\\d+$/.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+$/.test(host) ||\n host.startsWith(\"169.254.\") ||\n (host.includes(\":\") &&\n (host.startsWith(\"fe80:\") || host.startsWith(\"fc\") || host.startsWith(\"fd\")))\n );\n } catch {\n return true;\n }\n}\n\n/**\n * Deploy origin resolution (ADR 0020, as amended): the CDN origin comes from\n * the env or the authored `cdn.origin` (inherited via extends) — a hard\n * requirement when uploads are planned, because the host never serves\n * `/bundles` itself. The upload origin is the env, the `bos login` session's\n * siteUrl, or the runtime's own gateway. A session pinned to a local site is\n * a hard error (the origin can only ever be a squatter's port); an env-pinned\n * local origin is deliberate local testing and only warns. Config-only\n * publishes (`uploadsPlanned: false`) ship the committed config verbatim —\n * no origins are resolved and nothing is required.\n */\nexport function resolveCdnDeployInputs(input: {\n env: Record<string, string | undefined>;\n bosConfig: { cdn?: { origin?: string } } | null;\n session: SessionCredentialLike | null;\n account: string;\n gateway: string;\n uploadsPlanned: boolean;\n}): CdnDeployInputs {\n const envCdnOrigin = input.env.BOS_BUNDLE_CDN_ORIGIN?.replace(/\\/$/, \"\");\n const configCdnOrigin = input.bosConfig?.cdn?.origin?.replace(/\\/$/, \"\");\n const storageEnvOrigin = input.env.BOS_STORAGE_ORIGIN?.replace(/\\/$/, \"\");\n const sessionSite = input.session?.siteUrl?.replace(/\\/$/, \"\");\n const apiKey = input.env.BOS_STORAGE_API_KEY ?? input.session?.apiKey;\n const uploadsPlanned = input.uploadsPlanned;\n\n const storageOriginDefault = storageEnvOrigin ?? sessionSite ?? `https://${input.gateway}`;\n\n if (!uploadsPlanned) {\n return { cdnOrigin: undefined, storageOrigin: storageOriginDefault, apiKey };\n }\n\n let cdnOrigin: string | undefined;\n let warning: string | undefined;\n if (envCdnOrigin) {\n cdnOrigin = envCdnOrigin;\n if (isLocalOrigin(envCdnOrigin)) {\n warning = `BOS_BUNDLE_CDN_ORIGIN is a local URL (${envCdnOrigin}) — deploying to a local stack, published bundle URLs will not resolve publicly.`;\n }\n } else if (configCdnOrigin) {\n if (isLocalOrigin(configCdnOrigin)) {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n `the authored config sets cdn.origin to the local URL ${configCdnOrigin} — deploy bundle ` +\n \"origins must be publicly reachable. Set BOS_BUNDLE_CDN_ORIGIN for a local deploy, \" +\n \"or fix cdn.origin (inherited via extends).\",\n };\n }\n cdnOrigin = configCdnOrigin;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n \"CDN deploy requires a bundle origin — set `cdn.origin` in bos.config.json \" +\n \"(children inherit it from the base runtime via extends) or BOS_BUNDLE_CDN_ORIGIN \" +\n \"in the environment.\",\n };\n }\n\n let storageOrigin: string;\n if (storageEnvOrigin) {\n storageOrigin = storageEnvOrigin;\n if (isLocalOrigin(storageEnvOrigin) && !warning) {\n warning = `BOS_STORAGE_ORIGIN is a local URL (${storageEnvOrigin}) — uploading to a local stack.`;\n }\n } else if (sessionSite) {\n if (isLocalOrigin(sessionSite)) {\n return {\n cdnOrigin,\n storageOrigin: sessionSite,\n apiKey,\n error:\n `The CLI session pins uploads to ${sessionSite} — a local site can never receive ` +\n \"production bundles. Re-run `bos login` against the production site, or set \" +\n \"BOS_STORAGE_ORIGIN explicitly.\",\n };\n }\n storageOrigin = sessionSite;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n warning,\n error:\n `Bundle uploads require an upload-service origin — the gateway (${input.gateway}) no longer serves ` +\n \"uploads (ADR 0027: the upload service is standalone at upload.everything.dev). Set BOS_STORAGE_ORIGIN \" +\n \"in the environment (CI) or re-run `bos login` against the production site so the session pins it.\",\n };\n }\n\n if (!apiKey) {\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error:\n \"CDN deploy requires bundle-upload credentials — run `bos login --key` and add the printed key \" +\n \"to GitHub secrets as BOS_STORAGE_API_KEY (or run `bos login` for interactive deploys)\",\n };\n }\n if (input.session?.accountId && input.session.accountId !== input.account) {\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error: `The CLI session was created for ${input.session.accountId}, but the configured account is ${input.account}. Re-run bos login under the matching account.`,\n };\n }\n return { cdnOrigin, storageOrigin, apiKey, warning };\n}\n\n/**\n * Pre-upload probe: the storage origin must actually be the bundle-upload\n * service.\n * `/health` is the primary readiness check, with MCP kept as a compatibility\n * fallback for older fixtures and legacy hosts.\n */\nexport async function probeStorageOrigin(\n storageOrigin: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<string | undefined> {\n const base = storageOrigin.replace(/\\/$/, \"\");\n const healthUrl = `${base}/health`;\n const mcpUrl = `${base}/.well-known/mcp.json`;\n let response: Response;\n try {\n response = await fetchImpl(healthUrl, { headers: { accept: \"text/plain\" } });\n } catch (error) {\n return `unreachable (${String(error instanceof Error ? error.message : error)})`;\n }\n if (response.ok) {\n const body = await response.text().catch(() => \"\");\n if (body.trim() === \"OK\" || body.trim().length === 0) return undefined;\n }\n let mcpResponse: Response;\n try {\n mcpResponse = await fetchImpl(mcpUrl, { headers: { accept: \"application/json\" } });\n } catch {\n return `GET /health responded ${response.status}; fallback /.well-known/mcp.json unreachable`;\n }\n if (!mcpResponse.ok) {\n return `GET /health responded ${response.status}; GET /.well-known/mcp.json responded ${mcpResponse.status}`;\n }\n try {\n const body = await mcpResponse.json();\n if (!body || typeof body !== \"object\") {\n return \"did not return the platform MCP descriptor\";\n }\n return undefined;\n } catch {\n return \"did not return the platform MCP descriptor (non-JSON response)\";\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cdn-deploy.mjs","names":[],"sources":["../src/cdn-deploy.ts"],"sourcesContent":["interface SessionCredentialLike {\n apiKey?: string;\n siteUrl?: string;\n accountId?: string | null;\n}\n\nexport interface CdnDeployInputs {\n cdnOrigin: string | undefined;\n storageOrigin: string;\n apiKey: string | undefined;\n warning?: string;\n error?: string;\n}\n\nconst LOCAL_HOSTNAMES = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\", \"0.0.0.0\", \"local\"]);\n\n/** Local/private destinations can never serve production bundles. */\nexport function isLocalOrigin(url: string): boolean {\n try {\n const { hostname, protocol } = new URL(url);\n if (protocol !== \"http:\" && protocol !== \"https:\") return true;\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n return (\n LOCAL_HOSTNAMES.has(host) ||\n host.endsWith(\".localhost\") ||\n host.endsWith(\".local\") ||\n /^127\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^10\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n /^192\\.168\\.\\d+\\.\\d+$/.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+$/.test(host) ||\n host.startsWith(\"169.254.\") ||\n (host.includes(\":\") &&\n (host.startsWith(\"fe80:\") || host.startsWith(\"fc\") || host.startsWith(\"fd\")))\n );\n } catch {\n return true;\n }\n}\n\n/**\n * Deploy origin resolution (ADR 0020, as amended): the CDN origin comes from\n * the env or the authored `cdn.origin` (inherited via extends) — a hard\n * requirement when uploads are planned, because the host never serves\n * `/bundles` itself. The upload origin is the env, the `bos login` session's\n * siteUrl, or the runtime's own gateway. A session pinned to a local site is\n * a hard error (the origin can only ever be a squatter's port); an env-pinned\n * local origin is deliberate local testing and only warns. Config-only\n * publishes (`uploadsPlanned: false`) ship the committed config verbatim —\n * no origins are resolved and nothing is required.\n */\nexport function resolveCdnDeployInputs(input: {\n env: Record<string, string | undefined>;\n bosConfig: { cdn?: { origin?: string } } | null;\n session: SessionCredentialLike | null;\n custodyAccount?: string;\n account: string;\n gateway: string;\n uploadsPlanned: boolean;\n}): CdnDeployInputs {\n const envCdnOrigin = input.env.BOS_BUNDLE_CDN_ORIGIN?.replace(/\\/$/, \"\");\n const configCdnOrigin = input.bosConfig?.cdn?.origin?.replace(/\\/$/, \"\");\n const storageEnvOrigin = input.env.BOS_STORAGE_ORIGIN?.replace(/\\/$/, \"\");\n const sessionSite = input.session?.siteUrl?.replace(/\\/$/, \"\");\n const apiKey = input.env.BOS_STORAGE_API_KEY ?? input.session?.apiKey;\n const uploadsPlanned = input.uploadsPlanned;\n\n const storageOriginDefault = storageEnvOrigin ?? sessionSite ?? `https://${input.gateway}`;\n\n if (!uploadsPlanned) {\n return { cdnOrigin: undefined, storageOrigin: storageOriginDefault, apiKey };\n }\n\n let cdnOrigin: string | undefined;\n let warning: string | undefined;\n if (envCdnOrigin) {\n cdnOrigin = envCdnOrigin;\n if (isLocalOrigin(envCdnOrigin)) {\n warning = `BOS_BUNDLE_CDN_ORIGIN is a local URL (${envCdnOrigin}) — deploying to a local stack, published bundle URLs will not resolve publicly.`;\n }\n } else if (configCdnOrigin) {\n if (isLocalOrigin(configCdnOrigin)) {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n `the authored config sets cdn.origin to the local URL ${configCdnOrigin} — deploy bundle ` +\n \"origins must be publicly reachable. Set BOS_BUNDLE_CDN_ORIGIN for a local deploy, \" +\n \"or fix cdn.origin (inherited via extends).\",\n };\n }\n cdnOrigin = configCdnOrigin;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n error:\n \"CDN deploy requires a bundle origin — set `cdn.origin` in bos.config.json \" +\n \"(children inherit it from the base runtime via extends) or BOS_BUNDLE_CDN_ORIGIN \" +\n \"in the environment.\",\n };\n }\n\n let storageOrigin: string;\n if (storageEnvOrigin) {\n storageOrigin = storageEnvOrigin;\n if (isLocalOrigin(storageEnvOrigin) && !warning) {\n warning = `BOS_STORAGE_ORIGIN is a local URL (${storageEnvOrigin}) — uploading to a local stack.`;\n }\n } else if (sessionSite) {\n if (isLocalOrigin(sessionSite)) {\n return {\n cdnOrigin,\n storageOrigin: sessionSite,\n apiKey,\n error:\n `The CLI session pins uploads to ${sessionSite} — a local site can never receive ` +\n \"production bundles. Re-run `bos login` against the production site, or set \" +\n \"BOS_STORAGE_ORIGIN explicitly.\",\n };\n }\n storageOrigin = sessionSite;\n } else {\n return {\n cdnOrigin,\n storageOrigin: storageOriginDefault,\n apiKey,\n warning,\n error:\n `Bundle uploads require an upload-service origin — the gateway (${input.gateway}) no longer serves ` +\n \"uploads (ADR 0027: the upload service is standalone at upload.everything.dev). Set BOS_STORAGE_ORIGIN \" +\n \"in the environment (CI) or re-run `bos login` against the production site so the session pins it.\",\n };\n }\n\n if (!apiKey) {\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error:\n \"CDN deploy requires bundle-upload credentials — run `bos login --key` and add the printed key \" +\n \"to GitHub secrets as BOS_STORAGE_API_KEY (or run `bos login` for interactive deploys)\",\n };\n }\n const uploadIdentities = new Set(\n [input.session?.accountId, input.custodyAccount].filter((id): id is string => !!id),\n );\n if (uploadIdentities.size > 0 && !uploadIdentities.has(input.account)) {\n const sessionAccount = input.session?.accountId;\n return {\n cdnOrigin,\n storageOrigin,\n apiKey,\n warning,\n error: sessionAccount\n ? `The CLI session was created for ${sessionAccount}, but the configured account is ${input.account}. Re-run bos login under the matching account.`\n : `The configured account is ${input.account}, but the custody publish identity is ${input.custodyAccount}. Set the authored config's account to the custody wallet account.`,\n };\n }\n return { cdnOrigin, storageOrigin, apiKey, warning };\n}\n\n/**\n * Pre-upload probe: the storage origin must actually be the bundle-upload\n * service.\n * `/health` is the primary readiness check, with MCP kept as a compatibility\n * fallback for older fixtures and legacy hosts.\n */\nexport async function probeStorageOrigin(\n storageOrigin: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<string | undefined> {\n const base = storageOrigin.replace(/\\/$/, \"\");\n const healthUrl = `${base}/health`;\n const mcpUrl = `${base}/.well-known/mcp.json`;\n let response: Response;\n try {\n response = await fetchImpl(healthUrl, { headers: { accept: \"text/plain\" } });\n } catch (error) {\n return `unreachable (${String(error instanceof Error ? error.message : error)})`;\n }\n if (response.ok) {\n const body = await response.text().catch(() => \"\");\n if (body.trim() === \"OK\" || body.trim().length === 0) return undefined;\n }\n let mcpResponse: Response;\n try {\n mcpResponse = await fetchImpl(mcpUrl, { headers: { accept: \"application/json\" } });\n } catch {\n return `GET /health responded ${response.status}; fallback /.well-known/mcp.json unreachable`;\n }\n if (!mcpResponse.ok) {\n return `GET /health responded ${response.status}; GET /.well-known/mcp.json responded ${mcpResponse.status}`;\n }\n try {\n const body = await mcpResponse.json();\n if (!body || typeof body !== \"object\") {\n return \"did not return the platform MCP descriptor\";\n }\n return undefined;\n } catch {\n return \"did not return the platform MCP descriptor (non-JSON response)\";\n }\n}\n"],"mappings":"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"}
|