@dragonmastery/tamer 0.36.5 → 0.36.6

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.
@@ -32,7 +32,10 @@ function topoSortWorkersByServiceBindings(workers, config, naming, env) {
32
32
  visiting.add(key);
33
33
  const cfg = byKey.get(key);
34
34
  if (cfg) {
35
- const deps = rewriteIntraStackServiceTargets(mergedWorkerConfigForEnv(cfg, env, config.tenant), intraMap).services?.map((s) => s.service) ?? [];
35
+ const merged = rewriteIntraStackServiceTargets(mergedWorkerConfigForEnv(cfg, env, config.tenant), intraMap);
36
+ const serviceDeps = merged.services?.map((s) => s.service) ?? [];
37
+ const doDeps = merged.durable_objects?.bindings?.map((b) => b.script_name).filter((s) => typeof s === "string" && s.length > 0).map((s) => intraMap.get(s) ?? s) ?? [];
38
+ const deps = [...serviceDeps, ...doDeps];
36
39
  for (const dep of deps) {
37
40
  const depKey = scriptNameToKey.get(dep);
38
41
  if (depKey && depKey !== key) visit(depKey);
@@ -158,4 +161,4 @@ async function runDeploy(options) {
158
161
 
159
162
  //#endregion
160
163
  export { runDeploy };
161
- //# sourceMappingURL=deploy-ByatGWlQ.mjs.map
164
+ //# sourceMappingURL=deploy-CiGgo_Om.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy-CiGgo_Om.mjs","names":["out: WorkerEntry[]","deploySecrets: Awaited<\n ReturnType<typeof createDeploySecretsResources>\n > | null","buildEnv: Record<string, string>"],"sources":["../src/cli/commands/deploy.ts"],"sourcesContent":["import { loadConfig, getWorkers, getConfigBaseDir } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { wranglerConfigCliArgs } from \"../../core/wrangler/wranglerOutFile.js\";\nimport { spawnWranglerSync, spawnBuildSync } from \"../../core/wrangler/wranglerSpawn.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport {\n buildIntraStackScriptNameMap,\n mergedWorkerConfigForEnv,\n resolveDeployedWorkerName,\n resolveWorkerConfig,\n rewriteIntraStackServiceTargets,\n} from \"../../core/config/resolver.js\";\nimport { requiredSecretsForWorker } from \"../../core/secrets/declared.js\";\nimport { createDeploySecretsResources } from \"./secrets/context.js\";\nimport { pushSecretsForDeploy } from \"./secrets/push.js\";\nimport { workflowsApply } from \"../../features/workflows/workflows.apply.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\nimport { runSync } from \"./sync.js\";\nimport { workerRoutesApply } from \"../../features/worker-route/index.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\nimport { assertShardRegistryPresentForDeploy } from \"../../core/codegen/shardRegistry/index.js\";\nimport type { CfiConfig, WorkerConfig } from \"../../types.js\";\n\ntype WorkerEntry = [string, WorkerConfig];\n\n/**\n * Topologically sort workers by `services[].service` so that dependencies\n * deploy before dependents. Cloudflare rejects deploys that reference\n * service bindings to workers that don't yet exist on the account.\n * Cross-config dependencies (services not in this monorepo) are ignored.\n */\nexport function topoSortWorkersByServiceBindings(\n workers: WorkerEntry[],\n config: CfiConfig,\n naming: NamingEngine,\n env: string,\n): WorkerEntry[] {\n const intraMap = buildIntraStackScriptNameMap(config, env, naming);\n const scriptNameToKey = new Map<string, string>();\n for (const [key, cfg] of workers) {\n const name = resolveDeployedWorkerName(config, key, cfg, env, naming);\n scriptNameToKey.set(name, key);\n }\n\n const byKey = new Map(workers);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const out: WorkerEntry[] = [];\n\n function visit(key: string): void {\n if (visited.has(key)) return;\n if (visiting.has(key)) return;\n visiting.add(key);\n const cfg = byKey.get(key);\n if (cfg) {\n const merged = rewriteIntraStackServiceTargets(\n mergedWorkerConfigForEnv(cfg, env, config.tenant),\n intraMap,\n );\n const serviceDeps = merged.services?.map((s) => s.service) ?? [];\n const doDeps =\n merged.durable_objects?.bindings\n ?.map((b) => b.script_name)\n .filter((s): s is string => typeof s === \"string\" && s.length > 0)\n .map((s) => intraMap.get(s) ?? s)\n ?? [];\n const deps = [...serviceDeps, ...doDeps];\n for (const dep of deps) {\n const depKey = scriptNameToKey.get(dep);\n if (depKey && depKey !== key) visit(depKey);\n }\n visiting.delete(key);\n visited.add(key);\n out.push([key, cfg]);\n }\n }\n\n for (const [key] of workers) visit(key);\n return out;\n}\n\nexport async function runDeploy(options: {\n worker?: string;\n env?: string;\n configPath?: string;\n /** Passed to `wrangler deploy --dispatch-namespace` when the worker has no `dispatchNamespace` in config. */\n dispatchNamespace?: string;\n}): Promise<void> {\n const workerFilter = options.worker;\n // `--env` is intentionally required (no silent default to \"prod\") to\n // match every other Tamer command and to avoid the classic \"ran\n // `tamer deploy` from the wrong shell, shipped a half-tested branch\n // to production\" footgun.\n const env = options.env;\n if (!env) {\n throw new Error(\n \"deploy: --env is required (e.g. --env staging). \" +\n \"Tamer no longer defaults to prod — pass the env explicitly.\",\n );\n }\n const configPath = options.configPath;\n\n const config = await loadConfig(configPath, { env });\n const baseDir = getConfigBaseDir();\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n console.log(`Syncing state for env: ${env}...`);\n await runSync({ env, configPath });\n\n const naming = namingFromConfig(config);\n const api = new CFApiClient(accountId);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n const imports = await fetchStackImports(api, config, env);\n state.beginOperation(\"deploy\", workerFilter ? `worker:${workerFilter}` : undefined);\n\n try {\n\n const workers = await getWorkers(config, baseDir);\n const toDeploy = workerFilter\n ? workers.filter(([k]) => k === workerFilter)\n : workers;\n\n if (toDeploy.length === 0) {\n throw new Error(\n workerFilter\n ? `Worker \"${workerFilter}\" not found`\n : \"No workers configured\",\n );\n }\n\n const ordered = topoSortWorkersByServiceBindings(\n toDeploy,\n config,\n naming,\n env,\n );\n\n await assertShardRegistryPresentForDeploy({\n config,\n env,\n baseDir,\n accountId,\n naming,\n state,\n imports,\n workers,\n });\n\n let deploySecrets: Awaited<\n ReturnType<typeof createDeploySecretsResources>\n > | null = null;\n\n for (const [workerKey, workerConfig] of ordered) {\n const mergedForSecrets = mergedWorkerConfigForEnv(\n workerConfig,\n env,\n config.tenant,\n );\n const requiredSecrets = requiredSecretsForWorker(mergedForSecrets);\n\n if (requiredSecrets.length > 0 && env !== \"local\") {\n if (!deploySecrets) {\n deploySecrets = await createDeploySecretsResources(api, env);\n }\n const deployedName = resolveDeployedWorkerName(\n config,\n workerKey,\n workerConfig,\n env,\n naming,\n );\n await pushSecretsForDeploy({\n workerKey,\n deployedName,\n required: requiredSecrets,\n vault: deploySecrets.vault,\n state,\n api,\n masterKey: deploySecrets.masterKey,\n });\n }\n\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n const wranglerConfig = generateWranglerConfig(resolved, state, naming);\n writeWranglerJson(resolved.workerDir, wranglerConfig, resolved.wranglerOutFile);\n\n const buildConfig = mergedForSecrets.build;\n if (buildConfig) {\n console.log(`Building ${workerKey} (${buildConfig.command})...`);\n const buildEnv: Record<string, string> = {};\n if (wranglerConfig.vars) {\n for (const [k, v] of Object.entries(wranglerConfig.vars)) {\n buildEnv[k] = typeof v === \"string\" ? v : String(v);\n }\n }\n const buildResult = spawnBuildSync(buildConfig.command, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n env: buildEnv,\n });\n if (buildResult.status !== 0) {\n throw new Error(\n `build failed for ${workerKey} (exit ${buildResult.status})`,\n );\n }\n console.log(`Built ${workerKey}`);\n }\n\n const typesArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"types\",\n ];\n const typesResult = spawnWranglerSync(typesArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (typesResult.status !== 0) {\n throw new Error(`wrangler types failed for ${workerKey}`);\n }\n\n const dispatchNs =\n resolved.dispatchNamespace ?? options.dispatchNamespace;\n const deployArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"deploy\",\n ];\n if (dispatchNs) {\n deployArgs.push(\"--dispatch-namespace\", dispatchNs);\n }\n\n const deployResult = spawnWranglerSync(deployArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (deployResult.status !== 0) {\n throw new Error(`wrangler deploy failed for ${workerKey}`);\n }\n console.log(`Deployed ${workerKey}`);\n\n // Register workflows after the script exists (chicken-and-egg: workflows\n // need the deployed script). During `tamer apply`, workflow registration\n // is deferred when the script doesn't exist yet. Here the script is live.\n const workflowResources = resolved.resources?.workflows;\n if (workflowResources && workflowResources.length > 0) {\n await workflowsApply(\n workflowResources,\n config.tenant,\n env,\n api,\n state,\n naming,\n { workerKey, deployedName: resolved.workerName },\n );\n }\n }\n\n if (env !== \"local\") {\n try {\n await workerRoutesApply(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`worker routes apply failed after deploy: ${msg}`);\n }\n }\n\n state.finishOperation();\n await state.persist(api);\n console.log(`Deploy complete for env: ${env}`);\n } catch (err) {\n state.failOperation(err instanceof Error ? err.message : String(err));\n try {\n await state.persist(api);\n } catch {\n /* swallow secondary persist failure */\n }\n throw err;\n }\n}\n"],"mappings":"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"}
package/dist/tamer.mjs CHANGED
@@ -8856,7 +8856,7 @@ async function main() {
8856
8856
  break;
8857
8857
  case "deploy": {
8858
8858
  const d = parseDeployArgs(rest);
8859
- await import("./deploy-ByatGWlQ.mjs").then((m) => m.runDeploy({
8859
+ await import("./deploy-CiGgo_Om.mjs").then((m) => m.runDeploy({
8860
8860
  worker: d.worker,
8861
8861
  env: d.env,
8862
8862
  configPath: d.configPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dragonmastery/tamer",
3
- "version": "0.36.5",
3
+ "version": "0.36.6",
4
4
  "description": "Tamer: Cloudflare Workers infra CLI (sync, apply, deploy, migrate, destroy) and Wrangler-oriented TypeScript types.",
5
5
  "author": "DragonMastery",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy-ByatGWlQ.mjs","names":["out: WorkerEntry[]","deploySecrets: Awaited<\n ReturnType<typeof createDeploySecretsResources>\n > | null","buildEnv: Record<string, string>"],"sources":["../src/cli/commands/deploy.ts"],"sourcesContent":["import { loadConfig, getWorkers, getConfigBaseDir } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { wranglerConfigCliArgs } from \"../../core/wrangler/wranglerOutFile.js\";\nimport { spawnWranglerSync, spawnBuildSync } from \"../../core/wrangler/wranglerSpawn.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport {\n buildIntraStackScriptNameMap,\n mergedWorkerConfigForEnv,\n resolveDeployedWorkerName,\n resolveWorkerConfig,\n rewriteIntraStackServiceTargets,\n} from \"../../core/config/resolver.js\";\nimport { requiredSecretsForWorker } from \"../../core/secrets/declared.js\";\nimport { createDeploySecretsResources } from \"./secrets/context.js\";\nimport { pushSecretsForDeploy } from \"./secrets/push.js\";\nimport { workflowsApply } from \"../../features/workflows/workflows.apply.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\nimport { runSync } from \"./sync.js\";\nimport { workerRoutesApply } from \"../../features/worker-route/index.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\nimport { assertShardRegistryPresentForDeploy } from \"../../core/codegen/shardRegistry/index.js\";\nimport type { CfiConfig, WorkerConfig } from \"../../types.js\";\n\ntype WorkerEntry = [string, WorkerConfig];\n\n/**\n * Topologically sort workers by `services[].service` so that dependencies\n * deploy before dependents. Cloudflare rejects deploys that reference\n * service bindings to workers that don't yet exist on the account.\n * Cross-config dependencies (services not in this monorepo) are ignored.\n */\nexport function topoSortWorkersByServiceBindings(\n workers: WorkerEntry[],\n config: CfiConfig,\n naming: NamingEngine,\n env: string,\n): WorkerEntry[] {\n const intraMap = buildIntraStackScriptNameMap(config, env, naming);\n const scriptNameToKey = new Map<string, string>();\n for (const [key, cfg] of workers) {\n const name = resolveDeployedWorkerName(config, key, cfg, env, naming);\n scriptNameToKey.set(name, key);\n }\n\n const byKey = new Map(workers);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const out: WorkerEntry[] = [];\n\n function visit(key: string): void {\n if (visited.has(key)) return;\n if (visiting.has(key)) return;\n visiting.add(key);\n const cfg = byKey.get(key);\n if (cfg) {\n const merged = rewriteIntraStackServiceTargets(\n mergedWorkerConfigForEnv(cfg, env, config.tenant),\n intraMap,\n );\n const deps = merged.services?.map((s) => s.service) ?? [];\n for (const dep of deps) {\n const depKey = scriptNameToKey.get(dep);\n if (depKey && depKey !== key) visit(depKey);\n }\n visiting.delete(key);\n visited.add(key);\n out.push([key, cfg]);\n }\n }\n\n for (const [key] of workers) visit(key);\n return out;\n}\n\nexport async function runDeploy(options: {\n worker?: string;\n env?: string;\n configPath?: string;\n /** Passed to `wrangler deploy --dispatch-namespace` when the worker has no `dispatchNamespace` in config. */\n dispatchNamespace?: string;\n}): Promise<void> {\n const workerFilter = options.worker;\n // `--env` is intentionally required (no silent default to \"prod\") to\n // match every other Tamer command and to avoid the classic \"ran\n // `tamer deploy` from the wrong shell, shipped a half-tested branch\n // to production\" footgun.\n const env = options.env;\n if (!env) {\n throw new Error(\n \"deploy: --env is required (e.g. --env staging). \" +\n \"Tamer no longer defaults to prod — pass the env explicitly.\",\n );\n }\n const configPath = options.configPath;\n\n const config = await loadConfig(configPath, { env });\n const baseDir = getConfigBaseDir();\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n console.log(`Syncing state for env: ${env}...`);\n await runSync({ env, configPath });\n\n const naming = namingFromConfig(config);\n const api = new CFApiClient(accountId);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n const imports = await fetchStackImports(api, config, env);\n state.beginOperation(\"deploy\", workerFilter ? `worker:${workerFilter}` : undefined);\n\n try {\n\n const workers = await getWorkers(config, baseDir);\n const toDeploy = workerFilter\n ? workers.filter(([k]) => k === workerFilter)\n : workers;\n\n if (toDeploy.length === 0) {\n throw new Error(\n workerFilter\n ? `Worker \"${workerFilter}\" not found`\n : \"No workers configured\",\n );\n }\n\n const ordered = topoSortWorkersByServiceBindings(\n toDeploy,\n config,\n naming,\n env,\n );\n\n await assertShardRegistryPresentForDeploy({\n config,\n env,\n baseDir,\n accountId,\n naming,\n state,\n imports,\n workers,\n });\n\n let deploySecrets: Awaited<\n ReturnType<typeof createDeploySecretsResources>\n > | null = null;\n\n for (const [workerKey, workerConfig] of ordered) {\n const mergedForSecrets = mergedWorkerConfigForEnv(\n workerConfig,\n env,\n config.tenant,\n );\n const requiredSecrets = requiredSecretsForWorker(mergedForSecrets);\n\n if (requiredSecrets.length > 0 && env !== \"local\") {\n if (!deploySecrets) {\n deploySecrets = await createDeploySecretsResources(api, env);\n }\n const deployedName = resolveDeployedWorkerName(\n config,\n workerKey,\n workerConfig,\n env,\n naming,\n );\n await pushSecretsForDeploy({\n workerKey,\n deployedName,\n required: requiredSecrets,\n vault: deploySecrets.vault,\n state,\n api,\n masterKey: deploySecrets.masterKey,\n });\n }\n\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n const wranglerConfig = generateWranglerConfig(resolved, state, naming);\n writeWranglerJson(resolved.workerDir, wranglerConfig, resolved.wranglerOutFile);\n\n const buildConfig = mergedForSecrets.build;\n if (buildConfig) {\n console.log(`Building ${workerKey} (${buildConfig.command})...`);\n const buildEnv: Record<string, string> = {};\n if (wranglerConfig.vars) {\n for (const [k, v] of Object.entries(wranglerConfig.vars)) {\n buildEnv[k] = typeof v === \"string\" ? v : String(v);\n }\n }\n const buildResult = spawnBuildSync(buildConfig.command, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n env: buildEnv,\n });\n if (buildResult.status !== 0) {\n throw new Error(\n `build failed for ${workerKey} (exit ${buildResult.status})`,\n );\n }\n console.log(`Built ${workerKey}`);\n }\n\n const typesArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"types\",\n ];\n const typesResult = spawnWranglerSync(typesArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (typesResult.status !== 0) {\n throw new Error(`wrangler types failed for ${workerKey}`);\n }\n\n const dispatchNs =\n resolved.dispatchNamespace ?? options.dispatchNamespace;\n const deployArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"deploy\",\n ];\n if (dispatchNs) {\n deployArgs.push(\"--dispatch-namespace\", dispatchNs);\n }\n\n const deployResult = spawnWranglerSync(deployArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (deployResult.status !== 0) {\n throw new Error(`wrangler deploy failed for ${workerKey}`);\n }\n console.log(`Deployed ${workerKey}`);\n\n // Register workflows after the script exists (chicken-and-egg: workflows\n // need the deployed script). During `tamer apply`, workflow registration\n // is deferred when the script doesn't exist yet. Here the script is live.\n const workflowResources = resolved.resources?.workflows;\n if (workflowResources && workflowResources.length > 0) {\n await workflowsApply(\n workflowResources,\n config.tenant,\n env,\n api,\n state,\n naming,\n { workerKey, deployedName: resolved.workerName },\n );\n }\n }\n\n if (env !== \"local\") {\n try {\n await workerRoutesApply(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`worker routes apply failed after deploy: ${msg}`);\n }\n }\n\n state.finishOperation();\n await state.persist(api);\n console.log(`Deploy complete for env: ${env}`);\n } catch (err) {\n state.failOperation(err instanceof Error ? err.message : String(err));\n try {\n await state.persist(api);\n } catch {\n /* swallow secondary persist failure */\n }\n throw err;\n }\n}\n"],"mappings":"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"}