@smoothbricks/cli 0.10.9 → 0.10.10

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.
Files changed (39) hide show
  1. package/dist/cli.js +6 -5
  2. package/dist/github-ci/index.d.ts +8 -6
  3. package/dist/github-ci/index.d.ts.map +1 -1
  4. package/dist/github-ci/index.js +35 -35
  5. package/dist/monorepo/ci-workflow.d.ts +3 -0
  6. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  7. package/dist/monorepo/ci-workflow.js +59 -15
  8. package/dist/monorepo/managed-files.d.ts +1 -0
  9. package/dist/monorepo/managed-files.d.ts.map +1 -1
  10. package/dist/monorepo/managed-files.js +15 -5
  11. package/dist/monorepo/publish-workflow.d.ts +2 -2
  12. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  13. package/dist/monorepo/publish-workflow.js +6 -6
  14. package/dist/wrangler/cloudflare.d.ts +1 -1
  15. package/dist/wrangler/cloudflare.d.ts.map +1 -1
  16. package/dist/wrangler/{deploy-environment.d.ts → deploy-stage.d.ts} +6 -6
  17. package/dist/wrangler/deploy-stage.d.ts.map +1 -0
  18. package/dist/wrangler/{deploy-environment.js → deploy-stage.js} +26 -26
  19. package/dist/wrangler/stage.d.ts +58 -0
  20. package/dist/wrangler/stage.d.ts.map +1 -0
  21. package/dist/wrangler/{environment.js → stage.js} +44 -44
  22. package/package.json +7 -7
  23. package/src/cli.ts +9 -7
  24. package/src/github-ci/index.test.ts +101 -32
  25. package/src/github-ci/index.ts +51 -45
  26. package/src/monorepo/__tests__/ci-workflow.test.ts +87 -49
  27. package/src/monorepo/__tests__/publish-workflow.test.ts +8 -8
  28. package/src/monorepo/ci-workflow.ts +67 -14
  29. package/src/monorepo/managed-files.test.ts +26 -5
  30. package/src/monorepo/managed-files.ts +18 -5
  31. package/src/monorepo/publish-workflow.ts +9 -9
  32. package/src/wrangler/cloudflare.ts +1 -1
  33. package/src/wrangler/{deploy-environment.test.ts → deploy-stage.test.ts} +11 -11
  34. package/src/wrangler/{deploy-environment.ts → deploy-stage.ts} +41 -41
  35. package/src/wrangler/{environment.test.ts → stage.test.ts} +15 -15
  36. package/src/wrangler/{environment.ts → stage.ts} +49 -52
  37. package/dist/wrangler/deploy-environment.d.ts.map +0 -1
  38. package/dist/wrangler/environment.d.ts +0 -58
  39. package/dist/wrangler/environment.d.ts.map +0 -1
@@ -4,19 +4,19 @@ import { readFile, rm, writeFile } from 'node:fs/promises';
4
4
  import { join } from 'node:path';
5
5
  import typia from 'typia';
6
6
  import { type CloudflareClient, CloudflareRestClient } from './cloudflare.js';
7
+ import { parseDevVarsExample } from './prepare-env.js';
7
8
  import {
8
- type ConfiguredEnvironmentResourcePlan,
9
+ type ConfiguredStageResourcePlan,
10
+ type DeploymentStage,
9
11
  derivePullRequestWranglerConfig,
10
- type EnvironmentToken,
11
- environmentResourceName,
12
- hasExactEnvironmentSegment,
13
- isPullRequestEnvironment,
14
- parseEnvironmentToken,
15
- planConfiguredEnvironmentResources,
12
+ hasExactStageSegment,
13
+ isPullRequestStage,
14
+ parseDeploymentStage,
15
+ planConfiguredStageResources,
16
16
  planPullRequestResources,
17
- pullRequestEnvironment,
18
- } from './environment.js';
19
- import { parseDevVarsExample } from './prepare-env.js';
17
+ pullRequestStage,
18
+ stageResourceName,
19
+ } from './stage.js';
20
20
 
21
21
  export interface ProcessResult {
22
22
  exitCode: number;
@@ -56,8 +56,8 @@ export interface WranglerCommandDependencies {
56
56
  processEnv?: NodeJS.ProcessEnv;
57
57
  }
58
58
 
59
- export interface DeployEnvironmentResult {
60
- environment: EnvironmentToken;
59
+ export interface DeployStageResult {
60
+ stage: DeploymentStage;
61
61
  workerName: string;
62
62
  action: 'deployed' | 'activated' | 'remote-cache-hit';
63
63
  versionTag?: string;
@@ -65,12 +65,12 @@ export interface DeployEnvironmentResult {
65
65
 
66
66
  const isUnknownRecord = typia.createIs<Record<string, unknown>>();
67
67
 
68
- export async function deployEnvironment(
68
+ export async function deployStage(
69
69
  cwd: string,
70
- environmentValue: string,
70
+ stageValue: string,
71
71
  dependencies: WranglerCommandDependencies = {},
72
- ): Promise<DeployEnvironmentResult> {
73
- const environment = parseEnvironmentToken(environmentValue);
72
+ ): Promise<DeployStageResult> {
73
+ const stage = parseDeploymentStage(stageValue);
74
74
  const processEnv = dependencies.processEnv ?? process.env;
75
75
  const accountId = processEnv.CLOUDFLARE_ACCOUNT_ID;
76
76
  const apiToken = processEnv.CLOUDFLARE_API_TOKEN;
@@ -92,12 +92,12 @@ export async function deployEnvironment(
92
92
  let temporaryConfigPath: string | undefined;
93
93
  let temporarySecretsPath: string | undefined;
94
94
  try {
95
- if (isPullRequestEnvironment(environment)) {
96
- const staging = planConfiguredEnvironmentResources(committedToml, 'staging');
95
+ if (isPullRequestStage(stage)) {
96
+ const staging = planConfiguredStageResources(committedToml, 'staging');
97
97
  if (!staging.workerName.endsWith('-staging')) {
98
98
  throw new Error('[env.staging].name must end with the exact suffix -staging.');
99
99
  }
100
- const workerName = environmentResourceName(staging.workerName.slice(0, -'-staging'.length), environment);
100
+ const workerName = stageResourceName(staging.workerName.slice(0, -'-staging'.length), stage);
101
101
  const firstDeployment = !(await cloudflare.listWorkerScripts()).some((script) => script.id === workerName);
102
102
  if (firstDeployment && missingSecrets.length > 0) {
103
103
  throw new Error(
@@ -105,7 +105,7 @@ export async function deployEnvironment(
105
105
  );
106
106
  }
107
107
  const liveNamespaces = await cloudflare.listKvNamespaces();
108
- const plan = planPullRequestResources(committedToml, environment, liveNamespaces);
108
+ const plan = planPullRequestResources(committedToml, stage, liveNamespaces);
109
109
  const derivedIds = new Map<string, string>();
110
110
  const byTitle = new Map(liveNamespaces.map((namespace) => [namespace.title, namespace]));
111
111
  for (const namespace of plan.kvNamespaces) {
@@ -122,7 +122,7 @@ export async function deployEnvironment(
122
122
  derivedIds.set(namespace.stagingId, live.id);
123
123
  }
124
124
  const derivedToml = derivePullRequestWranglerConfig(committedToml, {
125
- environment,
125
+ stage: stage,
126
126
  accountId,
127
127
  kvNamespaceIds: derivedIds,
128
128
  });
@@ -132,10 +132,10 @@ export async function deployEnvironment(
132
132
  }
133
133
 
134
134
  const toml = configPath === committedConfigPath ? committedToml : await readFile(configPath, 'utf8');
135
- const plan = planConfiguredEnvironmentResources(toml, environment);
136
- const workerExists = await reconcileEnvironmentResources(plan, cloudflare);
135
+ const plan = planConfiguredStageResources(toml, stage);
136
+ const workerExists = await reconcileStageResources(plan, cloudflare);
137
137
  const versionTag = nxTaskVersionTag(processEnv);
138
- const commandContext = { cwd, configPath, environment, workerName: plan.workerName };
138
+ const commandContext = { cwd, configPath, stage, workerName: plan.workerName };
139
139
 
140
140
  if (versionTag && workerExists) {
141
141
  const versions = await wranglerJson(runner, ['versions', 'list', '--name', plan.workerName, '--json'], cwd);
@@ -146,7 +146,7 @@ export async function deployEnvironment(
146
146
  );
147
147
  const versionId = findVersionIdByTag(versions, versionTag);
148
148
  if (versionId && isFullCurrentDeployment(deployments, versionId)) {
149
- return { environment, workerName: plan.workerName, action: 'remote-cache-hit', versionTag };
149
+ return { stage, workerName: plan.workerName, action: 'remote-cache-hit', versionTag };
150
150
  }
151
151
  if (versionId) {
152
152
  await wrangler(
@@ -161,16 +161,16 @@ export async function deployEnvironment(
161
161
  '--config',
162
162
  configPath,
163
163
  '--env',
164
- environment,
164
+ stage,
165
165
  '--yes',
166
166
  ],
167
167
  cwd,
168
168
  );
169
- return { environment, workerName: plan.workerName, action: 'activated', versionTag };
169
+ return { stage, workerName: plan.workerName, action: 'activated', versionTag };
170
170
  }
171
171
  }
172
172
 
173
- const deployArgs = ['deploy', '--config', commandContext.configPath, '--env', commandContext.environment];
173
+ const deployArgs = ['deploy', '--config', commandContext.configPath, '--env', commandContext.stage];
174
174
  if (versionTag) deployArgs.push('--tag', versionTag);
175
175
  if (Object.keys(secretValues).length > 0) {
176
176
  temporarySecretsPath = join(cwd, `.wrangler-secrets.smoo-${process.pid}-${randomUUID()}.json`);
@@ -179,7 +179,7 @@ export async function deployEnvironment(
179
179
  }
180
180
  await wrangler(runner, deployArgs, cwd);
181
181
  return {
182
- environment,
182
+ stage,
183
183
  workerName: commandContext.workerName,
184
184
  action: 'deployed',
185
185
  ...(versionTag ? { versionTag } : {}),
@@ -194,7 +194,7 @@ export async function deployEnvironment(
194
194
  }
195
195
  }
196
196
  export interface CleanupResult {
197
- environment: `pr${number}`;
197
+ stage: `pr${number}`;
198
198
  deleted: {
199
199
  workers: number;
200
200
  routes: number;
@@ -211,7 +211,7 @@ export async function cleanupPullRequest(
211
211
  prNumber: number,
212
212
  dependencies: WranglerCommandDependencies = {},
213
213
  ): Promise<CleanupResult> {
214
- const environment = pullRequestEnvironment(prNumber);
214
+ const stage = pullRequestStage(prNumber);
215
215
  const processEnv = dependencies.processEnv ?? process.env;
216
216
  const cloudflare =
217
217
  dependencies.cloudflare ??
@@ -231,36 +231,36 @@ export async function cleanupPullRequest(
231
231
  };
232
232
 
233
233
  for (const domain of await cloudflare.listWorkerDomains()) {
234
- if (!hasExactEnvironmentSegment(domain.hostname, environment)) continue;
234
+ if (!hasExactStageSegment(domain.hostname, stage)) continue;
235
235
  await cloudflare.deleteWorkerDomain(domain.id);
236
236
  deleted.domains += 1;
237
237
  }
238
238
 
239
239
  for (const zone of await cloudflare.listZones()) {
240
240
  for (const route of await cloudflare.listWorkerRoutes(zone.id)) {
241
- if (!hasExactEnvironmentSegment(route.pattern, environment)) continue;
241
+ if (!hasExactStageSegment(route.pattern, stage)) continue;
242
242
  await cloudflare.deleteWorkerRoute(zone.id, route.id);
243
243
  deleted.routes += 1;
244
244
  }
245
245
  for (const record of await cloudflare.listDnsRecords(zone.id)) {
246
- if (!hasExactEnvironmentSegment(record.name, environment)) continue;
246
+ if (!hasExactStageSegment(record.name, stage)) continue;
247
247
  await cloudflare.deleteDnsRecord(zone.id, record.id);
248
248
  deleted.dnsRecords += 1;
249
249
  }
250
250
  }
251
251
 
252
252
  for (const script of await cloudflare.listWorkerScripts()) {
253
- if (!hasExactEnvironmentSegment(script.id, environment)) continue;
253
+ if (!hasExactStageSegment(script.id, stage)) continue;
254
254
  await cloudflare.deleteWorkerScript(script.id);
255
255
  deleted.workers += 1;
256
256
  }
257
257
  for (const namespace of await cloudflare.listKvNamespaces()) {
258
- if (!hasExactEnvironmentSegment(namespace.title, environment)) continue;
258
+ if (!hasExactStageSegment(namespace.title, stage)) continue;
259
259
  await cloudflare.deleteKvNamespace(namespace.id);
260
260
  deleted.kvNamespaces += 1;
261
261
  }
262
262
  for (const bucket of await cloudflare.listR2Buckets()) {
263
- if (!hasExactEnvironmentSegment(bucket.name, environment)) continue;
263
+ if (!hasExactStageSegment(bucket.name, stage)) continue;
264
264
  for (const key of await cloudflare.listR2Objects(bucket.name)) {
265
265
  await cloudflare.deleteR2Object(bucket.name, key);
266
266
  deleted.r2Objects += 1;
@@ -268,11 +268,11 @@ export async function cleanupPullRequest(
268
268
  await cloudflare.deleteR2Bucket(bucket.name);
269
269
  deleted.r2Buckets += 1;
270
270
  }
271
- return { environment, deleted };
271
+ return { stage, deleted };
272
272
  }
273
273
 
274
- async function reconcileEnvironmentResources(
275
- plan: ConfiguredEnvironmentResourcePlan,
274
+ async function reconcileStageResources(
275
+ plan: ConfiguredStageResourcePlan,
276
276
  cloudflare: CloudflareClient,
277
277
  ): Promise<boolean> {
278
278
  const namespaces = await cloudflare.listKvNamespaces();
@@ -364,7 +364,7 @@ export function nxTaskVersionTag(environment: NodeJS.ProcessEnv): string | undef
364
364
  environment.NX_TASK_TARGET_PROJECT !== undefined ||
365
365
  environment.NX_TASK_TARGET_TARGET !== undefined;
366
366
  if (!underNx) return undefined;
367
- if (!hash) throw new Error('NX_TASK_HASH is required when deploy-environment runs under Nx.');
367
+ if (!hash) throw new Error('NX_TASK_HASH is required when deploy-stage runs under Nx.');
368
368
  if (/^(?:0|[1-9][0-9]*)$/.test(hash)) {
369
369
  return `nx-${hash}`;
370
370
  }
@@ -1,12 +1,12 @@
1
1
  import { describe, expect, it } from 'bun:test';
2
2
  import {
3
3
  derivePullRequestWranglerConfig,
4
- environmentDomain,
5
- environmentResourceName,
6
4
  planPullRequestResources,
7
- pullRequestEnvironment,
5
+ pullRequestStage,
8
6
  rateLimitNamespaceId,
9
- } from './environment.js';
7
+ stageDomain,
8
+ stageResourceName,
9
+ } from './stage.js';
10
10
 
11
11
  const APP_FIXTURE = `name = "conloca-app"
12
12
  compatibility_date = "2026-05-06"
@@ -103,21 +103,21 @@ const DERIVED_IDS = new Map([
103
103
  ['kv-mail-staging-id', 'kv-mail-pr123-id'],
104
104
  ]);
105
105
 
106
- describe('Wrangler environment convention', () => {
106
+ describe('Wrangler deployment stage convention', () => {
107
107
  it('validates pull-request numbers and derives generic names', () => {
108
- expect(pullRequestEnvironment(123)).toBe('pr123');
109
- expect(() => pullRequestEnvironment(0)).toThrow(/1 through 999999999/);
110
- expect(() => pullRequestEnvironment(1.5)).toThrow(/integer/);
111
- expect(() => pullRequestEnvironment(1_000_000_000)).toThrow(/1 through 999999999/);
112
- expect(environmentDomain('pr123', 'conloca.com')).toBe('pr123.conloca.com');
113
- expect(environmentDomain('production', 'conloca.com')).toBe('conloca.com');
114
- expect(environmentResourceName('conloca-app', 'staging')).toBe('conloca-app-staging');
115
- expect(environmentResourceName('conloca-app', 'production')).toBe('conloca-app');
108
+ expect(pullRequestStage(123)).toBe('pr123');
109
+ expect(() => pullRequestStage(0)).toThrow(/1 through 999999999/);
110
+ expect(() => pullRequestStage(1.5)).toThrow(/integer/);
111
+ expect(() => pullRequestStage(1_000_000_000)).toThrow(/1 through 999999999/);
112
+ expect(stageDomain('pr123', 'conloca.com')).toBe('pr123.conloca.com');
113
+ expect(stageDomain('production', 'conloca.com')).toBe('conloca.com');
114
+ expect(stageResourceName('conloca-app', 'staging')).toBe('conloca-app-staging');
115
+ expect(stageResourceName('conloca-app', 'production')).toBe('conloca-app');
116
116
  });
117
117
 
118
118
  it('derives the app staging block without changing inherited/static semantics', () => {
119
119
  const derived = derivePullRequestWranglerConfig(APP_FIXTURE, {
120
- environment: 'pr123',
120
+ stage: 'pr123',
121
121
  accountId: 'account-1',
122
122
  kvNamespaceIds: new Map<string, string>(),
123
123
  });
@@ -141,7 +141,7 @@ describe('Wrangler environment convention', () => {
141
141
  expect(plan.r2Buckets).toEqual([{ binding: 'MEDIA', bucketName: 'conloca-media-pr123' }]);
142
142
 
143
143
  const derived = derivePullRequestWranglerConfig(BACKEND_FIXTURE, {
144
- environment: 'pr123',
144
+ stage: 'pr123',
145
145
  accountId: 'account-1',
146
146
  kvNamespaceIds: DERIVED_IDS,
147
147
  });
@@ -3,50 +3,50 @@ import { getStaticTOMLValue, parseTOML } from 'toml-eslint-parser';
3
3
  import typia from 'typia';
4
4
  import { cloneEnvBlock } from './prepare-env.js';
5
5
 
6
- export type EnvironmentToken = 'staging' | 'production' | `pr${number}`;
6
+ export type DeploymentStage = 'staging' | 'production' | `pr${number}`;
7
7
 
8
8
  const MAX_PULL_REQUEST_NUMBER = 999_999_999;
9
- const ENVIRONMENT_PATTERN = /^(?:staging|production|pr[1-9][0-9]{0,8})$/;
9
+ const STAGE_PATTERN = /^(?:staging|production|pr[1-9][0-9]{0,8})$/;
10
10
 
11
- export function pullRequestEnvironment(prNumber: number): `pr${number}` {
11
+ export function pullRequestStage(prNumber: number): `pr${number}` {
12
12
  if (!Number.isInteger(prNumber) || prNumber < 1 || prNumber > MAX_PULL_REQUEST_NUMBER) {
13
13
  throw new Error(`Pull request number must be an integer from 1 through ${MAX_PULL_REQUEST_NUMBER}.`);
14
14
  }
15
15
  return `pr${prNumber}`;
16
16
  }
17
17
 
18
- export function parseEnvironmentToken(value: string): EnvironmentToken {
19
- if (!ENVIRONMENT_PATTERN.test(value)) {
18
+ export function parseDeploymentStage(value: string): DeploymentStage {
19
+ if (!STAGE_PATTERN.test(value)) {
20
20
  throw new Error(
21
- 'Environment must be exactly staging, production, or pr followed by an integer from 1 through 999999999.',
21
+ 'Deployment stage must be exactly staging, production, or pr followed by an integer from 1 through 999999999.',
22
22
  );
23
23
  }
24
24
  if (value === 'staging' || value === 'production') return value;
25
- return pullRequestEnvironment(Number(value.slice(2)));
25
+ return pullRequestStage(Number(value.slice(2)));
26
26
  }
27
27
 
28
- export function isPullRequestEnvironment(environment: EnvironmentToken): environment is `pr${number}` {
29
- return environment.startsWith('pr');
28
+ export function isPullRequestStage(stage: DeploymentStage): stage is `pr${number}` {
29
+ return stage.startsWith('pr');
30
30
  }
31
31
 
32
- export function environmentDomain(environment: string, zone: string): string {
33
- const token = parseEnvironmentToken(environment);
32
+ export function stageDomain(stage: string, zone: string): string {
33
+ const token = parseDeploymentStage(stage);
34
34
  if (!zone || zone.startsWith('.') || zone.endsWith('.')) {
35
35
  throw new Error('Zone must be a non-empty DNS name without leading or trailing dots.');
36
36
  }
37
37
  return token === 'production' ? zone : `${token}.${zone}`;
38
38
  }
39
39
 
40
- export function environmentResourceName(base: string, environment: string): string {
41
- const token = parseEnvironmentToken(environment);
40
+ export function stageResourceName(base: string, stage: string): string {
41
+ const token = parseDeploymentStage(stage);
42
42
  if (!base) {
43
43
  throw new Error('Resource base name must not be empty.');
44
44
  }
45
45
  return token === 'production' ? base : `${base}-${token}`;
46
46
  }
47
47
 
48
- export function hasExactEnvironmentSegment(value: string, environment: `pr${number}`): boolean {
49
- const escaped = environment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
48
+ export function hasExactStageSegment(value: string, stage: `pr${number}`): boolean {
49
+ const escaped = stage.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
50
50
  return new RegExp(`(?:^|[-.])${escaped}(?=$|[-.])`).test(value);
51
51
  }
52
52
 
@@ -90,32 +90,29 @@ export interface PullRequestKvResource {
90
90
  }
91
91
 
92
92
  export interface PullRequestResourcePlan {
93
- environment: `pr${number}`;
93
+ stage: `pr${number}`;
94
94
  workerName: string;
95
95
  workerBaseName: string;
96
96
  kvNamespaces: PullRequestKvResource[];
97
97
  r2Buckets: R2Binding[];
98
98
  routes: Array<{ pattern: string; zoneName?: string; customDomain: boolean }>;
99
99
  }
100
- export interface ConfiguredEnvironmentResourcePlan {
101
- environment: EnvironmentToken;
100
+ export interface ConfiguredStageResourcePlan {
101
+ stage: DeploymentStage;
102
102
  workerName: string;
103
103
  kvNamespaces: KvBinding[];
104
104
  r2Buckets: R2Binding[];
105
105
  routes: Array<{ pattern: string; zoneName?: string; customDomain: boolean }>;
106
106
  }
107
107
 
108
- export function planConfiguredEnvironmentResources(
109
- toml: string,
110
- environment: EnvironmentToken,
111
- ): ConfiguredEnvironmentResourcePlan {
112
- const block = parseRoot(toml).env?.[environment];
108
+ export function planConfiguredStageResources(toml: string, stage: DeploymentStage): ConfiguredStageResourcePlan {
109
+ const block = parseRoot(toml).env?.[stage];
113
110
  if (!isWranglerEnvironment(block)) {
114
- throw new Error(`Wrangler configuration must declare [env.${environment}].`);
111
+ throw new Error(`Wrangler configuration must declare [env.${stage}].`);
115
112
  }
116
- const workerName = requiredString(block, 'name', `[env.${environment}]`);
113
+ const workerName = requiredString(block, 'name', `[env.${stage}]`);
117
114
  return {
118
- environment,
115
+ stage,
119
116
  workerName,
120
117
  kvNamespaces: readKvBindings(block.kv_namespaces),
121
118
  r2Buckets: readRows(block.r2_buckets).map((row) => {
@@ -155,10 +152,10 @@ function stagingWorkerName(staging: WranglerEnvironment): { workerName: string;
155
152
 
156
153
  export function planPullRequestResources(
157
154
  toml: string,
158
- environment: `pr${number}`,
155
+ stage: `pr${number}`,
159
156
  liveNamespaces: LiveKvNamespace[],
160
157
  ): PullRequestResourcePlan {
161
- parseEnvironmentToken(environment);
158
+ parseDeploymentStage(stage);
162
159
  const staging = stagingEnvironment(toml);
163
160
  const { workerBaseName } = stagingWorkerName(staging);
164
161
  const namespaceById = new Map(liveNamespaces.map((namespace) => [namespace.id, namespace]));
@@ -169,7 +166,7 @@ export function planPullRequestResources(
169
166
  `Staging KV binding ${binding} references namespace ${id}, which is absent from the account listing.`,
170
167
  );
171
168
  }
172
- const title = replaceExactToken(stagingNamespace.title, 'staging', environment);
169
+ const title = replaceExactToken(stagingNamespace.title, 'staging', stage);
173
170
  if (title === stagingNamespace.title) {
174
171
  throw new Error(`Staging KV namespace title ${stagingNamespace.title} has no exact staging segment.`);
175
172
  }
@@ -178,20 +175,20 @@ export function planPullRequestResources(
178
175
  const r2Buckets = readRows(staging.r2_buckets).map((row) => {
179
176
  const binding = requiredString(row, 'binding', 'R2 binding');
180
177
  const stagingBucket = requiredString(row, 'bucket_name', `R2 binding ${binding}`);
181
- const bucketName = replaceExactToken(stagingBucket, 'staging', environment);
178
+ const bucketName = replaceExactToken(stagingBucket, 'staging', stage);
182
179
  if (bucketName === stagingBucket) {
183
180
  throw new Error(`Staging R2 bucket ${stagingBucket} has no exact staging segment.`);
184
181
  }
185
182
  return { binding, bucketName };
186
183
  });
187
184
  const routes = readRows(staging.routes).map((row) => ({
188
- pattern: replaceHostnameLabel(requiredString(row, 'pattern', 'route'), environment),
185
+ pattern: replaceHostnameLabel(requiredString(row, 'pattern', 'route'), stage),
189
186
  ...(typeof row.zone_name === 'string' ? { zoneName: row.zone_name } : {}),
190
187
  customDomain: row.custom_domain === true,
191
188
  }));
192
189
  return {
193
- environment,
194
- workerName: environmentResourceName(workerBaseName, environment),
190
+ stage,
191
+ workerName: stageResourceName(workerBaseName, stage),
195
192
  workerBaseName,
196
193
  kvNamespaces,
197
194
  r2Buckets,
@@ -200,20 +197,20 @@ export function planPullRequestResources(
200
197
  }
201
198
 
202
199
  export interface DerivePullRequestConfigOptions {
203
- environment: `pr${number}`;
200
+ stage: `pr${number}`;
204
201
  accountId: string;
205
202
  kvNamespaceIds: ReadonlyMap<string, string>;
206
203
  }
207
204
 
208
205
  export function derivePullRequestWranglerConfig(toml: string, options: DerivePullRequestConfigOptions): string {
209
- const environment = options.environment;
210
- parseEnvironmentToken(environment);
206
+ const stage = options.stage;
207
+ parseDeploymentStage(stage);
211
208
  if (!options.accountId) {
212
209
  throw new Error('Cloudflare account id is required to derive rate-limit namespaces.');
213
210
  }
214
211
  const staging = stagingEnvironment(toml);
215
212
  const { workerBaseName } = stagingWorkerName(staging);
216
- const cloned = cloneEnvBlock(toml, 'staging', environment);
213
+ const cloned = cloneEnvBlock(toml, 'staging', stage);
217
214
  const program = parseTOML(cloned);
218
215
  const rootValue: unknown = getStaticTOMLValue(program);
219
216
  if (!isWranglerRoot(rootValue)) {
@@ -223,7 +220,7 @@ export function derivePullRequestWranglerConfig(toml: string, options: DerivePul
223
220
  const edits: Array<{ start: number; end: number; value: string }> = [];
224
221
 
225
222
  for (const table of program.body[0].body) {
226
- if (table.type !== 'TOMLTable' || table.resolvedKey[0] !== 'env' || table.resolvedKey[1] !== environment) {
223
+ if (table.type !== 'TOMLTable' || table.resolvedKey[0] !== 'env' || table.resolvedKey[1] !== stage) {
227
224
  continue;
228
225
  }
229
226
  const tableValue = valueAtPath(root, table.resolvedKey);
@@ -238,7 +235,7 @@ export function derivePullRequestWranglerConfig(toml: string, options: DerivePul
238
235
  tableValue,
239
236
  key,
240
237
  current,
241
- environment,
238
+ stage,
242
239
  workerBaseName,
243
240
  options.accountId,
244
241
  options.kvNamespaceIds,
@@ -262,29 +259,29 @@ function deriveFieldValue(
262
259
  table: Record<string, unknown>,
263
260
  key: string,
264
261
  current: unknown,
265
- environment: `pr${number}`,
262
+ stage: `pr${number}`,
266
263
  workerBaseName: string,
267
264
  accountId: string,
268
265
  kvNamespaceIds: ReadonlyMap<string, string>,
269
266
  ): unknown {
270
267
  const section = path[0];
271
268
  if (path.length === 0 && key === 'name') {
272
- return environmentResourceName(workerBaseName, environment);
269
+ return stageResourceName(workerBaseName, stage);
273
270
  }
274
271
  if (section === 'routes' && key === 'pattern' && typeof current === 'string') {
275
- return replaceHostnameLabel(current, environment);
272
+ return replaceHostnameLabel(current, stage);
276
273
  }
277
274
  if (section === 'vars' && typeof current === 'string') {
278
275
  if (key === 'ENVIRONMENT') {
279
- return environment;
276
+ return stage;
280
277
  }
281
278
  if (key === 'AUTH_KEYS_INSTANCE_NAME') {
282
- return replaceExactToken(current, 'staging', environment);
279
+ return replaceExactToken(current, 'staging', stage);
283
280
  }
284
- return replaceHostnameLabel(current, environment);
281
+ return replaceHostnameLabel(current, stage);
285
282
  }
286
283
  if (section === 'send_email' && key === 'allowed_sender_addresses' && Array.isArray(current)) {
287
- return current.map((value) => (typeof value === 'string' ? replaceHostnameLabel(value, environment) : value));
284
+ return current.map((value) => (typeof value === 'string' ? replaceHostnameLabel(value, stage) : value));
288
285
  }
289
286
  if (section === 'kv_namespaces' && key === 'id' && typeof current === 'string') {
290
287
  const derived = kvNamespaceIds.get(current);
@@ -294,11 +291,11 @@ function deriveFieldValue(
294
291
  return derived;
295
292
  }
296
293
  if (section === 'r2_buckets' && key === 'bucket_name' && typeof current === 'string') {
297
- return replaceExactToken(current, 'staging', environment);
294
+ return replaceExactToken(current, 'staging', stage);
298
295
  }
299
296
  if (section === 'ratelimits' && key === 'namespace_id') {
300
297
  const bindingName = requiredString(table, 'name', 'Rate-limit binding');
301
- return rateLimitNamespaceId(accountId, workerBaseName, environment, bindingName);
298
+ return rateLimitNamespaceId(accountId, workerBaseName, stage, bindingName);
302
299
  }
303
300
  return current;
304
301
  }
@@ -306,17 +303,17 @@ function deriveFieldValue(
306
303
  export function rateLimitNamespaceId(
307
304
  accountId: string,
308
305
  workerBaseName: string,
309
- environment: string,
306
+ stage: string,
310
307
  bindingName: string,
311
308
  ): string {
312
- const token = parseEnvironmentToken(environment);
309
+ const token = parseDeploymentStage(stage);
313
310
  const digest = createHash('sha256').update(`${accountId}:${workerBaseName}:${token}:${bindingName}`).digest();
314
311
  const value = digest.readUInt32BE(0) & 0x7fff_ffff;
315
312
  return String(value === 0 ? 1 : value);
316
313
  }
317
314
 
318
- function replaceHostnameLabel(value: string, environment: `pr${number}`): string {
319
- return value.replace(/(^|[.@/])staging(?=\.)/g, `$1${environment}`);
315
+ function replaceHostnameLabel(value: string, stage: `pr${number}`): string {
316
+ return value.replace(/(^|[.@/])staging(?=\.)/g, `$1${stage}`);
320
317
  }
321
318
 
322
319
  function replaceExactToken(value: string, from: string, to: string): string {
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy-environment.d.ts","sourceRoot":"","sources":["../../src/wrangler/deploy-environment.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,gBAAgB,EAAwB,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAGL,KAAK,gBAAgB,EAQtB,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACtH;AAED,qBAAa,gBAAiB,YAAW,aAAa;IAC9C,GAAG,CACP,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GACrD,OAAO,CAAC,aAAa,CAAC,CAcxB;CACF;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,kBAAkB,CAAC;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,gBAAgB,EAAE,MAAM,EACxB,YAAY,GAAE,2BAAgC,GAC7C,OAAO,CAAC,uBAAuB,CAAC,CA2HlC;AACD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,YAAY,GAAE,2BAAgC,GAC7C,OAAO,CAAC,aAAa,CAAC,CA2DxB;AAwFD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,SAAS,CAgBnF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuB7E;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAelF"}
@@ -1,58 +0,0 @@
1
- export type EnvironmentToken = 'staging' | 'production' | `pr${number}`;
2
- export declare function pullRequestEnvironment(prNumber: number): `pr${number}`;
3
- export declare function parseEnvironmentToken(value: string): EnvironmentToken;
4
- export declare function isPullRequestEnvironment(environment: EnvironmentToken): environment is `pr${number}`;
5
- export declare function environmentDomain(environment: string, zone: string): string;
6
- export declare function environmentResourceName(base: string, environment: string): string;
7
- export declare function hasExactEnvironmentSegment(value: string, environment: `pr${number}`): boolean;
8
- export interface KvBinding {
9
- binding: string;
10
- id: string;
11
- }
12
- export interface R2Binding {
13
- binding: string;
14
- bucketName: string;
15
- }
16
- export interface LiveKvNamespace {
17
- id: string;
18
- title: string;
19
- }
20
- export interface PullRequestKvResource {
21
- binding: string;
22
- stagingId: string;
23
- stagingTitle: string;
24
- title: string;
25
- }
26
- export interface PullRequestResourcePlan {
27
- environment: `pr${number}`;
28
- workerName: string;
29
- workerBaseName: string;
30
- kvNamespaces: PullRequestKvResource[];
31
- r2Buckets: R2Binding[];
32
- routes: Array<{
33
- pattern: string;
34
- zoneName?: string;
35
- customDomain: boolean;
36
- }>;
37
- }
38
- export interface ConfiguredEnvironmentResourcePlan {
39
- environment: EnvironmentToken;
40
- workerName: string;
41
- kvNamespaces: KvBinding[];
42
- r2Buckets: R2Binding[];
43
- routes: Array<{
44
- pattern: string;
45
- zoneName?: string;
46
- customDomain: boolean;
47
- }>;
48
- }
49
- export declare function planConfiguredEnvironmentResources(toml: string, environment: EnvironmentToken): ConfiguredEnvironmentResourcePlan;
50
- export declare function planPullRequestResources(toml: string, environment: `pr${number}`, liveNamespaces: LiveKvNamespace[]): PullRequestResourcePlan;
51
- export interface DerivePullRequestConfigOptions {
52
- environment: `pr${number}`;
53
- accountId: string;
54
- kvNamespaceIds: ReadonlyMap<string, string>;
55
- }
56
- export declare function derivePullRequestWranglerConfig(toml: string, options: DerivePullRequestConfigOptions): string;
57
- export declare function rateLimitNamespaceId(accountId: string, workerBaseName: string, environment: string, bindingName: string): string;
58
- //# sourceMappingURL=environment.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/wrangler/environment.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,YAAY,GAAG,KAAK,MAAM,EAAE,CAAC;AAKxE,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAKtE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAQrE;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,gBAAgB,GAAG,WAAW,IAAI,KAAK,MAAM,EAAE,CAEpG;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAMjF;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAG7F;AAgBD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AACD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,qBAAqB,EAAE,CAAC;IACtC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC9E;AACD,MAAM,WAAW,iCAAiC;IAChD,WAAW,EAAE,gBAAgB,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC9E;AAED,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,gBAAgB,GAC5B,iCAAiC,CAoBnC;AAyBD,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,KAAK,MAAM,EAAE,EAC1B,cAAc,EAAE,eAAe,EAAE,GAChC,uBAAuB,CAwCzB;AAED,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAED,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,8BAA8B,GAAG,MAAM,CAkD7G;AAgDD,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,MAAM,CAKR"}