everything-dev 2.0.0-rc.0 → 2.0.0-rc.4
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/auth-login.cjs +1 -1
- package/dist/auth-login.mjs +1 -1
- package/dist/build.cjs +2 -2
- package/dist/build.mjs +2 -2
- package/dist/bundle-fs-resolve.cjs +9 -17
- package/dist/bundle-fs-resolve.cjs.map +1 -1
- package/dist/bundle-fs-resolve.d.cts +6 -0
- package/dist/bundle-fs-resolve.d.mts +6 -0
- package/dist/bundle-fs-resolve.mjs +9 -17
- package/dist/bundle-fs-resolve.mjs.map +1 -1
- package/dist/bundle-path.cjs +48 -0
- package/dist/bundle-path.cjs.map +1 -0
- package/dist/bundle-path.mjs +45 -0
- package/dist/bundle-path.mjs.map +1 -0
- package/dist/cli/init.cjs +13 -13
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.mjs +13 -13
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli/status.cjs +69 -3
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.mjs +67 -4
- package/dist/cli/status.mjs.map +1 -1
- package/dist/cli/sync.cjs +1 -1
- package/dist/cli/sync.cjs.map +1 -1
- package/dist/cli/sync.mjs +1 -1
- package/dist/cli/sync.mjs.map +1 -1
- package/dist/cli/upgrade.cjs +2 -2
- package/dist/cli/upgrade.cjs.map +1 -1
- package/dist/cli/upgrade.mjs +2 -2
- package/dist/cli/upgrade.mjs.map +1 -1
- package/dist/cli.cjs +5 -7
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +5 -7
- package/dist/cli.mjs.map +1 -1
- package/dist/commands/deploy.cjs +26 -16
- package/dist/commands/deploy.cjs.map +1 -1
- package/dist/commands/deploy.mjs +26 -16
- package/dist/commands/deploy.mjs.map +1 -1
- package/dist/commands/init.cjs +1 -1
- package/dist/commands/init.cjs.map +1 -1
- package/dist/commands/init.mjs +1 -1
- package/dist/commands/init.mjs.map +1 -1
- package/dist/commands/plugins.cjs +2 -2
- package/dist/commands/plugins.cjs.map +1 -1
- package/dist/commands/plugins.mjs +2 -2
- package/dist/commands/plugins.mjs.map +1 -1
- package/dist/commands/upgrade.cjs +1 -1
- package/dist/commands/upgrade.mjs +1 -1
- package/dist/components/dev-render.cjs +1 -1
- package/dist/components/dev-render.mjs +1 -1
- package/dist/config.cjs +3 -3
- package/dist/config.cjs.map +1 -1
- package/dist/config.mjs +3 -3
- package/dist/config.mjs.map +1 -1
- package/dist/contract.cjs +2 -0
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +3 -0
- package/dist/contract.d.mts +3 -0
- package/dist/contract.meta.cjs +2 -1
- package/dist/contract.meta.cjs.map +1 -1
- package/dist/contract.meta.d.cts +4 -1
- package/dist/contract.meta.d.mts +4 -1
- package/dist/contract.meta.mjs +2 -1
- package/dist/contract.meta.mjs.map +1 -1
- package/dist/contract.mjs +2 -0
- package/dist/contract.mjs.map +1 -1
- package/dist/db/driver.cjs +22 -2
- package/dist/db/driver.cjs.map +1 -1
- package/dist/db/driver.d.cts +13 -2
- package/dist/db/driver.d.mts +13 -2
- package/dist/db/driver.mjs +22 -3
- package/dist/db/driver.mjs.map +1 -1
- package/dist/db/index.cjs +1 -0
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.mts +2 -2
- package/dist/db/index.mjs +2 -2
- package/dist/deploy-diff.cjs +1 -1
- package/dist/deploy-diff.cjs.map +1 -1
- package/dist/deploy-diff.mjs +1 -1
- package/dist/deploy-diff.mjs.map +1 -1
- package/dist/dev-program.cjs +10 -2
- package/dist/dev-program.cjs.map +1 -1
- package/dist/dev-program.mjs +10 -2
- package/dist/dev-program.mjs.map +1 -1
- package/dist/image-deploy.cjs +65 -17
- package/dist/image-deploy.cjs.map +1 -1
- package/dist/image-deploy.mjs +64 -18
- package/dist/image-deploy.mjs.map +1 -1
- package/dist/internal/manifest-normalizer.cjs.map +1 -1
- package/dist/internal/manifest-normalizer.mjs.map +1 -1
- package/dist/plugin.d.cts +902 -1
- package/dist/plugin.d.mts +902 -1
- package/dist/publish.cjs +51 -2
- package/dist/publish.cjs.map +1 -1
- package/dist/publish.mjs +51 -4
- package/dist/publish.mjs.map +1 -1
- package/dist/resolution/session.cjs.map +1 -1
- package/dist/resolution/session.d.cts +5 -5
- package/dist/resolution/session.d.mts +5 -5
- package/dist/resolution/session.mjs.map +1 -1
- package/dist/types.d.cts +31 -1
- package/dist/types.d.mts +31 -1
- package/dist/ui/auth-guards.d.cts +78 -2
- package/dist/ui/auth-guards.d.mts +78 -2
- package/dist/ui/auth.cjs.map +1 -1
- package/dist/ui/auth.d.cts +4133 -7
- package/dist/ui/auth.d.mts +4133 -7
- package/dist/ui/auth.mjs.map +1 -1
- package/dist/ui/hydrate.cjs +2 -2
- package/dist/ui/hydrate.cjs.map +1 -1
- package/dist/ui/hydrate.mjs +2 -2
- package/dist/ui/hydrate.mjs.map +1 -1
- package/dist/utils/theme.cjs +2 -2
- package/dist/utils/theme.cjs.map +1 -1
- package/dist/utils/theme.mjs +2 -2
- package/dist/utils/theme.mjs.map +1 -1
- package/dist/version-manifest-resolve.cjs +55 -10
- package/dist/version-manifest-resolve.cjs.map +1 -1
- package/dist/version-manifest-resolve.mjs +53 -10
- package/dist/version-manifest-resolve.mjs.map +1 -1
- package/dist/workspace.cjs +26 -13
- package/dist/workspace.cjs.map +1 -1
- package/dist/workspace.mjs +26 -14
- package/dist/workspace.mjs.map +1 -1
- package/package.json +11 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.cjs","names":["Context","BosDepsTag","MISSING_CONFIG_MESSAGE","publishToFastKv","fetchConfigHistory","summarizeSlotPins","fetchBosConfigFromFastKv","verifyRollbackSnapshot","BosConfigSchema","buildRollbackPayload","fetchDeployManifests","openResolution","resolveImageRef","process","colors","hasDocker","existsSync","join","buildAndPushImage","icons","deployImageToRailway"],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Context } from \"effect\";\nimport { MISSING_CONFIG_MESSAGE } from \"../config\";\nimport {\n type ConfigHistoryEntry,\n fetchBosConfigFromFastKv,\n fetchConfigHistory,\n fetchDeployManifests,\n} from \"../fastkv\";\nimport {\n buildAndPushImage,\n deployImageToRailway,\n hasDocker,\n resolveImageRef,\n} from \"../image-deploy\";\nimport { publishToFastKv } from \"../publish\";\nimport { openResolution } from \"../resolution/session\";\nimport { buildRollbackPayload, summarizeSlotPins, verifyRollbackSnapshot } from \"../rollback\";\nimport type { BosConfigInput } from \"../types\";\nimport { BosConfigSchema } from \"../types\";\nimport { colors, icons } from \"../utils/theme\";\nimport { type BosBuilder, BosDepsTag } from \"./shared\";\n\nexport function registerDeploy(builder: BosBuilder) {\n return {\n publish: builder.publish.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n };\n }),\n\n rollback: builder.rollback.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const { account, domain } = session.config ?? {};\n if (!account || !domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to roll back\",\n };\n }\n\n let history: ConfigHistoryEntry[];\n try {\n history = await fetchConfigHistory({\n accountId: account,\n gatewayId: domain,\n registry: input.registry,\n limit: input.limit,\n });\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to fetch publish history: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n if (history.length === 0) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `No publish history for ${account}/${domain} — nothing to roll back to`,\n };\n }\n\n const historyEntries = history.map((entry) => ({\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...(entry.txHash ? { txHash: entry.txHash } : {}),\n summary: summarizeSlotPins(entry.value as BosConfigInput),\n }));\n\n if (input.listOnly) {\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: historyEntries,\n };\n }\n\n const target =\n input.version !== undefined\n ? history.find((entry) => {\n const iso = new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString();\n return (\n String(entry.blockHeight) === input.version ||\n iso.startsWith(input.version as string)\n );\n })\n : input.previous\n ? history[1]\n : undefined;\n\n if (!target) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n history: historyEntries,\n error: input.version\n ? `No history entry matches \"${input.version}\" — pick a block height from the listing`\n : \"Specify --version <block-height> or --previous (interactive selection happens CLI-side)\",\n };\n }\n\n let liveValue: unknown;\n try {\n liveValue = await fetchBosConfigFromFastKv<unknown>(\n `bos://${account}/${domain}`,\n input.registry,\n );\n } catch {\n liveValue = undefined;\n }\n if (liveValue && JSON.stringify(liveValue) === JSON.stringify(target.value)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"The selected snapshot is identical to the live config — nothing to do\",\n };\n }\n\n const verification = await verifyRollbackSnapshot(target.value as BosConfigInput);\n const slotChecks = verification.slots.map((check) => ({\n slot: check.slot,\n ok: check.ok,\n ...(check.reason ? { reason: check.reason } : {}),\n }));\n if (!verification.ok && verification.verifiable) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n verification: slotChecks,\n error:\n \"Refusing to roll back — a pinned slot's bytes are gone or no longer match their SRI\",\n };\n }\n\n if (!verification.verifiable && !input.force) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error:\n \"Snapshot predates version manifests and cannot be verified — its bytes were overwritten in place. Re-run with --force to publish it anyway.\",\n };\n }\n\n const parsedTarget = BosConfigSchema.parse(target.value);\n const payload = buildRollbackPayload(parsedTarget, new Date().toISOString());\n\n const result = await publishToFastKv({\n bosConfig: payload,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n history: historyEntries,\n ...(slotChecks.length > 0 ? { verification: slotChecks } : {}),\n };\n }),\n\n deploy: builder.deploy.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n if (input.statusList) {\n if (!session.config?.account || !session.config.domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to list deploy manifests\",\n };\n }\n try {\n const manifests = await fetchDeployManifests({\n accountId: session.config.account,\n gatewayId: session.config.domain,\n registry: input.registry,\n });\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: manifests.map((entry) => ({\n key: entry.key,\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...((entry.value as { txHash?: string } | undefined)?.txHash\n ? { txHash: (entry.value as { txHash?: string }).txHash }\n : {}),\n ...((entry.value as { publishedAt?: string } | undefined)?.publishedAt\n ? { publishedAt: (entry.value as { publishedAt?: string }).publishedAt }\n : {}),\n })),\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to list deploy manifests: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: input.build,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: input.packages,\n network: input.network,\n privateKey: input.privateKey,\n registry: input.registry,\n fullUpload: input.fullUpload,\n });\n\n if (result.status === \"error\") {\n return {\n status: \"error\" as const,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n built: result.built,\n skipped: result.skipped,\n error: result.error,\n deployResults: result.deployResults,\n };\n }\n\n if (result.status === \"dry-run\") {\n return {\n status: \"dry-run\" as const,\n registryUrl: result.registryUrl,\n built: result.built,\n skipped: result.skipped,\n };\n }\n\n let nextSession = session;\n if (result.publishConfig) {\n const opened = await openResolution({ cwd: session.root });\n if (opened) {\n nextSession = opened;\n }\n }\n\n const configPublished = {\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n fingerprint: result.fingerprint,\n slotPins: result.slotPins,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n } as const;\n\n let image: string | undefined;\n let imageDigest: string | undefined;\n let service: string | undefined;\n\n const imageRef = resolveImageRef({\n ciImage: nextSession.config?.ci?.image,\n repository: nextSession.config?.repository,\n env: process.env,\n });\n if (!imageRef) {\n console.log();\n console.log(\n colors.yellow(\n \" Image skipped: set ci.image in bos.config.json (or BOS_IMAGE) to build and push the runtime image\",\n ),\n );\n } else if (!(await hasDocker())) {\n console.log();\n console.log(colors.yellow(\" Image skipped: docker is not available\"));\n } else if (!existsSync(join(session.root, \"Dockerfile\"))) {\n // Children fetch the universal image (ADR 0020/0021) — a removed\n // Dockerfile means this runtime never builds its own image.\n console.log();\n console.log(colors.yellow(\" Image skipped: no Dockerfile at the config root\"));\n } else {\n console.log();\n try {\n const imageResult = await buildAndPushImage({\n image: imageRef.image,\n configDir: session.root,\n verbose: input.verbose,\n });\n image = imageResult.image;\n imageDigest = imageResult.digest;\n console.log(\n colors.green(\n ` ${icons.ok} Image pushed ${imageResult.image}:${imageResult.tag}${imageResult.digest ? ` (${imageResult.digest.slice(0, 19)}…)` : \"\"}`,\n ),\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const imageError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Docker not found — install Docker to build the runtime image\"\n : `Image build/push failed: ${message}`;\n console.log(colors.yellow(` ${imageError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n error: `Config published but ${imageError}`,\n };\n }\n }\n\n if (process.env.RAILWAY_TOKEN) {\n const railwayService = input.service ?? nextSession.config?.ci?.railway?.service;\n if (!railwayService) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: ci.railway.service is not configured in bos.config.json\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n error:\n \"Config published but Railway deploy failed: ci.railway.service is not configured in bos.config.json\",\n };\n }\n if (!image || !imageDigest) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: no pushed image digest — set ci.image and install docker\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service: railwayService,\n error:\n \"Config published but Railway deploy requires a pushed image (set ci.image and install docker)\",\n };\n }\n\n service = railwayService;\n try {\n await deployImageToRailway({\n image,\n digest: imageDigest,\n service: railwayService,\n configDir: session.root,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const railError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Railway CLI not found. Install it: npm i -g @railway/cli\"\n : `Railway deploy failed: ${message}`;\n console.log(colors.yellow(` ${railError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service,\n error: `Config published but ${railError}`,\n };\n }\n } else {\n console.log();\n console.log(colors.yellow(\" Railway deploy skipped (RAILWAY_TOKEN not set)\"));\n }\n\n return {\n status: \"deployed\" as const,\n ...configPublished,\n image,\n service,\n };\n }),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"deploy.cjs","names":["Context","BosDepsTag","MISSING_CONFIG_MESSAGE","publishToFastKv","fetchConfigHistory","summarizeSlotPins","fetchBosConfigFromFastKv","verifyRollbackSnapshot","BosConfigSchema","buildRollbackPayload","fetchDeployManifests","process","isValidImageDigest","openResolution","resolveDeployImagePlan","resolveImageRef","hasDocker","existsSync","join","colors","icons","buildAndPushImage","deployImageToRailway"],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Context } from \"effect\";\nimport { MISSING_CONFIG_MESSAGE } from \"../config\";\nimport {\n type ConfigHistoryEntry,\n fetchBosConfigFromFastKv,\n fetchConfigHistory,\n fetchDeployManifests,\n} from \"../fastkv\";\nimport {\n buildAndPushImage,\n deployImageToRailway,\n hasDocker,\n isValidImageDigest,\n resolveDeployImagePlan,\n resolveImageRef,\n} from \"../image-deploy\";\nimport { publishToFastKv } from \"../publish\";\nimport { openResolution } from \"../resolution/session\";\nimport { buildRollbackPayload, summarizeSlotPins, verifyRollbackSnapshot } from \"../rollback\";\nimport type { BosConfigInput } from \"../types\";\nimport { BosConfigSchema } from \"../types\";\nimport { colors, icons } from \"../utils/theme\";\nimport { type BosBuilder, BosDepsTag } from \"./shared\";\n\nexport function registerDeploy(builder: BosBuilder) {\n return {\n publish: builder.publish.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n };\n }),\n\n rollback: builder.rollback.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const { account, domain } = session.config ?? {};\n if (!account || !domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to roll back\",\n };\n }\n\n let history: ConfigHistoryEntry[];\n try {\n history = await fetchConfigHistory({\n accountId: account,\n gatewayId: domain,\n registry: input.registry,\n limit: input.limit,\n });\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to fetch publish history: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n if (history.length === 0) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `No publish history for ${account}/${domain} — nothing to roll back to`,\n };\n }\n\n const historyEntries = history.map((entry) => ({\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...(entry.txHash ? { txHash: entry.txHash } : {}),\n summary: summarizeSlotPins(entry.value as BosConfigInput),\n }));\n\n if (input.listOnly) {\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: historyEntries,\n };\n }\n\n const target =\n input.version !== undefined\n ? history.find((entry) => {\n const iso = new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString();\n return (\n String(entry.blockHeight) === input.version ||\n iso.startsWith(input.version as string)\n );\n })\n : input.previous\n ? history[1]\n : undefined;\n\n if (!target) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n history: historyEntries,\n error: input.version\n ? `No history entry matches \"${input.version}\" — pick a block height from the listing`\n : \"Specify --version <block-height> or --previous (interactive selection happens CLI-side)\",\n };\n }\n\n let liveValue: unknown;\n try {\n liveValue = await fetchBosConfigFromFastKv<unknown>(\n `bos://${account}/${domain}`,\n input.registry,\n );\n } catch {\n liveValue = undefined;\n }\n if (liveValue && JSON.stringify(liveValue) === JSON.stringify(target.value)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"The selected snapshot is identical to the live config — nothing to do\",\n };\n }\n\n const verification = await verifyRollbackSnapshot(target.value as BosConfigInput);\n const slotChecks = verification.slots.map((check) => ({\n slot: check.slot,\n ok: check.ok,\n ...(check.reason ? { reason: check.reason } : {}),\n }));\n if (!verification.ok && verification.verifiable) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n verification: slotChecks,\n error:\n \"Refusing to roll back — a pinned slot's bytes are gone or no longer match their SRI\",\n };\n }\n\n if (!verification.verifiable && !input.force) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error:\n \"Snapshot predates version manifests and cannot be verified — its bytes were overwritten in place. Re-run with --force to publish it anyway.\",\n };\n }\n\n const parsedTarget = BosConfigSchema.parse(target.value);\n const payload = buildRollbackPayload(parsedTarget, new Date().toISOString());\n\n const result = await publishToFastKv({\n bosConfig: payload,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n history: historyEntries,\n ...(slotChecks.length > 0 ? { verification: slotChecks } : {}),\n };\n }),\n\n deploy: builder.deploy.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n if (input.statusList) {\n if (!session.config?.account || !session.config.domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to list deploy manifests\",\n };\n }\n try {\n const manifests = await fetchDeployManifests({\n accountId: session.config.account,\n gatewayId: session.config.domain,\n registry: input.registry,\n });\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: manifests.map((entry) => ({\n key: entry.key,\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...((entry.value as { txHash?: string } | undefined)?.txHash\n ? { txHash: (entry.value as { txHash?: string }).txHash }\n : {}),\n ...((entry.value as { publishedAt?: string } | undefined)?.publishedAt\n ? { publishedAt: (entry.value as { publishedAt?: string }).publishedAt }\n : {}),\n })),\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to list deploy manifests: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n const imageDigestInput = input.imageDigest ?? process.env.BOS_IMAGE_DIGEST;\n if (imageDigestInput && !isValidImageDigest(imageDigestInput)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Invalid image digest \"${imageDigestInput}\" — expected sha256:<64 hex characters> (--image-digest / BOS_IMAGE_DIGEST)`,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: input.build,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: input.packages,\n network: input.network,\n privateKey: input.privateKey,\n registry: input.registry,\n fullUpload: input.fullUpload,\n });\n\n if (result.status === \"error\") {\n return {\n status: \"error\" as const,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n built: result.built,\n skipped: result.skipped,\n error: result.error,\n deployResults: result.deployResults,\n };\n }\n\n if (result.status === \"dry-run\") {\n return {\n status: \"dry-run\" as const,\n registryUrl: result.registryUrl,\n built: result.built,\n skipped: result.skipped,\n };\n }\n\n let nextSession = session;\n if (result.publishConfig) {\n const opened = await openResolution({ cwd: session.root });\n if (opened) {\n nextSession = opened;\n }\n }\n\n const configPublished = {\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n fingerprint: result.fingerprint,\n slotPins: result.slotPins,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n } as const;\n\n let image: string | undefined;\n let imageDigest: string | undefined;\n let service: string | undefined;\n\n const imagePlan = resolveDeployImagePlan({\n // A prebuilt digest pairs with the pushed ref (BOS_IMAGE from the CI\n // image job, or repository derivation) — ci.image is a build-time\n // choice, not a pin-time one; letting it win here could pin a digest\n // from a different image.\n imageRef: resolveImageRef({\n ciImage: imageDigestInput ? undefined : nextSession.config?.ci?.image,\n repository: nextSession.config?.repository,\n env: process.env,\n }),\n imageDigest: imageDigestInput,\n hasDocker: await hasDocker(),\n hasDockerfile: existsSync(join(session.root, \"Dockerfile\")),\n });\n\n if (imagePlan.kind === \"skip\") {\n console.log();\n console.log(colors.yellow(` Image skipped: ${imagePlan.reason}`));\n } else if (imagePlan.kind === \"prebuilt\") {\n image = imagePlan.image;\n imageDigest = imagePlan.digest;\n console.log();\n console.log(\n colors.green(\n ` ${icons.ok} Using pre-pushed image ${imagePlan.image}@${imagePlan.digest.slice(0, 19)}…`,\n ),\n );\n } else {\n console.log();\n try {\n const imageResult = await buildAndPushImage({\n image: imagePlan.image,\n configDir: session.root,\n verbose: input.verbose,\n });\n image = imageResult.image;\n imageDigest = imageResult.digest;\n console.log(\n colors.green(\n ` ${icons.ok} Image pushed ${imageResult.image}:${imageResult.tag}${imageResult.digest ? ` (${imageResult.digest.slice(0, 19)}…)` : \"\"}`,\n ),\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const imageError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Docker not found — install Docker to build the runtime image\"\n : `Image build/push failed: ${message}`;\n console.log(colors.yellow(` ${imageError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n error: `Config published but ${imageError}`,\n };\n }\n }\n\n if (process.env.RAILWAY_TOKEN) {\n const railwayService = input.service ?? nextSession.config?.ci?.railway?.service;\n if (!railwayService) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: ci.railway.service is not configured in bos.config.json\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n error:\n \"Config published but Railway deploy failed: ci.railway.service is not configured in bos.config.json\",\n };\n }\n if (!image || !imageDigest) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: no runtime image digest — set ci.image (or pass BOS_IMAGE_DIGEST) and make the image available\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service: railwayService,\n error:\n \"Config published but Railway deploy requires a runtime image (set ci.image, or pass BOS_IMAGE_DIGEST for a pre-pushed image)\",\n };\n }\n\n service = railwayService;\n try {\n await deployImageToRailway({\n image,\n digest: imageDigest,\n service: railwayService,\n configDir: session.root,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const railError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Railway CLI not found. Install it: npm i -g @railway/cli\"\n : `Railway deploy failed: ${message}`;\n console.log(colors.yellow(` ${railError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service,\n error: `Config published but ${railError}`,\n };\n }\n } else {\n console.log();\n console.log(colors.yellow(\" Railway deploy skipped (RAILWAY_TOKEN not set)\"));\n }\n\n return {\n status: \"deployed\" as const,\n ...configPublished,\n image,\n service,\n };\n }),\n };\n}\n"],"mappings":"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"}
|
package/dist/commands/deploy.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BosConfigSchema } from "../types.mjs";
|
|
2
2
|
import { fetchBosConfigFromFastKv, fetchConfigHistory, fetchDeployManifests } from "../fastkv.mjs";
|
|
3
3
|
import { MISSING_CONFIG_MESSAGE } from "../config.mjs";
|
|
4
|
-
import { openResolution } from "../resolution/session.mjs";
|
|
5
4
|
import { colors, icons } from "../utils/theme.mjs";
|
|
5
|
+
import { buildAndPushImage, deployImageToRailway, hasDocker, isValidImageDigest, resolveDeployImagePlan, resolveImageRef } from "../image-deploy.mjs";
|
|
6
|
+
import { openResolution } from "../resolution/session.mjs";
|
|
6
7
|
import { BosDepsTag } from "./shared.mjs";
|
|
7
|
-
import { buildAndPushImage, deployImageToRailway, hasDocker, resolveImageRef } from "../image-deploy.mjs";
|
|
8
8
|
import { buildRollbackPayload, summarizeSlotPins, verifyRollbackSnapshot } from "../rollback.mjs";
|
|
9
9
|
import { publishToFastKv } from "../publish.mjs";
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
@@ -190,6 +190,12 @@ function registerDeploy(builder) {
|
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
|
+
const imageDigestInput = input.imageDigest ?? process.env.BOS_IMAGE_DIGEST;
|
|
194
|
+
if (imageDigestInput && !isValidImageDigest(imageDigestInput)) return {
|
|
195
|
+
status: "error",
|
|
196
|
+
registryUrl: "",
|
|
197
|
+
error: `Invalid image digest "${imageDigestInput}" — expected sha256:<64 hex characters> (--image-digest / BOS_IMAGE_DIGEST)`
|
|
198
|
+
};
|
|
193
199
|
const result = await publishToFastKv({
|
|
194
200
|
bosConfig: session.config,
|
|
195
201
|
runtimeConfig: session.runtime,
|
|
@@ -236,25 +242,29 @@ function registerDeploy(builder) {
|
|
|
236
242
|
let image;
|
|
237
243
|
let imageDigest;
|
|
238
244
|
let service;
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
245
|
+
const imagePlan = resolveDeployImagePlan({
|
|
246
|
+
imageRef: resolveImageRef({
|
|
247
|
+
ciImage: imageDigestInput ? void 0 : nextSession.config?.ci?.image,
|
|
248
|
+
repository: nextSession.config?.repository,
|
|
249
|
+
env: process.env
|
|
250
|
+
}),
|
|
251
|
+
imageDigest: imageDigestInput,
|
|
252
|
+
hasDocker: await hasDocker(),
|
|
253
|
+
hasDockerfile: existsSync(join(session.root, "Dockerfile"))
|
|
243
254
|
});
|
|
244
|
-
if (
|
|
245
|
-
console.log();
|
|
246
|
-
console.log(colors.yellow(" Image skipped: set ci.image in bos.config.json (or BOS_IMAGE) to build and push the runtime image"));
|
|
247
|
-
} else if (!await hasDocker()) {
|
|
255
|
+
if (imagePlan.kind === "skip") {
|
|
248
256
|
console.log();
|
|
249
|
-
console.log(colors.yellow(
|
|
250
|
-
} else if (
|
|
257
|
+
console.log(colors.yellow(` Image skipped: ${imagePlan.reason}`));
|
|
258
|
+
} else if (imagePlan.kind === "prebuilt") {
|
|
259
|
+
image = imagePlan.image;
|
|
260
|
+
imageDigest = imagePlan.digest;
|
|
251
261
|
console.log();
|
|
252
|
-
console.log(colors.
|
|
262
|
+
console.log(colors.green(` ${icons.ok} Using pre-pushed image ${imagePlan.image}@${imagePlan.digest.slice(0, 19)}…`));
|
|
253
263
|
} else {
|
|
254
264
|
console.log();
|
|
255
265
|
try {
|
|
256
266
|
const imageResult = await buildAndPushImage({
|
|
257
|
-
image:
|
|
267
|
+
image: imagePlan.image,
|
|
258
268
|
configDir: session.root,
|
|
259
269
|
verbose: input.verbose
|
|
260
270
|
});
|
|
@@ -286,13 +296,13 @@ function registerDeploy(builder) {
|
|
|
286
296
|
}
|
|
287
297
|
if (!image || !imageDigest) {
|
|
288
298
|
console.log();
|
|
289
|
-
console.log(colors.yellow(" Railway deploy skipped: no
|
|
299
|
+
console.log(colors.yellow(" Railway deploy skipped: no runtime image digest — set ci.image (or pass BOS_IMAGE_DIGEST) and make the image available"));
|
|
290
300
|
return {
|
|
291
301
|
status: "published",
|
|
292
302
|
...configPublished,
|
|
293
303
|
image,
|
|
294
304
|
service: railwayService,
|
|
295
|
-
error: "Config published but Railway deploy requires a
|
|
305
|
+
error: "Config published but Railway deploy requires a runtime image (set ci.image, or pass BOS_IMAGE_DIGEST for a pre-pushed image)"
|
|
296
306
|
};
|
|
297
307
|
}
|
|
298
308
|
service = railwayService;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Context } from \"effect\";\nimport { MISSING_CONFIG_MESSAGE } from \"../config\";\nimport {\n type ConfigHistoryEntry,\n fetchBosConfigFromFastKv,\n fetchConfigHistory,\n fetchDeployManifests,\n} from \"../fastkv\";\nimport {\n buildAndPushImage,\n deployImageToRailway,\n hasDocker,\n resolveImageRef,\n} from \"../image-deploy\";\nimport { publishToFastKv } from \"../publish\";\nimport { openResolution } from \"../resolution/session\";\nimport { buildRollbackPayload, summarizeSlotPins, verifyRollbackSnapshot } from \"../rollback\";\nimport type { BosConfigInput } from \"../types\";\nimport { BosConfigSchema } from \"../types\";\nimport { colors, icons } from \"../utils/theme\";\nimport { type BosBuilder, BosDepsTag } from \"./shared\";\n\nexport function registerDeploy(builder: BosBuilder) {\n return {\n publish: builder.publish.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n };\n }),\n\n rollback: builder.rollback.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const { account, domain } = session.config ?? {};\n if (!account || !domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to roll back\",\n };\n }\n\n let history: ConfigHistoryEntry[];\n try {\n history = await fetchConfigHistory({\n accountId: account,\n gatewayId: domain,\n registry: input.registry,\n limit: input.limit,\n });\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to fetch publish history: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n if (history.length === 0) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `No publish history for ${account}/${domain} — nothing to roll back to`,\n };\n }\n\n const historyEntries = history.map((entry) => ({\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...(entry.txHash ? { txHash: entry.txHash } : {}),\n summary: summarizeSlotPins(entry.value as BosConfigInput),\n }));\n\n if (input.listOnly) {\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: historyEntries,\n };\n }\n\n const target =\n input.version !== undefined\n ? history.find((entry) => {\n const iso = new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString();\n return (\n String(entry.blockHeight) === input.version ||\n iso.startsWith(input.version as string)\n );\n })\n : input.previous\n ? history[1]\n : undefined;\n\n if (!target) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n history: historyEntries,\n error: input.version\n ? `No history entry matches \"${input.version}\" — pick a block height from the listing`\n : \"Specify --version <block-height> or --previous (interactive selection happens CLI-side)\",\n };\n }\n\n let liveValue: unknown;\n try {\n liveValue = await fetchBosConfigFromFastKv<unknown>(\n `bos://${account}/${domain}`,\n input.registry,\n );\n } catch {\n liveValue = undefined;\n }\n if (liveValue && JSON.stringify(liveValue) === JSON.stringify(target.value)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"The selected snapshot is identical to the live config — nothing to do\",\n };\n }\n\n const verification = await verifyRollbackSnapshot(target.value as BosConfigInput);\n const slotChecks = verification.slots.map((check) => ({\n slot: check.slot,\n ok: check.ok,\n ...(check.reason ? { reason: check.reason } : {}),\n }));\n if (!verification.ok && verification.verifiable) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n verification: slotChecks,\n error:\n \"Refusing to roll back — a pinned slot's bytes are gone or no longer match their SRI\",\n };\n }\n\n if (!verification.verifiable && !input.force) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error:\n \"Snapshot predates version manifests and cannot be verified — its bytes were overwritten in place. Re-run with --force to publish it anyway.\",\n };\n }\n\n const parsedTarget = BosConfigSchema.parse(target.value);\n const payload = buildRollbackPayload(parsedTarget, new Date().toISOString());\n\n const result = await publishToFastKv({\n bosConfig: payload,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n history: historyEntries,\n ...(slotChecks.length > 0 ? { verification: slotChecks } : {}),\n };\n }),\n\n deploy: builder.deploy.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n if (input.statusList) {\n if (!session.config?.account || !session.config.domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to list deploy manifests\",\n };\n }\n try {\n const manifests = await fetchDeployManifests({\n accountId: session.config.account,\n gatewayId: session.config.domain,\n registry: input.registry,\n });\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: manifests.map((entry) => ({\n key: entry.key,\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...((entry.value as { txHash?: string } | undefined)?.txHash\n ? { txHash: (entry.value as { txHash?: string }).txHash }\n : {}),\n ...((entry.value as { publishedAt?: string } | undefined)?.publishedAt\n ? { publishedAt: (entry.value as { publishedAt?: string }).publishedAt }\n : {}),\n })),\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to list deploy manifests: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: input.build,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: input.packages,\n network: input.network,\n privateKey: input.privateKey,\n registry: input.registry,\n fullUpload: input.fullUpload,\n });\n\n if (result.status === \"error\") {\n return {\n status: \"error\" as const,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n built: result.built,\n skipped: result.skipped,\n error: result.error,\n deployResults: result.deployResults,\n };\n }\n\n if (result.status === \"dry-run\") {\n return {\n status: \"dry-run\" as const,\n registryUrl: result.registryUrl,\n built: result.built,\n skipped: result.skipped,\n };\n }\n\n let nextSession = session;\n if (result.publishConfig) {\n const opened = await openResolution({ cwd: session.root });\n if (opened) {\n nextSession = opened;\n }\n }\n\n const configPublished = {\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n fingerprint: result.fingerprint,\n slotPins: result.slotPins,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n } as const;\n\n let image: string | undefined;\n let imageDigest: string | undefined;\n let service: string | undefined;\n\n const imageRef = resolveImageRef({\n ciImage: nextSession.config?.ci?.image,\n repository: nextSession.config?.repository,\n env: process.env,\n });\n if (!imageRef) {\n console.log();\n console.log(\n colors.yellow(\n \" Image skipped: set ci.image in bos.config.json (or BOS_IMAGE) to build and push the runtime image\",\n ),\n );\n } else if (!(await hasDocker())) {\n console.log();\n console.log(colors.yellow(\" Image skipped: docker is not available\"));\n } else if (!existsSync(join(session.root, \"Dockerfile\"))) {\n // Children fetch the universal image (ADR 0020/0021) — a removed\n // Dockerfile means this runtime never builds its own image.\n console.log();\n console.log(colors.yellow(\" Image skipped: no Dockerfile at the config root\"));\n } else {\n console.log();\n try {\n const imageResult = await buildAndPushImage({\n image: imageRef.image,\n configDir: session.root,\n verbose: input.verbose,\n });\n image = imageResult.image;\n imageDigest = imageResult.digest;\n console.log(\n colors.green(\n ` ${icons.ok} Image pushed ${imageResult.image}:${imageResult.tag}${imageResult.digest ? ` (${imageResult.digest.slice(0, 19)}…)` : \"\"}`,\n ),\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const imageError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Docker not found — install Docker to build the runtime image\"\n : `Image build/push failed: ${message}`;\n console.log(colors.yellow(` ${imageError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n error: `Config published but ${imageError}`,\n };\n }\n }\n\n if (process.env.RAILWAY_TOKEN) {\n const railwayService = input.service ?? nextSession.config?.ci?.railway?.service;\n if (!railwayService) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: ci.railway.service is not configured in bos.config.json\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n error:\n \"Config published but Railway deploy failed: ci.railway.service is not configured in bos.config.json\",\n };\n }\n if (!image || !imageDigest) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: no pushed image digest — set ci.image and install docker\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service: railwayService,\n error:\n \"Config published but Railway deploy requires a pushed image (set ci.image and install docker)\",\n };\n }\n\n service = railwayService;\n try {\n await deployImageToRailway({\n image,\n digest: imageDigest,\n service: railwayService,\n configDir: session.root,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const railError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Railway CLI not found. Install it: npm i -g @railway/cli\"\n : `Railway deploy failed: ${message}`;\n console.log(colors.yellow(` ${railError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service,\n error: `Config published but ${railError}`,\n };\n }\n } else {\n console.log();\n console.log(colors.yellow(\" Railway deploy skipped (RAILWAY_TOKEN not set)\"));\n }\n\n return {\n status: \"deployed\" as const,\n ...configPublished,\n image,\n service,\n };\n }),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAyBA,SAAgB,eAAe,SAAqB;CAClD,OAAO;EACL,SAAS,QAAQ,QAAQ,QAAQ,OAAO,EAAE,OAAO,cAAc;GAE7D,MAAM,UADO,QAAQ,IAAI,QAAQ,mBAAmB,UACjC,CAAC,CAAC;GACrB,IAAI,CAAC,SAAS,QACZ,OAAO;IACL,QAAQ;IACR,aAAa;IACb,OAAO;GACT;GAGF,MAAM,SAAS,MAAM,gBAAgB;IACnC,WAAW,QAAQ;IACnB,eAAe,QAAQ;IACvB,WAAW,QAAQ;IACnB,KAAK,MAAM;IACX,OAAO;IACP,QAAQ,MAAM;IACd,SAAS,MAAM;IACf,UAAU;IACV,SAAS,MAAM;IACf,YAAY,MAAM;IAClB,QAAQ,MAAM;IACd,UAAU,MAAM;GAClB,CAAC;GAED,OAAO;IACL,QAAQ,OAAO;IACf,aAAa,OAAO;IACpB,QAAQ,OAAO;IACf,OAAO,OAAO;IACd,OAAO,OAAO;IACd,SAAS,OAAO;IAChB,eAAe,OAAO;GACxB;EACF,CAAC;EAED,UAAU,QAAQ,SAAS,QAAQ,OAAO,EAAE,OAAO,cAAc;GAE/D,MAAM,UADO,QAAQ,IAAI,QAAQ,mBAAmB,UACjC,CAAC,CAAC;GACrB,IAAI,CAAC,SACH,OAAO;IACL,QAAQ;IACR,aAAa;IACb,OAAO;GACT;GAGF,MAAM,EAAE,SAAS,WAAW,QAAQ,UAAU,CAAC;GAC/C,IAAI,CAAC,WAAW,CAAC,QACf,OAAO;IACL,QAAQ;IACR,aAAa;IACb,OAAO;GACT;GAGF,IAAI;GACJ,IAAI;IACF,UAAU,MAAM,mBAAmB;KACjC,WAAW;KACX,WAAW;KACX,UAAU,MAAM;KAChB,OAAO,MAAM;IACf,CAAC;GACH,SAAS,OAAO;IACd,OAAO;KACL,QAAQ;KACR,aAAa;KACb,OAAO,oCAAoC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAClG;GACF;GAEA,IAAI,QAAQ,WAAW,GACrB,OAAO;IACL,QAAQ;IACR,aAAa;IACb,OAAO,0BAA0B,QAAQ,GAAG,OAAO;GACrD;GAGF,MAAM,iBAAiB,QAAQ,KAAK,WAAW;IAC7C,aAAa,MAAM;IACnB,gBAAgB,IAAI,KAAK,OAAO,MAAM,iBAAiB,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY;IAClF,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;IAC/C,SAAS,kBAAkB,MAAM,KAAuB;GAC1D,EAAE;GAEF,IAAI,MAAM,UACR,OAAO;IACL,QAAQ;IACR,aAAa;IACb,SAAS;GACX;GAGF,MAAM,SACJ,MAAM,YAAY,SACd,QAAQ,MAAM,UAAU;IACtB,MAAM,MAAM,IAAI,KAAK,OAAO,MAAM,iBAAiB,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY;IAC9E,OACE,OAAO,MAAM,WAAW,MAAM,MAAM,WACpC,IAAI,WAAW,MAAM,OAAiB;GAE1C,CAAC,IACD,MAAM,WACJ,QAAQ,KACR;GAER,IAAI,CAAC,QACH,OAAO;IACL,QAAQ;IACR,aAAa;IACb,SAAS;IACT,OAAO,MAAM,UACT,6BAA6B,MAAM,QAAQ,4CAC3C;GACN;GAGF,IAAI;GACJ,IAAI;IACF,YAAY,MAAM,yBAChB,SAAS,QAAQ,GAAG,UACpB,MAAM,QACR;GACF,QAAQ;IACN,YAAY;GACd;GACA,IAAI,aAAa,KAAK,UAAU,SAAS,MAAM,KAAK,UAAU,OAAO,KAAK,GACxE,OAAO;IACL,QAAQ;IACR,aAAa;IACb,OAAO;GACT;GAGF,MAAM,eAAe,MAAM,uBAAuB,OAAO,KAAuB;GAChF,MAAM,aAAa,aAAa,MAAM,KAAK,WAAW;IACpD,MAAM,MAAM;IACZ,IAAI,MAAM;IACV,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;GACjD,EAAE;GACF,IAAI,CAAC,aAAa,MAAM,aAAa,YACnC,OAAO;IACL,QAAQ;IACR,aAAa;IACb,cAAc;IACd,OACE;GACJ;GAGF,IAAI,CAAC,aAAa,cAAc,CAAC,MAAM,OACrC,OAAO;IACL,QAAQ;IACR,aAAa;IACb,OACE;GACJ;GAGF,MAAM,eAAe,gBAAgB,MAAM,OAAO,KAAK;GACvD,MAAM,UAAU,qBAAqB,+BAAc,IAAI,KAAK,EAAC,CAAC,YAAY,CAAC;GAE3E,MAAM,SAAS,MAAM,gBAAgB;IACnC,WAAW;IACX,eAAe,QAAQ;IACvB,WAAW,QAAQ;IACnB,KAAK,MAAM;IACX,OAAO;IACP,QAAQ,MAAM;IACd,SAAS,MAAM;IACf,UAAU;IACV,SAAS,MAAM;IACf,YAAY,MAAM;IAClB,QAAQ,MAAM;IACd,UAAU,MAAM;GAClB,CAAC;GAED,OAAO;IACL,QAAQ,OAAO;IACf,aAAa,OAAO;IACpB,QAAQ,OAAO;IACf,OAAO,OAAO;IACd,SAAS;IACT,GAAI,WAAW,SAAS,IAAI,EAAE,cAAc,WAAW,IAAI,CAAC;GAC9D;EACF,CAAC;EAED,QAAQ,QAAQ,OAAO,QAAQ,OAAO,EAAE,OAAO,cAAc;GAE3D,MAAM,UADO,QAAQ,IAAI,QAAQ,mBAAmB,UACjC,CAAC,CAAC;GACrB,IAAI,CAAC,SAAS,QACZ,OAAO;IACL,QAAQ;IACR,aAAa;IACb,OAAO;GACT;GAGF,IAAI,MAAM,YAAY;IACpB,IAAI,CAAC,QAAQ,QAAQ,WAAW,CAAC,QAAQ,OAAO,QAC9C,OAAO;KACL,QAAQ;KACR,aAAa;KACb,OAAO;IACT;IAEF,IAAI;KAMF,OAAO;MACL,QAAQ;MACR,aAAa;MACb,UAAS,MARa,qBAAqB;OAC3C,WAAW,QAAQ,OAAO;OAC1B,WAAW,QAAQ,OAAO;OAC1B,UAAU,MAAM;MAClB,CAAC,EAImB,CAAC,KAAK,WAAW;OACjC,KAAK,MAAM;OACX,aAAa,MAAM;OACnB,gBAAgB,IAAI,KAAK,OAAO,MAAM,iBAAiB,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY;OAClF,GAAK,MAAM,OAA2C,SAClD,EAAE,QAAS,MAAM,MAA8B,OAAO,IACtD,CAAC;OACL,GAAK,MAAM,OAAgD,cACvD,EAAE,aAAc,MAAM,MAAmC,YAAY,IACrE,CAAC;MACP,EAAE;KACJ;IACF,SAAS,OAAO;KACd,OAAO;MACL,QAAQ;MACR,aAAa;MACb,OAAO,oCAAoC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;KAClG;IACF;GACF;GAEA,MAAM,SAAS,MAAM,gBAAgB;IACnC,WAAW,QAAQ;IACnB,eAAe,QAAQ;IACvB,WAAW,QAAQ;IACnB,KAAK,MAAM;IACX,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,SAAS,MAAM;IACf,UAAU,MAAM;IAChB,SAAS,MAAM;IACf,YAAY,MAAM;IAClB,UAAU,MAAM;IAChB,YAAY,MAAM;GACpB,CAAC;GAED,IAAI,OAAO,WAAW,SACpB,OAAO;IACL,QAAQ;IACR,aAAa,OAAO;IACpB,QAAQ,OAAO;IACf,OAAO,OAAO;IACd,SAAS,OAAO;IAChB,OAAO,OAAO;IACd,eAAe,OAAO;GACxB;GAGF,IAAI,OAAO,WAAW,WACpB,OAAO;IACL,QAAQ;IACR,aAAa,OAAO;IACpB,OAAO,OAAO;IACd,SAAS,OAAO;GAClB;GAGF,IAAI,cAAc;GAClB,IAAI,OAAO,eAAe;IACxB,MAAM,SAAS,MAAM,eAAe,EAAE,KAAK,QAAQ,KAAK,CAAC;IACzD,IAAI,QACF,cAAc;GAElB;GAEA,MAAM,kBAAkB;IACtB,aAAa,OAAO;IACpB,QAAQ,OAAO;IACf,aAAa,OAAO;IACpB,UAAU,OAAO;IACjB,OAAO,OAAO;IACd,SAAS,OAAO;IAChB,eAAe,OAAO;GACxB;GAEA,IAAI;GACJ,IAAI;GACJ,IAAI;GAEJ,MAAM,WAAW,gBAAgB;IAC/B,SAAS,YAAY,QAAQ,IAAI;IACjC,YAAY,YAAY,QAAQ;IAChC,KAAK,QAAQ;GACf,CAAC;GACD,IAAI,CAAC,UAAU;IACb,QAAQ,IAAI;IACZ,QAAQ,IACN,OAAO,OACL,qGACF,CACF;GACF,OAAO,IAAI,CAAE,MAAM,UAAU,GAAI;IAC/B,QAAQ,IAAI;IACZ,QAAQ,IAAI,OAAO,OAAO,0CAA0C,CAAC;GACvE,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,MAAM,YAAY,CAAC,GAAG;IAGxD,QAAQ,IAAI;IACZ,QAAQ,IAAI,OAAO,OAAO,mDAAmD,CAAC;GAChF,OAAO;IACL,QAAQ,IAAI;IACZ,IAAI;KACF,MAAM,cAAc,MAAM,kBAAkB;MAC1C,OAAO,SAAS;MAChB,WAAW,QAAQ;MACnB,SAAS,MAAM;KACjB,CAAC;KACD,QAAQ,YAAY;KACpB,cAAc,YAAY;KAC1B,QAAQ,IACN,OAAO,MACL,KAAK,MAAM,GAAG,gBAAgB,YAAY,MAAM,GAAG,YAAY,MAAM,YAAY,SAAS,KAAK,YAAY,OAAO,MAAM,GAAG,EAAE,EAAE,MAAM,IACvI,CACF;IACF,SAAS,OAAO;KACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;KACrE,MAAM,aACJ,QAAQ,SAAS,WAAW,KAAK,QAAQ,SAAS,QAAQ,IACtD,iEACA,4BAA4B;KAClC,QAAQ,IAAI,OAAO,OAAO,KAAK,YAAY,CAAC;KAC5C,OAAO;MACL,QAAQ;MACR,GAAG;MACH,OAAO,wBAAwB;KACjC;IACF;GACF;GAEA,IAAI,QAAQ,IAAI,eAAe;IAC7B,MAAM,iBAAiB,MAAM,WAAW,YAAY,QAAQ,IAAI,SAAS;IACzE,IAAI,CAAC,gBAAgB;KACnB,QAAQ,IAAI;KACZ,QAAQ,IACN,OAAO,OACL,mFACF,CACF;KACA,OAAO;MACL,QAAQ;MACR,GAAG;MACH;MACA,OACE;KACJ;IACF;IACA,IAAI,CAAC,SAAS,CAAC,aAAa;KAC1B,QAAQ,IAAI;KACZ,QAAQ,IACN,OAAO,OACL,oFACF,CACF;KACA,OAAO;MACL,QAAQ;MACR,GAAG;MACH;MACA,SAAS;MACT,OACE;KACJ;IACF;IAEA,UAAU;IACV,IAAI;KACF,MAAM,qBAAqB;MACzB;MACA,QAAQ;MACR,SAAS;MACT,WAAW,QAAQ;KACrB,CAAC;IACH,SAAS,OAAO;KACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;KACrE,MAAM,YACJ,QAAQ,SAAS,WAAW,KAAK,QAAQ,SAAS,QAAQ,IACtD,6DACA,0BAA0B;KAChC,QAAQ,IAAI,OAAO,OAAO,KAAK,WAAW,CAAC;KAC3C,OAAO;MACL,QAAQ;MACR,GAAG;MACH;MACA;MACA,OAAO,wBAAwB;KACjC;IACF;GACF,OAAO;IACL,QAAQ,IAAI;IACZ,QAAQ,IAAI,OAAO,OAAO,kDAAkD,CAAC;GAC/E;GAEA,OAAO;IACL,QAAQ;IACR,GAAG;IACH;IACA;GACF;EACF,CAAC;CACH;AACF"}
|
|
1
|
+
{"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Context } from \"effect\";\nimport { MISSING_CONFIG_MESSAGE } from \"../config\";\nimport {\n type ConfigHistoryEntry,\n fetchBosConfigFromFastKv,\n fetchConfigHistory,\n fetchDeployManifests,\n} from \"../fastkv\";\nimport {\n buildAndPushImage,\n deployImageToRailway,\n hasDocker,\n isValidImageDigest,\n resolveDeployImagePlan,\n resolveImageRef,\n} from \"../image-deploy\";\nimport { publishToFastKv } from \"../publish\";\nimport { openResolution } from \"../resolution/session\";\nimport { buildRollbackPayload, summarizeSlotPins, verifyRollbackSnapshot } from \"../rollback\";\nimport type { BosConfigInput } from \"../types\";\nimport { BosConfigSchema } from \"../types\";\nimport { colors, icons } from \"../utils/theme\";\nimport { type BosBuilder, BosDepsTag } from \"./shared\";\n\nexport function registerDeploy(builder: BosBuilder) {\n return {\n publish: builder.publish.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n };\n }),\n\n rollback: builder.rollback.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const { account, domain } = session.config ?? {};\n if (!account || !domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to roll back\",\n };\n }\n\n let history: ConfigHistoryEntry[];\n try {\n history = await fetchConfigHistory({\n accountId: account,\n gatewayId: domain,\n registry: input.registry,\n limit: input.limit,\n });\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to fetch publish history: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n if (history.length === 0) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `No publish history for ${account}/${domain} — nothing to roll back to`,\n };\n }\n\n const historyEntries = history.map((entry) => ({\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...(entry.txHash ? { txHash: entry.txHash } : {}),\n summary: summarizeSlotPins(entry.value as BosConfigInput),\n }));\n\n if (input.listOnly) {\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: historyEntries,\n };\n }\n\n const target =\n input.version !== undefined\n ? history.find((entry) => {\n const iso = new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString();\n return (\n String(entry.blockHeight) === input.version ||\n iso.startsWith(input.version as string)\n );\n })\n : input.previous\n ? history[1]\n : undefined;\n\n if (!target) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n history: historyEntries,\n error: input.version\n ? `No history entry matches \"${input.version}\" — pick a block height from the listing`\n : \"Specify --version <block-height> or --previous (interactive selection happens CLI-side)\",\n };\n }\n\n let liveValue: unknown;\n try {\n liveValue = await fetchBosConfigFromFastKv<unknown>(\n `bos://${account}/${domain}`,\n input.registry,\n );\n } catch {\n liveValue = undefined;\n }\n if (liveValue && JSON.stringify(liveValue) === JSON.stringify(target.value)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"The selected snapshot is identical to the live config — nothing to do\",\n };\n }\n\n const verification = await verifyRollbackSnapshot(target.value as BosConfigInput);\n const slotChecks = verification.slots.map((check) => ({\n slot: check.slot,\n ok: check.ok,\n ...(check.reason ? { reason: check.reason } : {}),\n }));\n if (!verification.ok && verification.verifiable) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n verification: slotChecks,\n error:\n \"Refusing to roll back — a pinned slot's bytes are gone or no longer match their SRI\",\n };\n }\n\n if (!verification.verifiable && !input.force) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error:\n \"Snapshot predates version manifests and cannot be verified — its bytes were overwritten in place. Re-run with --force to publish it anyway.\",\n };\n }\n\n const parsedTarget = BosConfigSchema.parse(target.value);\n const payload = buildRollbackPayload(parsedTarget, new Date().toISOString());\n\n const result = await publishToFastKv({\n bosConfig: payload,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n history: historyEntries,\n ...(slotChecks.length > 0 ? { verification: slotChecks } : {}),\n };\n }),\n\n deploy: builder.deploy.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n if (input.statusList) {\n if (!session.config?.account || !session.config.domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to list deploy manifests\",\n };\n }\n try {\n const manifests = await fetchDeployManifests({\n accountId: session.config.account,\n gatewayId: session.config.domain,\n registry: input.registry,\n });\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: manifests.map((entry) => ({\n key: entry.key,\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...((entry.value as { txHash?: string } | undefined)?.txHash\n ? { txHash: (entry.value as { txHash?: string }).txHash }\n : {}),\n ...((entry.value as { publishedAt?: string } | undefined)?.publishedAt\n ? { publishedAt: (entry.value as { publishedAt?: string }).publishedAt }\n : {}),\n })),\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to list deploy manifests: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n const imageDigestInput = input.imageDigest ?? process.env.BOS_IMAGE_DIGEST;\n if (imageDigestInput && !isValidImageDigest(imageDigestInput)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Invalid image digest \"${imageDigestInput}\" — expected sha256:<64 hex characters> (--image-digest / BOS_IMAGE_DIGEST)`,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: input.build,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: input.packages,\n network: input.network,\n privateKey: input.privateKey,\n registry: input.registry,\n fullUpload: input.fullUpload,\n });\n\n if (result.status === \"error\") {\n return {\n status: \"error\" as const,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n built: result.built,\n skipped: result.skipped,\n error: result.error,\n deployResults: result.deployResults,\n };\n }\n\n if (result.status === \"dry-run\") {\n return {\n status: \"dry-run\" as const,\n registryUrl: result.registryUrl,\n built: result.built,\n skipped: result.skipped,\n };\n }\n\n let nextSession = session;\n if (result.publishConfig) {\n const opened = await openResolution({ cwd: session.root });\n if (opened) {\n nextSession = opened;\n }\n }\n\n const configPublished = {\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n fingerprint: result.fingerprint,\n slotPins: result.slotPins,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n } as const;\n\n let image: string | undefined;\n let imageDigest: string | undefined;\n let service: string | undefined;\n\n const imagePlan = resolveDeployImagePlan({\n // A prebuilt digest pairs with the pushed ref (BOS_IMAGE from the CI\n // image job, or repository derivation) — ci.image is a build-time\n // choice, not a pin-time one; letting it win here could pin a digest\n // from a different image.\n imageRef: resolveImageRef({\n ciImage: imageDigestInput ? undefined : nextSession.config?.ci?.image,\n repository: nextSession.config?.repository,\n env: process.env,\n }),\n imageDigest: imageDigestInput,\n hasDocker: await hasDocker(),\n hasDockerfile: existsSync(join(session.root, \"Dockerfile\")),\n });\n\n if (imagePlan.kind === \"skip\") {\n console.log();\n console.log(colors.yellow(` Image skipped: ${imagePlan.reason}`));\n } else if (imagePlan.kind === \"prebuilt\") {\n image = imagePlan.image;\n imageDigest = imagePlan.digest;\n console.log();\n console.log(\n colors.green(\n ` ${icons.ok} Using pre-pushed image ${imagePlan.image}@${imagePlan.digest.slice(0, 19)}…`,\n ),\n );\n } else {\n console.log();\n try {\n const imageResult = await buildAndPushImage({\n image: imagePlan.image,\n configDir: session.root,\n verbose: input.verbose,\n });\n image = imageResult.image;\n imageDigest = imageResult.digest;\n console.log(\n colors.green(\n ` ${icons.ok} Image pushed ${imageResult.image}:${imageResult.tag}${imageResult.digest ? ` (${imageResult.digest.slice(0, 19)}…)` : \"\"}`,\n ),\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const imageError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Docker not found — install Docker to build the runtime image\"\n : `Image build/push failed: ${message}`;\n console.log(colors.yellow(` ${imageError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n error: `Config published but ${imageError}`,\n };\n }\n }\n\n if (process.env.RAILWAY_TOKEN) {\n const railwayService = input.service ?? nextSession.config?.ci?.railway?.service;\n if (!railwayService) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: ci.railway.service is not configured in bos.config.json\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n error:\n \"Config published but Railway deploy failed: ci.railway.service is not configured in bos.config.json\",\n };\n }\n if (!image || !imageDigest) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: no runtime image digest — set ci.image (or pass BOS_IMAGE_DIGEST) and make the image available\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service: railwayService,\n error:\n \"Config published but Railway deploy requires a runtime image (set ci.image, or pass BOS_IMAGE_DIGEST for a pre-pushed image)\",\n };\n }\n\n service = railwayService;\n try {\n await deployImageToRailway({\n image,\n digest: imageDigest,\n service: railwayService,\n configDir: session.root,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const railError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Railway CLI not found. Install it: npm i -g @railway/cli\"\n : `Railway deploy failed: ${message}`;\n console.log(colors.yellow(` ${railError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service,\n error: `Config published but ${railError}`,\n };\n }\n } else {\n console.log();\n console.log(colors.yellow(\" Railway deploy skipped (RAILWAY_TOKEN not set)\"));\n }\n\n return {\n status: \"deployed\" as const,\n ...configPublished,\n image,\n service,\n };\n }),\n };\n}\n"],"mappings":"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"}
|
package/dist/commands/init.cjs
CHANGED
|
@@ -58,7 +58,7 @@ function registerInit(builder) {
|
|
|
58
58
|
parentConfig = parent.parentConfig;
|
|
59
59
|
parentPluginKeys = parent.parentPluginKeys;
|
|
60
60
|
} catch (e) {
|
|
61
|
-
console.warn(`[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${e instanceof Error ? e.message : e}`);
|
|
61
|
+
console.warn(`[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${e instanceof Error ? e.message : String(e)}`);
|
|
62
62
|
return {
|
|
63
63
|
status: "error",
|
|
64
64
|
directory,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.cjs","names":["fetchParentConfig","parseBosUrl","resolve","timePhase","detectGitRemoteUrl","process","resolveSourceDir","scaffoldMinimalProject","personalizeConfig","convertChildConfigToAppForm","buildInitPatterns","buildPluginRouteExclusions","buildStarterRouteExclusions","copyFilteredFiles","existsSync","join","saveBosConfig","pruneUnusedUiFiles","writeInitSnapshot","personalizeAgentsMd","syncResolvedSharedDeps","openResolution","materializeViaLayer","Effect","makeProjectEnv","runPnpmInstall","runTypesGen","generateDatabaseMigrations","generateCodeArtifacts"],"sources":["../../src/commands/init.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { Effect } from \"effect\";\nimport {\n buildInitPatterns,\n buildPluginRouteExclusions,\n buildStarterRouteExclusions,\n convertChildConfigToAppForm,\n copyFilteredFiles,\n detectGitRemoteUrl,\n fetchParentConfig,\n generateDatabaseMigrations,\n personalizeAgentsMd,\n personalizeConfig,\n removeStrayLockfiles,\n resolveSourceDir,\n runPnpmInstall,\n runTypesGen,\n scaffoldMinimalProject,\n writeDevOverlayTemplate,\n writeInitSnapshot,\n} from \"../cli/init\";\nimport { pruneUnusedUiFiles } from \"../cli/prune\";\nimport { generateCodeArtifacts } from \"../code-artifacts\";\nimport type { OverrideSection, PhaseTiming } from \"../contract\";\nimport { makeProjectEnv } from \"../env/project-env\";\nimport { parseBosUrl } from \"../fastkv\";\nimport { materializeViaLayer } from \"../infra/materializer\";\nimport { timePhase } from \"../progress\";\nimport { openResolution } from \"../resolution/session\";\nimport { syncResolvedSharedDeps } from \"../shared-deps\";\nimport type { BosConfig, BosConfigInput, StarterLevel } from \"../types\";\nimport { saveBosConfig } from \"../utils/save-config\";\nimport type { BosBuilder } from \"./shared\";\n\nexport async function fetchInitParent(\n extendsAccount: string,\n extendsGateway: string,\n): Promise<{ parentConfig: BosConfig; parentPluginKeys: string[] }> {\n const parentConfig = await fetchParentConfig(extendsAccount, extendsGateway);\n const parentPluginKeys =\n parentConfig?.plugins && typeof parentConfig.plugins === \"object\"\n ? Object.keys(parentConfig.plugins)\n : [];\n return { parentConfig, parentPluginKeys };\n}\n\nfunction normalizeExtendsRef(extendsInput: string | undefined, fallback: string): string {\n if (!extendsInput) return fallback;\n return extendsInput.startsWith(\"bos://\") ? extendsInput : `bos://${extendsInput}`;\n}\n\nexport function registerInit(builder: BosBuilder) {\n return {\n init: builder.init.handler(async ({ input }) => {\n try {\n const timings: PhaseTiming[] = [];\n let extendsAccount = \"\";\n let extendsGateway = \"\";\n let directory = input.directory;\n const account = input.account;\n const domain = input.domain;\n let overrides = input.overrides as OverrideSection[] | undefined;\n let plugins = input.plugins;\n\n if (input.extends) {\n try {\n const { accountId, gatewayId } = parseBosUrl(normalizeExtendsRef(input.extends, \"\"));\n extendsAccount = accountId;\n extendsGateway = gatewayId;\n } catch {\n extendsAccount = \"\";\n extendsGateway = \"\";\n }\n }\n\n extendsAccount = extendsAccount || \"dev.everything.near\";\n extendsGateway = extendsGateway || \"everything.dev\";\n\n directory = directory || domain || extendsGateway;\n const targetDir = resolve(directory);\n const extendsRef = `bos://${extendsAccount}/${extendsGateway}`;\n\n let parentPluginKeys: string[] = [];\n let parentConfig: BosConfig | null = null;\n try {\n const parent = await timePhase(timings, \"parent config\", () =>\n fetchInitParent(extendsAccount, extendsGateway),\n );\n parentConfig = parent.parentConfig;\n parentPluginKeys = parent.parentPluginKeys;\n } catch (e) {\n console.warn(\n `[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${\n e instanceof Error ? e.message : e\n }`,\n );\n return {\n status: \"error\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied: 0,\n timings,\n error: `No config found at ${extendsRef} — are you sure this is the right parent?`,\n };\n }\n\n overrides = overrides?.length ? overrides : ([\"ui\", \"api\"] as OverrideSection[]);\n const level: StarterLevel = input.level ?? \"simple\";\n if (overrides.includes(\"plugins\") && plugins === undefined) {\n plugins = parentPluginKeys;\n }\n plugins = plugins ?? [];\n\n const pluginDirMap: Record<string, string> = {};\n if (parentConfig?.plugins) {\n for (const plugin of plugins) {\n const entry = (parentConfig.plugins as Record<string, unknown>)?.[plugin];\n if (entry && typeof entry === \"object\") {\n const dev = (entry as Record<string, unknown>).development;\n if (typeof dev === \"string\") {\n const match = dev.match(/^local:plugins\\/(.+)$/);\n if (match?.[1] && match[1] !== plugin) pluginDirMap[plugin] = match[1];\n }\n }\n }\n }\n\n const repository =\n (await detectGitRemoteUrl(process.cwd()).catch(() => undefined)) ??\n parentConfig?.repository;\n\n const {\n sourceDir,\n parentConfig: resolvedParentConfig,\n cleanup,\n } = await timePhase(timings, \"template source\", () =>\n resolveSourceDir({\n extendsAccount,\n extendsGateway,\n source: input.source,\n }),\n );\n\n parentConfig = resolvedParentConfig;\n\n const isMinimalScaffold = sourceDir === \"\";\n\n try {\n let filesCopied: number;\n let childBosConfig: BosConfigInput | null = null;\n\n if (isMinimalScaffold) {\n filesCopied = await timePhase(timings, \"scaffold project\", () =>\n scaffoldMinimalProject(targetDir, parentConfig as unknown as BosConfigInput, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain,\n plugins,\n overrides,\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n mode: \"init\",\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n } else {\n const patterns = buildInitPatterns(overrides, plugins, pluginDirMap);\n const routeExclusions = overrides.includes(\"ui\")\n ? buildPluginRouteExclusions(parentConfig, plugins)\n : [];\n const starterExclusions = overrides.includes(\"ui\")\n ? buildStarterRouteExclusions(level, parentConfig)\n : [];\n const copyIgnore = [...routeExclusions, ...starterExclusions];\n\n filesCopied = await timePhase(timings, \"copy files\", () =>\n copyFilteredFiles(sourceDir, targetDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n }),\n );\n\n // The child's authored config is always generated, never copied:\n // a TS-form parent's bos.app.ts imports everything-dev and cannot\n // load before the child's install. Write the JSON form from the\n // loaded parent config — the personalization +\n // convertChildConfigToAppForm below produce the child's own\n // authored bos.app.ts.\n if (!existsSync(join(targetDir, \"bos.config.json\"))) {\n await saveBosConfig(targetDir, parentConfig);\n }\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n workspaceOpts: { sourceDir },\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n\n if (overrides.includes(\"ui\")) {\n await timePhase(timings, \"prune unused ui files\", async () =>\n pruneUnusedUiFiles(targetDir, { log: console.log }),\n );\n }\n\n await timePhase(timings, \"write snapshot\", () =>\n writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize agents\", () =>\n personalizeAgentsMd(targetDir, { overrides, plugins }),\n );\n }\n\n await timePhase(timings, \"sync shared deps\", () =>\n syncResolvedSharedDeps({\n configDir: targetDir,\n hostMode: \"local\",\n bosConfig: childBosConfig\n ? (childBosConfig as unknown as Record<string, unknown>)\n : undefined,\n }),\n );\n\n // A stray lockfile (copied or left from a previous run) would pin\n // stale framework resolutions — the fresh install re-resolves.\n removeStrayLockfiles(targetDir);\n\n const initConfig = await timePhase(timings, \"resolve config\", () =>\n openResolution({ cwd: targetDir }).catch((error: unknown) => {\n console.warn(\n \"[init] Skipping config resolution — the child has no node_modules yet; `bos dev` resolves after `pnpm install`.\",\n error instanceof Error ? error.message : error,\n );\n return null;\n }),\n );\n const initRuntime = initConfig?.runtime;\n if (initRuntime) {\n await timePhase(timings, \"generate env/docker\", async () => {\n await materializeViaLayer(targetDir, initRuntime);\n });\n }\n await timePhase(timings, \"create env file\", async () => {\n await Effect.runPromise(makeProjectEnv().ensureFile(targetDir));\n });\n\n if (!input.noInstall) {\n await timePhase(timings, \"install dependencies\", () => runPnpmInstall(targetDir));\n await timePhase(timings, \"generate types\", () => runTypesGen(targetDir));\n await timePhase(timings, \"generate migrations\", () =>\n generateDatabaseMigrations(targetDir),\n );\n }\n\n const initArtifactsConfig = initConfig?.config;\n if (input.noInstall && initArtifactsConfig) {\n await timePhase(timings, \"generate code artifacts\", () =>\n generateCodeArtifacts(targetDir, initArtifactsConfig),\n );\n }\n\n return {\n status: \"initialized\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied,\n timings,\n targetDir,\n };\n } finally {\n await cleanup();\n }\n } catch (error) {\n const extendsRef = normalizeExtendsRef(\n input.extends,\n \"bos://dev.everything.near/everything.dev\",\n );\n return {\n status: \"error\" as const,\n directory: input.directory ?? \"\",\n extendsRef,\n account: input.account,\n domain: input.domain,\n extends: extendsRef,\n plugins: input.plugins ?? [],\n overrides: input.overrides,\n filesCopied: 0,\n timings: [],\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"init.cjs","names":["fetchParentConfig","parseBosUrl","resolve","timePhase","detectGitRemoteUrl","process","resolveSourceDir","scaffoldMinimalProject","personalizeConfig","convertChildConfigToAppForm","buildInitPatterns","buildPluginRouteExclusions","buildStarterRouteExclusions","copyFilteredFiles","existsSync","join","saveBosConfig","pruneUnusedUiFiles","writeInitSnapshot","personalizeAgentsMd","syncResolvedSharedDeps","openResolution","materializeViaLayer","Effect","makeProjectEnv","runPnpmInstall","runTypesGen","generateDatabaseMigrations","generateCodeArtifacts"],"sources":["../../src/commands/init.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { Effect } from \"effect\";\nimport {\n buildInitPatterns,\n buildPluginRouteExclusions,\n buildStarterRouteExclusions,\n convertChildConfigToAppForm,\n copyFilteredFiles,\n detectGitRemoteUrl,\n fetchParentConfig,\n generateDatabaseMigrations,\n personalizeAgentsMd,\n personalizeConfig,\n removeStrayLockfiles,\n resolveSourceDir,\n runPnpmInstall,\n runTypesGen,\n scaffoldMinimalProject,\n writeDevOverlayTemplate,\n writeInitSnapshot,\n} from \"../cli/init\";\nimport { pruneUnusedUiFiles } from \"../cli/prune\";\nimport { generateCodeArtifacts } from \"../code-artifacts\";\nimport type { OverrideSection, PhaseTiming } from \"../contract\";\nimport { makeProjectEnv } from \"../env/project-env\";\nimport { parseBosUrl } from \"../fastkv\";\nimport { materializeViaLayer } from \"../infra/materializer\";\nimport { timePhase } from \"../progress\";\nimport { openResolution } from \"../resolution/session\";\nimport { syncResolvedSharedDeps } from \"../shared-deps\";\nimport type { BosConfig, BosConfigInput, StarterLevel } from \"../types\";\nimport { saveBosConfig } from \"../utils/save-config\";\nimport type { BosBuilder } from \"./shared\";\n\nexport async function fetchInitParent(\n extendsAccount: string,\n extendsGateway: string,\n): Promise<{ parentConfig: BosConfig; parentPluginKeys: string[] }> {\n const parentConfig = await fetchParentConfig(extendsAccount, extendsGateway);\n const parentPluginKeys =\n parentConfig?.plugins && typeof parentConfig.plugins === \"object\"\n ? Object.keys(parentConfig.plugins)\n : [];\n return { parentConfig, parentPluginKeys };\n}\n\nfunction normalizeExtendsRef(extendsInput: string | undefined, fallback: string): string {\n if (!extendsInput) return fallback;\n return extendsInput.startsWith(\"bos://\") ? extendsInput : `bos://${extendsInput}`;\n}\n\nexport function registerInit(builder: BosBuilder) {\n return {\n init: builder.init.handler(async ({ input }) => {\n try {\n const timings: PhaseTiming[] = [];\n let extendsAccount = \"\";\n let extendsGateway = \"\";\n let directory = input.directory;\n const account = input.account;\n const domain = input.domain;\n let overrides = input.overrides as OverrideSection[] | undefined;\n let plugins = input.plugins;\n\n if (input.extends) {\n try {\n const { accountId, gatewayId } = parseBosUrl(normalizeExtendsRef(input.extends, \"\"));\n extendsAccount = accountId;\n extendsGateway = gatewayId;\n } catch {\n extendsAccount = \"\";\n extendsGateway = \"\";\n }\n }\n\n extendsAccount = extendsAccount || \"dev.everything.near\";\n extendsGateway = extendsGateway || \"everything.dev\";\n\n directory = directory || domain || extendsGateway;\n const targetDir = resolve(directory);\n const extendsRef = `bos://${extendsAccount}/${extendsGateway}`;\n\n let parentPluginKeys: string[] = [];\n let parentConfig: BosConfig | null = null;\n try {\n const parent = await timePhase(timings, \"parent config\", () =>\n fetchInitParent(extendsAccount, extendsGateway),\n );\n parentConfig = parent.parentConfig;\n parentPluginKeys = parent.parentPluginKeys;\n } catch (e) {\n console.warn(\n `[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${\n e instanceof Error ? e.message : String(e)\n }`,\n );\n return {\n status: \"error\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied: 0,\n timings,\n error: `No config found at ${extendsRef} — are you sure this is the right parent?`,\n };\n }\n\n overrides = overrides?.length ? overrides : ([\"ui\", \"api\"] as OverrideSection[]);\n const level: StarterLevel = input.level ?? \"simple\";\n if (overrides.includes(\"plugins\") && plugins === undefined) {\n plugins = parentPluginKeys;\n }\n plugins = plugins ?? [];\n\n const pluginDirMap: Record<string, string> = {};\n if (parentConfig?.plugins) {\n for (const plugin of plugins) {\n const entry = (parentConfig.plugins as Record<string, unknown>)?.[plugin];\n if (entry && typeof entry === \"object\") {\n const dev = (entry as Record<string, unknown>).development;\n if (typeof dev === \"string\") {\n const match = dev.match(/^local:plugins\\/(.+)$/);\n if (match?.[1] && match[1] !== plugin) pluginDirMap[plugin] = match[1];\n }\n }\n }\n }\n\n const repository =\n (await detectGitRemoteUrl(process.cwd()).catch(() => undefined)) ??\n parentConfig?.repository;\n\n const {\n sourceDir,\n parentConfig: resolvedParentConfig,\n cleanup,\n } = await timePhase(timings, \"template source\", () =>\n resolveSourceDir({\n extendsAccount,\n extendsGateway,\n source: input.source,\n }),\n );\n\n parentConfig = resolvedParentConfig;\n\n const isMinimalScaffold = sourceDir === \"\";\n\n try {\n let filesCopied: number;\n let childBosConfig: BosConfigInput | null = null;\n\n if (isMinimalScaffold) {\n filesCopied = await timePhase(timings, \"scaffold project\", () =>\n scaffoldMinimalProject(targetDir, parentConfig as unknown as BosConfigInput, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain,\n plugins,\n overrides,\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n mode: \"init\",\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n } else {\n const patterns = buildInitPatterns(overrides, plugins, pluginDirMap);\n const routeExclusions = overrides.includes(\"ui\")\n ? buildPluginRouteExclusions(parentConfig, plugins)\n : [];\n const starterExclusions = overrides.includes(\"ui\")\n ? buildStarterRouteExclusions(level, parentConfig)\n : [];\n const copyIgnore = [...routeExclusions, ...starterExclusions];\n\n filesCopied = await timePhase(timings, \"copy files\", () =>\n copyFilteredFiles(sourceDir, targetDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n }),\n );\n\n // The child's authored config is always generated, never copied:\n // a TS-form parent's bos.app.ts imports everything-dev and cannot\n // load before the child's install. Write the JSON form from the\n // loaded parent config — the personalization +\n // convertChildConfigToAppForm below produce the child's own\n // authored bos.app.ts.\n if (!existsSync(join(targetDir, \"bos.config.json\"))) {\n await saveBosConfig(targetDir, parentConfig);\n }\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n workspaceOpts: { sourceDir },\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n\n if (overrides.includes(\"ui\")) {\n await timePhase(timings, \"prune unused ui files\", async () =>\n pruneUnusedUiFiles(targetDir, { log: console.log }),\n );\n }\n\n await timePhase(timings, \"write snapshot\", () =>\n writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize agents\", () =>\n personalizeAgentsMd(targetDir, { overrides, plugins }),\n );\n }\n\n await timePhase(timings, \"sync shared deps\", () =>\n syncResolvedSharedDeps({\n configDir: targetDir,\n hostMode: \"local\",\n bosConfig: childBosConfig\n ? (childBosConfig as unknown as Record<string, unknown>)\n : undefined,\n }),\n );\n\n // A stray lockfile (copied or left from a previous run) would pin\n // stale framework resolutions — the fresh install re-resolves.\n removeStrayLockfiles(targetDir);\n\n const initConfig = await timePhase(timings, \"resolve config\", () =>\n openResolution({ cwd: targetDir }).catch((error: unknown) => {\n console.warn(\n \"[init] Skipping config resolution — the child has no node_modules yet; `bos dev` resolves after `pnpm install`.\",\n error instanceof Error ? error.message : error,\n );\n return null;\n }),\n );\n const initRuntime = initConfig?.runtime;\n if (initRuntime) {\n await timePhase(timings, \"generate env/docker\", async () => {\n await materializeViaLayer(targetDir, initRuntime);\n });\n }\n await timePhase(timings, \"create env file\", async () => {\n await Effect.runPromise(makeProjectEnv().ensureFile(targetDir));\n });\n\n if (!input.noInstall) {\n await timePhase(timings, \"install dependencies\", () => runPnpmInstall(targetDir));\n await timePhase(timings, \"generate types\", () => runTypesGen(targetDir));\n await timePhase(timings, \"generate migrations\", () =>\n generateDatabaseMigrations(targetDir),\n );\n }\n\n const initArtifactsConfig = initConfig?.config;\n if (input.noInstall && initArtifactsConfig) {\n await timePhase(timings, \"generate code artifacts\", () =>\n generateCodeArtifacts(targetDir, initArtifactsConfig),\n );\n }\n\n return {\n status: \"initialized\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied,\n timings,\n targetDir,\n };\n } finally {\n await cleanup();\n }\n } catch (error) {\n const extendsRef = normalizeExtendsRef(\n input.extends,\n \"bos://dev.everything.near/everything.dev\",\n );\n return {\n status: \"error\" as const,\n directory: input.directory ?? \"\",\n extendsRef,\n account: input.account,\n domain: input.domain,\n extends: extendsRef,\n plugins: input.plugins ?? [],\n overrides: input.overrides,\n filesCopied: 0,\n timings: [],\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n };\n}\n"],"mappings":"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"}
|
package/dist/commands/init.mjs
CHANGED
|
@@ -56,7 +56,7 @@ function registerInit(builder) {
|
|
|
56
56
|
parentConfig = parent.parentConfig;
|
|
57
57
|
parentPluginKeys = parent.parentPluginKeys;
|
|
58
58
|
} catch (e) {
|
|
59
|
-
console.warn(`[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${e instanceof Error ? e.message : e}`);
|
|
59
|
+
console.warn(`[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${e instanceof Error ? e.message : String(e)}`);
|
|
60
60
|
return {
|
|
61
61
|
status: "error",
|
|
62
62
|
directory,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.mjs","names":[],"sources":["../../src/commands/init.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { Effect } from \"effect\";\nimport {\n buildInitPatterns,\n buildPluginRouteExclusions,\n buildStarterRouteExclusions,\n convertChildConfigToAppForm,\n copyFilteredFiles,\n detectGitRemoteUrl,\n fetchParentConfig,\n generateDatabaseMigrations,\n personalizeAgentsMd,\n personalizeConfig,\n removeStrayLockfiles,\n resolveSourceDir,\n runPnpmInstall,\n runTypesGen,\n scaffoldMinimalProject,\n writeDevOverlayTemplate,\n writeInitSnapshot,\n} from \"../cli/init\";\nimport { pruneUnusedUiFiles } from \"../cli/prune\";\nimport { generateCodeArtifacts } from \"../code-artifacts\";\nimport type { OverrideSection, PhaseTiming } from \"../contract\";\nimport { makeProjectEnv } from \"../env/project-env\";\nimport { parseBosUrl } from \"../fastkv\";\nimport { materializeViaLayer } from \"../infra/materializer\";\nimport { timePhase } from \"../progress\";\nimport { openResolution } from \"../resolution/session\";\nimport { syncResolvedSharedDeps } from \"../shared-deps\";\nimport type { BosConfig, BosConfigInput, StarterLevel } from \"../types\";\nimport { saveBosConfig } from \"../utils/save-config\";\nimport type { BosBuilder } from \"./shared\";\n\nexport async function fetchInitParent(\n extendsAccount: string,\n extendsGateway: string,\n): Promise<{ parentConfig: BosConfig; parentPluginKeys: string[] }> {\n const parentConfig = await fetchParentConfig(extendsAccount, extendsGateway);\n const parentPluginKeys =\n parentConfig?.plugins && typeof parentConfig.plugins === \"object\"\n ? Object.keys(parentConfig.plugins)\n : [];\n return { parentConfig, parentPluginKeys };\n}\n\nfunction normalizeExtendsRef(extendsInput: string | undefined, fallback: string): string {\n if (!extendsInput) return fallback;\n return extendsInput.startsWith(\"bos://\") ? extendsInput : `bos://${extendsInput}`;\n}\n\nexport function registerInit(builder: BosBuilder) {\n return {\n init: builder.init.handler(async ({ input }) => {\n try {\n const timings: PhaseTiming[] = [];\n let extendsAccount = \"\";\n let extendsGateway = \"\";\n let directory = input.directory;\n const account = input.account;\n const domain = input.domain;\n let overrides = input.overrides as OverrideSection[] | undefined;\n let plugins = input.plugins;\n\n if (input.extends) {\n try {\n const { accountId, gatewayId } = parseBosUrl(normalizeExtendsRef(input.extends, \"\"));\n extendsAccount = accountId;\n extendsGateway = gatewayId;\n } catch {\n extendsAccount = \"\";\n extendsGateway = \"\";\n }\n }\n\n extendsAccount = extendsAccount || \"dev.everything.near\";\n extendsGateway = extendsGateway || \"everything.dev\";\n\n directory = directory || domain || extendsGateway;\n const targetDir = resolve(directory);\n const extendsRef = `bos://${extendsAccount}/${extendsGateway}`;\n\n let parentPluginKeys: string[] = [];\n let parentConfig: BosConfig | null = null;\n try {\n const parent = await timePhase(timings, \"parent config\", () =>\n fetchInitParent(extendsAccount, extendsGateway),\n );\n parentConfig = parent.parentConfig;\n parentPluginKeys = parent.parentPluginKeys;\n } catch (e) {\n console.warn(\n `[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${\n e instanceof Error ? e.message : e\n }`,\n );\n return {\n status: \"error\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied: 0,\n timings,\n error: `No config found at ${extendsRef} — are you sure this is the right parent?`,\n };\n }\n\n overrides = overrides?.length ? overrides : ([\"ui\", \"api\"] as OverrideSection[]);\n const level: StarterLevel = input.level ?? \"simple\";\n if (overrides.includes(\"plugins\") && plugins === undefined) {\n plugins = parentPluginKeys;\n }\n plugins = plugins ?? [];\n\n const pluginDirMap: Record<string, string> = {};\n if (parentConfig?.plugins) {\n for (const plugin of plugins) {\n const entry = (parentConfig.plugins as Record<string, unknown>)?.[plugin];\n if (entry && typeof entry === \"object\") {\n const dev = (entry as Record<string, unknown>).development;\n if (typeof dev === \"string\") {\n const match = dev.match(/^local:plugins\\/(.+)$/);\n if (match?.[1] && match[1] !== plugin) pluginDirMap[plugin] = match[1];\n }\n }\n }\n }\n\n const repository =\n (await detectGitRemoteUrl(process.cwd()).catch(() => undefined)) ??\n parentConfig?.repository;\n\n const {\n sourceDir,\n parentConfig: resolvedParentConfig,\n cleanup,\n } = await timePhase(timings, \"template source\", () =>\n resolveSourceDir({\n extendsAccount,\n extendsGateway,\n source: input.source,\n }),\n );\n\n parentConfig = resolvedParentConfig;\n\n const isMinimalScaffold = sourceDir === \"\";\n\n try {\n let filesCopied: number;\n let childBosConfig: BosConfigInput | null = null;\n\n if (isMinimalScaffold) {\n filesCopied = await timePhase(timings, \"scaffold project\", () =>\n scaffoldMinimalProject(targetDir, parentConfig as unknown as BosConfigInput, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain,\n plugins,\n overrides,\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n mode: \"init\",\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n } else {\n const patterns = buildInitPatterns(overrides, plugins, pluginDirMap);\n const routeExclusions = overrides.includes(\"ui\")\n ? buildPluginRouteExclusions(parentConfig, plugins)\n : [];\n const starterExclusions = overrides.includes(\"ui\")\n ? buildStarterRouteExclusions(level, parentConfig)\n : [];\n const copyIgnore = [...routeExclusions, ...starterExclusions];\n\n filesCopied = await timePhase(timings, \"copy files\", () =>\n copyFilteredFiles(sourceDir, targetDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n }),\n );\n\n // The child's authored config is always generated, never copied:\n // a TS-form parent's bos.app.ts imports everything-dev and cannot\n // load before the child's install. Write the JSON form from the\n // loaded parent config — the personalization +\n // convertChildConfigToAppForm below produce the child's own\n // authored bos.app.ts.\n if (!existsSync(join(targetDir, \"bos.config.json\"))) {\n await saveBosConfig(targetDir, parentConfig);\n }\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n workspaceOpts: { sourceDir },\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n\n if (overrides.includes(\"ui\")) {\n await timePhase(timings, \"prune unused ui files\", async () =>\n pruneUnusedUiFiles(targetDir, { log: console.log }),\n );\n }\n\n await timePhase(timings, \"write snapshot\", () =>\n writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize agents\", () =>\n personalizeAgentsMd(targetDir, { overrides, plugins }),\n );\n }\n\n await timePhase(timings, \"sync shared deps\", () =>\n syncResolvedSharedDeps({\n configDir: targetDir,\n hostMode: \"local\",\n bosConfig: childBosConfig\n ? (childBosConfig as unknown as Record<string, unknown>)\n : undefined,\n }),\n );\n\n // A stray lockfile (copied or left from a previous run) would pin\n // stale framework resolutions — the fresh install re-resolves.\n removeStrayLockfiles(targetDir);\n\n const initConfig = await timePhase(timings, \"resolve config\", () =>\n openResolution({ cwd: targetDir }).catch((error: unknown) => {\n console.warn(\n \"[init] Skipping config resolution — the child has no node_modules yet; `bos dev` resolves after `pnpm install`.\",\n error instanceof Error ? error.message : error,\n );\n return null;\n }),\n );\n const initRuntime = initConfig?.runtime;\n if (initRuntime) {\n await timePhase(timings, \"generate env/docker\", async () => {\n await materializeViaLayer(targetDir, initRuntime);\n });\n }\n await timePhase(timings, \"create env file\", async () => {\n await Effect.runPromise(makeProjectEnv().ensureFile(targetDir));\n });\n\n if (!input.noInstall) {\n await timePhase(timings, \"install dependencies\", () => runPnpmInstall(targetDir));\n await timePhase(timings, \"generate types\", () => runTypesGen(targetDir));\n await timePhase(timings, \"generate migrations\", () =>\n generateDatabaseMigrations(targetDir),\n );\n }\n\n const initArtifactsConfig = initConfig?.config;\n if (input.noInstall && initArtifactsConfig) {\n await timePhase(timings, \"generate code artifacts\", () =>\n generateCodeArtifacts(targetDir, initArtifactsConfig),\n );\n }\n\n return {\n status: \"initialized\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied,\n timings,\n targetDir,\n };\n } finally {\n await cleanup();\n }\n } catch (error) {\n const extendsRef = normalizeExtendsRef(\n input.extends,\n \"bos://dev.everything.near/everything.dev\",\n );\n return {\n status: \"error\" as const,\n directory: input.directory ?? \"\",\n extendsRef,\n account: input.account,\n domain: input.domain,\n extends: extendsRef,\n plugins: input.plugins ?? [],\n overrides: input.overrides,\n filesCopied: 0,\n timings: [],\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"init.mjs","names":[],"sources":["../../src/commands/init.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { Effect } from \"effect\";\nimport {\n buildInitPatterns,\n buildPluginRouteExclusions,\n buildStarterRouteExclusions,\n convertChildConfigToAppForm,\n copyFilteredFiles,\n detectGitRemoteUrl,\n fetchParentConfig,\n generateDatabaseMigrations,\n personalizeAgentsMd,\n personalizeConfig,\n removeStrayLockfiles,\n resolveSourceDir,\n runPnpmInstall,\n runTypesGen,\n scaffoldMinimalProject,\n writeDevOverlayTemplate,\n writeInitSnapshot,\n} from \"../cli/init\";\nimport { pruneUnusedUiFiles } from \"../cli/prune\";\nimport { generateCodeArtifacts } from \"../code-artifacts\";\nimport type { OverrideSection, PhaseTiming } from \"../contract\";\nimport { makeProjectEnv } from \"../env/project-env\";\nimport { parseBosUrl } from \"../fastkv\";\nimport { materializeViaLayer } from \"../infra/materializer\";\nimport { timePhase } from \"../progress\";\nimport { openResolution } from \"../resolution/session\";\nimport { syncResolvedSharedDeps } from \"../shared-deps\";\nimport type { BosConfig, BosConfigInput, StarterLevel } from \"../types\";\nimport { saveBosConfig } from \"../utils/save-config\";\nimport type { BosBuilder } from \"./shared\";\n\nexport async function fetchInitParent(\n extendsAccount: string,\n extendsGateway: string,\n): Promise<{ parentConfig: BosConfig; parentPluginKeys: string[] }> {\n const parentConfig = await fetchParentConfig(extendsAccount, extendsGateway);\n const parentPluginKeys =\n parentConfig?.plugins && typeof parentConfig.plugins === \"object\"\n ? Object.keys(parentConfig.plugins)\n : [];\n return { parentConfig, parentPluginKeys };\n}\n\nfunction normalizeExtendsRef(extendsInput: string | undefined, fallback: string): string {\n if (!extendsInput) return fallback;\n return extendsInput.startsWith(\"bos://\") ? extendsInput : `bos://${extendsInput}`;\n}\n\nexport function registerInit(builder: BosBuilder) {\n return {\n init: builder.init.handler(async ({ input }) => {\n try {\n const timings: PhaseTiming[] = [];\n let extendsAccount = \"\";\n let extendsGateway = \"\";\n let directory = input.directory;\n const account = input.account;\n const domain = input.domain;\n let overrides = input.overrides as OverrideSection[] | undefined;\n let plugins = input.plugins;\n\n if (input.extends) {\n try {\n const { accountId, gatewayId } = parseBosUrl(normalizeExtendsRef(input.extends, \"\"));\n extendsAccount = accountId;\n extendsGateway = gatewayId;\n } catch {\n extendsAccount = \"\";\n extendsGateway = \"\";\n }\n }\n\n extendsAccount = extendsAccount || \"dev.everything.near\";\n extendsGateway = extendsGateway || \"everything.dev\";\n\n directory = directory || domain || extendsGateway;\n const targetDir = resolve(directory);\n const extendsRef = `bos://${extendsAccount}/${extendsGateway}`;\n\n let parentPluginKeys: string[] = [];\n let parentConfig: BosConfig | null = null;\n try {\n const parent = await timePhase(timings, \"parent config\", () =>\n fetchInitParent(extendsAccount, extendsGateway),\n );\n parentConfig = parent.parentConfig;\n parentPluginKeys = parent.parentPluginKeys;\n } catch (e) {\n console.warn(\n `[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${\n e instanceof Error ? e.message : String(e)\n }`,\n );\n return {\n status: \"error\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied: 0,\n timings,\n error: `No config found at ${extendsRef} — are you sure this is the right parent?`,\n };\n }\n\n overrides = overrides?.length ? overrides : ([\"ui\", \"api\"] as OverrideSection[]);\n const level: StarterLevel = input.level ?? \"simple\";\n if (overrides.includes(\"plugins\") && plugins === undefined) {\n plugins = parentPluginKeys;\n }\n plugins = plugins ?? [];\n\n const pluginDirMap: Record<string, string> = {};\n if (parentConfig?.plugins) {\n for (const plugin of plugins) {\n const entry = (parentConfig.plugins as Record<string, unknown>)?.[plugin];\n if (entry && typeof entry === \"object\") {\n const dev = (entry as Record<string, unknown>).development;\n if (typeof dev === \"string\") {\n const match = dev.match(/^local:plugins\\/(.+)$/);\n if (match?.[1] && match[1] !== plugin) pluginDirMap[plugin] = match[1];\n }\n }\n }\n }\n\n const repository =\n (await detectGitRemoteUrl(process.cwd()).catch(() => undefined)) ??\n parentConfig?.repository;\n\n const {\n sourceDir,\n parentConfig: resolvedParentConfig,\n cleanup,\n } = await timePhase(timings, \"template source\", () =>\n resolveSourceDir({\n extendsAccount,\n extendsGateway,\n source: input.source,\n }),\n );\n\n parentConfig = resolvedParentConfig;\n\n const isMinimalScaffold = sourceDir === \"\";\n\n try {\n let filesCopied: number;\n let childBosConfig: BosConfigInput | null = null;\n\n if (isMinimalScaffold) {\n filesCopied = await timePhase(timings, \"scaffold project\", () =>\n scaffoldMinimalProject(targetDir, parentConfig as unknown as BosConfigInput, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain,\n plugins,\n overrides,\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n mode: \"init\",\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n } else {\n const patterns = buildInitPatterns(overrides, plugins, pluginDirMap);\n const routeExclusions = overrides.includes(\"ui\")\n ? buildPluginRouteExclusions(parentConfig, plugins)\n : [];\n const starterExclusions = overrides.includes(\"ui\")\n ? buildStarterRouteExclusions(level, parentConfig)\n : [];\n const copyIgnore = [...routeExclusions, ...starterExclusions];\n\n filesCopied = await timePhase(timings, \"copy files\", () =>\n copyFilteredFiles(sourceDir, targetDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n }),\n );\n\n // The child's authored config is always generated, never copied:\n // a TS-form parent's bos.app.ts imports everything-dev and cannot\n // load before the child's install. Write the JSON form from the\n // loaded parent config — the personalization +\n // convertChildConfigToAppForm below produce the child's own\n // authored bos.app.ts.\n if (!existsSync(join(targetDir, \"bos.config.json\"))) {\n await saveBosConfig(targetDir, parentConfig);\n }\n\n await timePhase(timings, \"personalize config\", () =>\n personalizeConfig(targetDir, {\n extendsAccount,\n extendsGateway,\n account: account || extendsAccount,\n domain: domain || extendsGateway,\n plugins,\n overrides,\n workspaceOpts: { sourceDir },\n repository,\n title: parentConfig?.title,\n description: parentConfig?.description,\n testnet: parentConfig?.testnet,\n staging: parentConfig?.staging,\n starter: level,\n }),\n );\n\n childBosConfig = await timePhase(timings, \"authored config form\", () =>\n convertChildConfigToAppForm(targetDir),\n );\n\n writeDevOverlayTemplate(targetDir, {\n extendsRef: `bos://${extendsAccount}/${extendsGateway}`,\n });\n\n if (overrides.includes(\"ui\")) {\n await timePhase(timings, \"prune unused ui files\", async () =>\n pruneUnusedUiFiles(targetDir, { log: console.log }),\n );\n }\n\n await timePhase(timings, \"write snapshot\", () =>\n writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {\n overrides,\n plugins,\n ignore: copyIgnore,\n starter: level,\n }),\n );\n\n await timePhase(timings, \"personalize agents\", () =>\n personalizeAgentsMd(targetDir, { overrides, plugins }),\n );\n }\n\n await timePhase(timings, \"sync shared deps\", () =>\n syncResolvedSharedDeps({\n configDir: targetDir,\n hostMode: \"local\",\n bosConfig: childBosConfig\n ? (childBosConfig as unknown as Record<string, unknown>)\n : undefined,\n }),\n );\n\n // A stray lockfile (copied or left from a previous run) would pin\n // stale framework resolutions — the fresh install re-resolves.\n removeStrayLockfiles(targetDir);\n\n const initConfig = await timePhase(timings, \"resolve config\", () =>\n openResolution({ cwd: targetDir }).catch((error: unknown) => {\n console.warn(\n \"[init] Skipping config resolution — the child has no node_modules yet; `bos dev` resolves after `pnpm install`.\",\n error instanceof Error ? error.message : error,\n );\n return null;\n }),\n );\n const initRuntime = initConfig?.runtime;\n if (initRuntime) {\n await timePhase(timings, \"generate env/docker\", async () => {\n await materializeViaLayer(targetDir, initRuntime);\n });\n }\n await timePhase(timings, \"create env file\", async () => {\n await Effect.runPromise(makeProjectEnv().ensureFile(targetDir));\n });\n\n if (!input.noInstall) {\n await timePhase(timings, \"install dependencies\", () => runPnpmInstall(targetDir));\n await timePhase(timings, \"generate types\", () => runTypesGen(targetDir));\n await timePhase(timings, \"generate migrations\", () =>\n generateDatabaseMigrations(targetDir),\n );\n }\n\n const initArtifactsConfig = initConfig?.config;\n if (input.noInstall && initArtifactsConfig) {\n await timePhase(timings, \"generate code artifacts\", () =>\n generateCodeArtifacts(targetDir, initArtifactsConfig),\n );\n }\n\n return {\n status: \"initialized\" as const,\n directory,\n extendsRef,\n account,\n domain,\n extends: extendsRef,\n plugins,\n overrides,\n filesCopied,\n timings,\n targetDir,\n };\n } finally {\n await cleanup();\n }\n } catch (error) {\n const extendsRef = normalizeExtendsRef(\n input.extends,\n \"bos://dev.everything.near/everything.dev\",\n );\n return {\n status: \"error\" as const,\n directory: input.directory ?? \"\",\n extendsRef,\n account: input.account,\n domain: input.domain,\n extends: extendsRef,\n plugins: input.plugins ?? [],\n overrides: input.overrides,\n filesCopied: 0,\n timings: [],\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n };\n}\n"],"mappings":"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"}
|
|
@@ -59,7 +59,7 @@ function registerPlugins(builder) {
|
|
|
59
59
|
await require_save_config.saveBosConfig(session.root, {
|
|
60
60
|
...authored,
|
|
61
61
|
plugins: {
|
|
62
|
-
...authored.plugins
|
|
62
|
+
...authored.plugins,
|
|
63
63
|
[key]: applyEntryDelta(authoredBase)
|
|
64
64
|
}
|
|
65
65
|
});
|
|
@@ -96,7 +96,7 @@ function registerPlugins(builder) {
|
|
|
96
96
|
};
|
|
97
97
|
const authored = session.rawConfig;
|
|
98
98
|
if (authored) {
|
|
99
|
-
const authoredPlugins = { ...authored.plugins
|
|
99
|
+
const authoredPlugins = { ...authored.plugins };
|
|
100
100
|
if (authoredPlugins[input.key] === void 0) {
|
|
101
101
|
if ((0, node_fs.existsSync)((0, node_path.join)(session.root, "bos.app.ts"))) return {
|
|
102
102
|
status: "error",
|