alchemy 0.77.5 → 0.79.0

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 (82) hide show
  1. package/bin/alchemy.js +2414 -323
  2. package/bin/commands/util.ts +234 -315
  3. package/bin/services/execute-alchemy.ts +8 -33
  4. package/lib/cloudflare/assets.js +1 -1
  5. package/lib/cloudflare/assets.js.map +1 -1
  6. package/lib/cloudflare/astro/plugin.d.ts.map +1 -1
  7. package/lib/cloudflare/astro/plugin.js +3 -1
  8. package/lib/cloudflare/astro/plugin.js.map +1 -1
  9. package/lib/cloudflare/auth.d.ts +73 -68
  10. package/lib/cloudflare/auth.d.ts.map +1 -1
  11. package/lib/cloudflare/auth.js +73 -72
  12. package/lib/cloudflare/auth.js.map +1 -1
  13. package/lib/cloudflare/cloudflare-env-proxy.d.ts +1 -1
  14. package/lib/cloudflare/cloudflare-env-proxy.d.ts.map +1 -1
  15. package/lib/cloudflare/cloudflare-env-proxy.js +2 -2
  16. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -1
  17. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  18. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  19. package/lib/cloudflare/container.d.ts +0 -3
  20. package/lib/cloudflare/container.d.ts.map +1 -1
  21. package/lib/cloudflare/container.js +10 -4
  22. package/lib/cloudflare/container.js.map +1 -1
  23. package/lib/cloudflare/d1-database.d.ts.map +1 -1
  24. package/lib/cloudflare/d1-database.js +3 -2
  25. package/lib/cloudflare/d1-database.js.map +1 -1
  26. package/lib/cloudflare/index.d.ts +2 -2
  27. package/lib/cloudflare/index.d.ts.map +1 -1
  28. package/lib/cloudflare/index.js +2 -2
  29. package/lib/cloudflare/index.js.map +1 -1
  30. package/lib/cloudflare/permission-groups.d.ts +35 -0
  31. package/lib/cloudflare/permission-groups.d.ts.map +1 -1
  32. package/lib/cloudflare/permission-groups.js +42 -0
  33. package/lib/cloudflare/permission-groups.js.map +1 -1
  34. package/lib/cloudflare/worker-assets.d.ts.map +1 -1
  35. package/lib/cloudflare/worker-assets.js +22 -1
  36. package/lib/cloudflare/worker-assets.js.map +1 -1
  37. package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
  38. package/lib/cloudflare/worker-bundle.js +1 -0
  39. package/lib/cloudflare/worker-bundle.js.map +1 -1
  40. package/lib/cloudflare/worker.d.ts +2 -0
  41. package/lib/cloudflare/worker.d.ts.map +1 -1
  42. package/lib/cloudflare/worker.js +15 -3
  43. package/lib/cloudflare/worker.js.map +1 -1
  44. package/lib/cloudflare/workflow.d.ts +1 -0
  45. package/lib/cloudflare/workflow.d.ts.map +1 -1
  46. package/lib/cloudflare/workflow.js +6 -0
  47. package/lib/cloudflare/workflow.js.map +1 -1
  48. package/lib/docker/api.d.ts.map +1 -1
  49. package/lib/docker/api.js +2 -1
  50. package/lib/docker/api.js.map +1 -1
  51. package/lib/util/camel-to-snake.d.ts +1 -1
  52. package/lib/util/camel-to-snake.d.ts.map +1 -1
  53. package/lib/util/camel-to-snake.js +26 -13
  54. package/lib/util/camel-to-snake.js.map +1 -1
  55. package/lib/util/detect-node-runtime.d.ts.map +1 -1
  56. package/lib/util/detect-node-runtime.js +0 -2
  57. package/lib/util/detect-node-runtime.js.map +1 -1
  58. package/lib/util/detect-package-manager.d.ts +1 -1
  59. package/lib/util/detect-package-manager.d.ts.map +1 -1
  60. package/lib/util/detect-package-manager.js +11 -8
  61. package/lib/util/detect-package-manager.js.map +1 -1
  62. package/package.json +5 -1
  63. package/src/cloudflare/assets.ts +1 -1
  64. package/src/cloudflare/astro/plugin.ts +8 -1
  65. package/src/cloudflare/auth.ts +94 -75
  66. package/src/cloudflare/cloudflare-env-proxy.ts +5 -1
  67. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  68. package/src/cloudflare/container.ts +10 -7
  69. package/src/cloudflare/d1-database.ts +6 -2
  70. package/src/cloudflare/index.ts +2 -2
  71. package/src/cloudflare/permission-groups.ts +42 -0
  72. package/src/cloudflare/worker-assets.ts +34 -1
  73. package/src/cloudflare/worker-bundle.ts +1 -0
  74. package/src/cloudflare/worker.ts +27 -2
  75. package/src/cloudflare/workflow.ts +9 -0
  76. package/src/docker/api.ts +2 -1
  77. package/src/util/camel-to-snake.ts +34 -19
  78. package/src/util/detect-node-runtime.ts +0 -2
  79. package/src/util/detect-package-manager.ts +12 -8
  80. package/templates/tanstack-start/alchemy.run.ts +8 -2
  81. package/templates/tanstack-start/src/routes/demo.start.server-funcs.tsx +11 -16
  82. package/workers/tunnel-proxy.js +1 -1
@@ -65,7 +65,7 @@ export namespace Assets {
65
65
  * @returns Metadata for all assets in the directory
66
66
  */
67
67
  export const read = async (root: string): Promise<FileMetadata[]> => {
68
- const matcher = ignore().add(".assetsignore");
68
+ const matcher = ignore().add([".assetsignore", "_headers", "_redirects"]);
69
69
  const ignorePath = path.join(root, ".assetsignore");
70
70
  try {
71
71
  const content = await fs.readFile(ignorePath, "utf-8");
@@ -2,9 +2,16 @@ import cloudflare, { type Options } from "@astrojs/cloudflare";
2
2
  import type { AstroIntegration } from "astro";
3
3
  import { getPlatformProxyOptions } from "../cloudflare-env-proxy.ts";
4
4
 
5
+ const isAstroCheck =
6
+ !!process.argv.find((arg) => arg.includes("astro")) &&
7
+ process.argv.includes("check");
8
+
5
9
  const alchemy = (options?: Options): AstroIntegration => {
6
10
  return cloudflare({
7
- platformProxy: getPlatformProxyOptions(options?.platformProxy),
11
+ platformProxy: getPlatformProxyOptions(
12
+ options?.platformProxy,
13
+ !isAstroCheck,
14
+ ),
8
15
  ...options,
9
16
  });
10
17
  };
@@ -18,88 +18,106 @@ export namespace CloudflareAuth {
18
18
  name: string;
19
19
  };
20
20
  export const ALL_SCOPES = {
21
- // TODO: Verify descriptions marked with `//*`
22
- "access:read": "Read Cloudflare Access", //*
23
- "access:write": "Write Cloudflare Access", //*
21
+ "access:read":
22
+ "See Cloudflare Access data such as zones, applications, certificates, device postures, groups, identity providers, login counts, organizations, policies, service tokens, and users",
23
+ "access:write":
24
+ "See and change Cloudflare Access data such as zones, applications, certificates, device postures, groups, identity providers, login counts, organizations, policies, service tokens, and users",
24
25
  "account:read":
25
- "See your account info such as account details, analytics, and memberships.",
26
- "agw:read": "Read API Gateway", //*
27
- "agw:run": "Run API Gateway", //*
28
- "ai:read": "Read access to Workers AI catalog and assets",
29
- "ai:write": "See and change Workers AI catalog and assets",
30
- "aiaudit:read": "Read AI Audit", //*
31
- "aiaudit:write": "Write AI Audit", //*
32
- "aig:read": "Read AI Gateway", //*
33
- "aig:write": "Write AI Gateway", //*
34
- "auditlogs:read": "Read audit logs", //*
35
- "browser:read": "Read Browser", //*
36
- "browser:write": "Write Browser", //*
37
- "cfone:read": "Read Cloudflare One", //*
38
- "cfone:write": "Write Cloudflare One", //*
39
- "cloudchamber:write": "Manage Cloudchamber",
40
- "constellation:write": "Write Constellation", //*
41
- "containers:write": "Manage Workers Containers",
42
- "d1:write": "See and change D1 Databases.",
43
- "dex:read": "Read DEX", //*
44
- "dex:write": "Write DEX", //*
45
- "dns_analytics:read": "Read DNS analytics",
46
- "dns_records:edit": "Edit DNS records",
47
- "dns_records:read": "Read DNS records",
48
- "dns_settings:read": "Read DNS settings",
49
- "firstpartytags:write": "Write First Party Tags", //*
50
- "lb:edit": "Edit Load Balancer", //*
51
- "lb:read": "Read Load Balancer", //*
52
- "logpush:read": "Read Logpush", //*
53
- "logpush:write": "Write Logpush", //*
54
- "notification:read": "Read Notifications", //*
55
- "notification:write": "Write Notifications", //*
56
- "pages:read": "Read access to Pages projects, settings, and deployments.",
57
- "pages:write": "See and change Pages projects, settings, and deployments.",
58
- "pipelines:read": "Read access to Pipelines configurations and data",
59
- "pipelines:setup": "Setup access to Pipelines configurations and data",
60
- "pipelines:write": "See and change Pipelines configurations and data",
61
- "query_cache:write": "Write Query Cache", //*
62
- "queues:write": "See and change Queues settings and data",
63
- "r2_catalog:write": "Write R2 Catalog", //*
64
- "radar:read": "Read Radar", //*
65
- "rag:read": "Read RAG", //*
66
- "rag:write": "Write RAG", //*
67
- "secrets_store:read":
68
- "Read access to secrets + stores within the Secrets Store",
69
- "secrets_store:write":
70
- "See and change secrets + stores within the Secrets Store",
71
- "sso-connector:read": "Read SSO Connector", //*
72
- "sso-connector:write": "Write SSO Connector", //*
73
- "ssl_certs:write": "See and manage mTLS certificates for your account",
74
- "teams:pii": "Read Teams PII", //*
75
- "teams:read": "Read Teams", //*
76
- "teams:secure_location": "Read Secure Location", //*
77
- "teams:write": "Write Teams", //*
78
- "url_scanner:read": "Read URL Scanner", //*
79
- "url_scanner:write": "Write URL Scanner", //*
26
+ "See your account info such as account details, analytics, and memberships",
27
+ "agw:read": "Grants read level access to Agents Gateway",
28
+ "agw:run": "Grants run level access to Agents Gateway",
29
+ "agw:write": "Grants read and write level access to Agents Gateway",
30
+ "ai:read": "Grants read level access to Workers AI",
31
+ "ai:write": "Grants write level access to Workers AI",
32
+ "aiaudit:read": "Grants read level access to AI Audit",
33
+ "aiaudit:write": "Grants write level access to AI Audit",
34
+ "aig:read": "Grants read level access to AI Gateway",
35
+ "aig:write": "Grants write level access to AI Gateway",
36
+ "auditlogs:read": "View Cloudflare Account Audit Logs",
37
+ "browser:read": "Grants read level access to Browser Rendering",
38
+ "browser:write": "Grants write level access to Browser Rendering",
39
+ "cfone:read": "Grants read level access to Cloudforce One data",
40
+ "cfone:write": "Grants write level access to Cloudforce One data",
41
+ "cloudchamber:write": "See and make changes to Cloudchamber",
42
+ "connectivity:admin":
43
+ "See, change, and bind to Connectivity Directory services, including creating services targeting Cloudflare Tunnel",
44
+ "connectivity:bind":
45
+ "read, list, and bind to Connectivity Directory services, as well as read and list Cloudflare Tunnels",
46
+ "connectivity:read":
47
+ "See Connectivity Directory services and Cloudflare Tunnels",
48
+ "constellation:write":
49
+ "Grants write access to Constellation configuration and models",
50
+ "containers:write": "See and make changes to Workers Containers",
51
+ "d1:write": "See and make changes to D1",
52
+ "dex:read": "Grants read level access to Cloudflare DEX",
53
+ "dex:write": "Grants write level access to Cloudflare DEX",
54
+ "dns_analytics:read":
55
+ "Grants read level access to Cloudflare DNS Analytics",
56
+ "dns_records:edit": "Grants edit level access to dns records",
57
+ "dns_records:read": "Grants read level access to dns records",
58
+ "dns_settings:read": "Grants read level access to Cloudflare DNS Settings",
59
+ "firstpartytags:write":
60
+ "Can see, edit and publish Google tag gateway configuration.",
61
+ "lb:edit": "Grants edit level access to lb and lb pools",
62
+ "lb:read": "Grants read level access to lb and lb pools",
63
+ "logpush:read": "See Cloudflare Logpush data",
64
+ "logpush:write": "See and change Cloudflare Logpush data",
65
+ "notification:read": "View Cloudflare Notifications",
66
+ "notification:write": "View and Modify Cloudflare Notifications",
67
+ "pages:read": "See Cloudflare Pages projects, settings and deployments",
68
+ "pages:write":
69
+ "See and change Cloudflare Pages projects, settings and deployments",
70
+ "pipelines:read": "Grants read level access to Cloudflare Pipelines",
71
+ "pipelines:setup":
72
+ "Grants permission to generate R2 tokens for Workers Pipelines",
73
+ "pipelines:write": "Grants write level access to Cloudflare Pipelines",
74
+ "query_cache:write": "See and make changes to Hyperdrive",
75
+ "queues:write": "See and change Cloudflare Queues settings and data",
76
+ "r2_catalog:write": "Grants write level access to R2 Data Catalog",
77
+ "radar:read": "Grants access to read Cloudflare Radar data",
78
+ "rag:read": "Grants read level access to Auto Rag",
79
+ "rag:write": "Grants write level access to Auto Rag",
80
+ "secrets_store:read": "Grants read level access to Secrets Store",
81
+ "secrets_store:write": "Grants write level access to Secrets Store",
82
+ "ssl_certs:write":
83
+ "Grants read and write access to SSL MTLS certificates or Certificate Store",
84
+ "sso-connector:read": "See Cloudflare SSO connectors",
85
+ "sso-connector:write":
86
+ "See Cloudflare SSO connectors to toggle activation and deactivation of SSO",
87
+ "teams:pii": "See personally identifiable Cloudflare Teams data",
88
+ "teams:read":
89
+ "See Cloudflare Teams data such as zones, gateway, and argo tunnel details",
90
+ "teams:secure_location":
91
+ "See all DNS Location data but can only change secure DNS Locations",
92
+ "teams:write":
93
+ "See and change Cloudflare Teams data such as zones, gateway, and argo tunnel details",
94
+ "url_scanner:read": "Grants read level access to URL Scanner",
95
+ "url_scanner:write": "Grants write level access to URL Scanner",
80
96
  "user:read":
81
- "See your user info such as name, email address, and account memberships.",
82
- "vectorize:write": "Write Vectorize", //*
97
+ "See your user info such as name, email address, and account memberships",
98
+ "vectorize:write": "See and make changes to Vectorize",
99
+ "workers:read":
100
+ "See Cloudflare Workers data such as zones, KV storage, R2 storage, scripts, and routes",
83
101
  "workers:write":
84
- "See and change Cloudflare Workers data such as zones, KV storage, namespaces, scripts, and routes.",
85
- "workers_builds:read": "Read Workers Builds", //*
86
- "workers_builds:write": "Write Workers Builds", //*
102
+ "See and change Cloudflare Workers data such as zones, KV storage, R2 storage, scripts, and routes",
103
+ "workers_builds:read":
104
+ "See Cloudflare Workers Builds data such as builds, build configuration, and build logs",
105
+ "workers_builds:write":
106
+ "See and change Cloudflare Workers Builds data such as builds, build configuration, and build logs",
87
107
  "workers_kv:write":
88
- "See and change Cloudflare Workers KV Storage data such as keys and namespaces.",
89
- "workers_observability:read": "Read Workers Observability", //*
90
- "workers_observability:write": "Write Workers Observability", //*
108
+ "See and change Cloudflare Workers KV Storage data such as keys and namespaces",
109
+ "workers_observability:read":
110
+ "Grants read access to Cloudflare Workers Observability",
91
111
  "workers_observability_telemetry:write":
92
- "Write Workers Observability Telemetry", //*
112
+ "Grants write access to Cloudflare Workers Observability Telemetry API",
93
113
  "workers_routes:write":
94
- "See and change Cloudflare Workers data such as filters and routes.",
114
+ "See and change Cloudflare Workers data such as filters and routes",
95
115
  "workers_scripts:write":
96
- "See and change Cloudflare Workers scripts, durable objects, subdomains, triggers, and tail data.",
97
- "workers_tail:read": "See Cloudflare Workers tail and script data.",
98
- "zone:read": "Grants read level access to account zone.",
99
- // Not granted yet
100
- // "connectivity:admin":
101
- // "See, change, and bind to Connectivity Directory services, including creating services targeting Cloudflare Tunnel.",
102
- };
116
+ "See and change Cloudflare Workers scripts, durable objects, subdomains, triggers, and tail data",
117
+ "workers_tail:read": "See Cloudflare Workers tail and script data",
118
+ "zone:read": "Grants read level access to account zone",
119
+ } as const;
120
+ export type Scope = keyof typeof ALL_SCOPES;
103
121
  export const DEFAULT_SCOPES = [
104
122
  "account:read",
105
123
  "user:read",
@@ -119,6 +137,7 @@ export namespace CloudflareAuth {
119
137
  "containers:write",
120
138
  "cloudchamber:write",
121
139
  "vectorize:write",
140
+ "connectivity:admin",
122
141
  ];
123
142
 
124
143
  /**
@@ -16,6 +16,7 @@ export const getCloudflareEnvProxy = async <E>(
16
16
 
17
17
  export const getPlatformProxyOptions = (
18
18
  input: GetPlatformProxyOptions = {},
19
+ throws: boolean = true,
19
20
  ): GetPlatformProxyOptions => {
20
21
  const persist =
21
22
  input.persist === false
@@ -37,7 +38,10 @@ export const getPlatformProxyOptions = (
37
38
  }
38
39
  return {
39
40
  ...input,
40
- configPath: validateConfigPath(input.configPath ?? getDefaultConfigPath()),
41
+ configPath: validateConfigPath(
42
+ input.configPath ?? getDefaultConfigPath(),
43
+ throws,
44
+ ),
41
45
  persist,
42
46
  };
43
47
  };
@@ -4,4 +4,4 @@
4
4
  /**
5
5
  * The default Cloudflare Workers compatibility date, set based on the latest workerd release at the time of build.
6
6
  */
7
- export const DEFAULT_COMPATIBILITY_DATE = "2025-11-11";
7
+ export const DEFAULT_COMPATIBILITY_DATE = "2025-11-28";
@@ -221,6 +221,11 @@ export async function Container<T>(
221
221
  ...props,
222
222
  name: `cloudflare-dev/${name}`, // prefix used by Miniflare
223
223
  tag,
224
+ build: props.build ?? {
225
+ dockerfile: "Dockerfile",
226
+ platform: "linux/amd64",
227
+ context: process.cwd(),
228
+ },
224
229
  } as ImageProps);
225
230
 
226
231
  return {
@@ -240,7 +245,11 @@ export async function Container<T>(
240
245
  platform: props.build?.platform ?? "linux/amd64",
241
246
  ...props.build,
242
247
  }
243
- : undefined,
248
+ : {
249
+ dockerfile: "Dockerfile",
250
+ platform: "linux/amd64",
251
+ context: process.cwd(),
252
+ },
244
253
  image: props.image,
245
254
  registry: {
246
255
  server: "registry.cloudflare.com",
@@ -562,9 +571,6 @@ export const ContainerApplication = Resource(
562
571
  logs: {
563
572
  enabled: true,
564
573
  },
565
- logging: {
566
- enabled: true,
567
- },
568
574
  },
569
575
  };
570
576
  if (this.phase === "update" && this.output?.id) {
@@ -1039,9 +1045,6 @@ interface CreateRolloutApplicationResponse {
1039
1045
  logs?: {
1040
1046
  enabled: boolean;
1041
1047
  };
1042
- logging?: {
1043
- enabled: boolean;
1044
- };
1045
1048
  };
1046
1049
  };
1047
1050
  target_configuration: DeploymentConfiguration;
@@ -386,7 +386,10 @@ const _D1Database = Resource(
386
386
  `Cannot update primaryLocationHint from '${this.output.primaryLocationHint}' to '${props.primaryLocationHint}' after database creation.`,
387
387
  );
388
388
  }
389
- if (props.jurisdiction !== this.output?.jurisdiction) {
389
+ if (
390
+ (props.jurisdiction ?? "default") !==
391
+ (this.output?.jurisdiction ?? "default")
392
+ ) {
390
393
  throw new Error(
391
394
  `Cannot update jurisdiction from '${this.output.jurisdiction}' to '${props.jurisdiction}' after database creation.`,
392
395
  );
@@ -468,7 +471,8 @@ export async function createDatabase(
468
471
  // Create new D1 database
469
472
  const createPayload: any = {
470
473
  name: databaseName,
471
- jurisdiction: props.jurisdiction,
474
+ jurisdiction:
475
+ props.jurisdiction !== "default" ? props.jurisdiction : undefined,
472
476
  };
473
477
 
474
478
  if (props.primaryLocationHint) {
@@ -69,11 +69,11 @@ export * from "./vectorize-metadata-index.ts";
69
69
  export * from "./version-metadata.ts";
70
70
  export * from "./vite/vite.ts";
71
71
  export * from "./website.ts";
72
- export { WorkerLoader } from "./worker-loader.ts";
72
+ export * from "./worker-loader.ts";
73
73
  export * from "./worker-ref.ts";
74
74
  export * from "./worker-stub.ts";
75
75
  export * from "./worker-subdomain.ts";
76
76
  export * from "./worker.ts";
77
- export { Workflow } from "./workflow.ts";
77
+ export * from "./workflow.ts";
78
78
  export * from "./wrangler.json.ts";
79
79
  export * from "./zone.ts";
@@ -359,6 +359,18 @@ export const PERMISSION_GROUPS = [
359
359
  description: "Grants write access to Account Rulesets",
360
360
  scopes: ["com.cloudflare.api.account"],
361
361
  },
362
+ {
363
+ id: "ece81d7757ff406cad61f221a4920d55",
364
+ name: "Account Security Center Insights Read",
365
+ description: "Grants read access to Security Center Insights",
366
+ scopes: ["com.cloudflare.api.account"],
367
+ },
368
+ {
369
+ id: "cfa2e2893226455c9b945914969dff7c",
370
+ name: "Account Security Center Insights Write",
371
+ description: "Grants write access to Security Center Insights",
372
+ scopes: ["com.cloudflare.api.account"],
373
+ },
362
374
  {
363
375
  id: "c1fde68c7bcc44588cbb6ddbc16d6480",
364
376
  name: "Account Settings Read",
@@ -527,6 +539,18 @@ export const PERMISSION_GROUPS = [
527
539
  description: "Grants write access to Browser Rendering API",
528
540
  scopes: ["com.cloudflare.api.account"],
529
541
  },
542
+ {
543
+ id: "da5fe84b9c5446a0a5955b673fafa288",
544
+ name: "CASB Read",
545
+ description: "Grants read access to Cloudflare CASB",
546
+ scopes: ["com.cloudflare.api.account"],
547
+ },
548
+ {
549
+ id: "b9ed086b20864ad89c5aac24cdd02365",
550
+ name: "CASB Write",
551
+ description: "Grants write access to Cloudflare CASB",
552
+ scopes: ["com.cloudflare.api.account"],
553
+ },
530
554
  {
531
555
  id: "47b936e2027140c0a474cac8887b8c29",
532
556
  name: "CF Agents Read",
@@ -970,6 +994,18 @@ export const PERMISSION_GROUPS = [
970
994
  description: "Grants full access to Email Security dmarc reports\n",
971
995
  scopes: ["com.cloudflare.api.account.zone"],
972
996
  },
997
+ {
998
+ id: "2d5b4b1f6c89487bb7184c2c1dcd3bf1",
999
+ name: "Email Sending Read",
1000
+ description: "Grants access to reading data from Email Sending",
1001
+ scopes: ["com.cloudflare.api.account"],
1002
+ },
1003
+ {
1004
+ id: "5df633d6b41c42bcaf5b4a62b9d14b64",
1005
+ name: "Email Sending Write",
1006
+ description: "Grants access to reading and writing data from Email Sending",
1007
+ scopes: ["com.cloudflare.api.account"],
1008
+ },
973
1009
  {
974
1010
  id: "4ec32dfcb35641c5bb32d5ef1ab963b4",
975
1011
  name: "Firewall Services Read",
@@ -1426,6 +1462,12 @@ export const PERMISSION_GROUPS = [
1426
1462
  description: "Grants admin access to Realtime configuration",
1427
1463
  scopes: ["com.cloudflare.api.account"],
1428
1464
  },
1465
+ {
1466
+ id: "9bb90620717647a39679e1d951f140d6",
1467
+ name: "Registrar Domains Read",
1468
+ description: "Grants read access to Cloudflare Registrar domains",
1469
+ scopes: ["com.cloudflare.api.account"],
1470
+ },
1429
1471
  {
1430
1472
  id: "93ae59e7a40c4287a57ff6e501186a63",
1431
1473
  name: "Response Compression Read",
@@ -1,4 +1,5 @@
1
1
  import fs from "node:fs/promises";
2
+ import path from "pathe";
2
3
  import { AsyncQueue } from "../util/async-queue.ts";
3
4
  import { withExponentialBackoff } from "../util/retry.ts";
4
5
  import { extractCloudflareResult } from "./api-response.ts";
@@ -38,7 +39,10 @@ export async function uploadAssets(
38
39
  },
39
40
  ): Promise<AssetUploadResult> {
40
41
  // Process the assets configuration once at the beginning
41
- const processedConfig = createAssetConfig(assetConfig);
42
+ const processedConfig = await createAssetConfigWithFiles(
43
+ assets.path,
44
+ assetConfig,
45
+ );
42
46
 
43
47
  const manifest: Record<string, FileMetadata> = {};
44
48
  const filesByHash = new Map<string, Assets.FileMetadata>();
@@ -95,6 +99,35 @@ export async function uploadAssets(
95
99
  };
96
100
  }
97
101
 
102
+ async function createAssetConfigWithFiles(
103
+ assetsPath: string,
104
+ config: AssetsConfig = {},
105
+ ): Promise<AssetsConfig> {
106
+ const [_headers, _redirects] = await Promise.all([
107
+ readFileOrProperty("_headers"),
108
+ readFileOrProperty("_redirects"),
109
+ ]);
110
+ return createAssetConfig({
111
+ ...config,
112
+ _headers,
113
+ _redirects,
114
+ });
115
+
116
+ async function readFileOrProperty(
117
+ property: "_headers" | "_redirects",
118
+ ): Promise<string | undefined> {
119
+ const content = await fs
120
+ .readFile(path.join(assetsPath, property), "utf-8")
121
+ .catch(() => undefined);
122
+ if (content && config[property]) {
123
+ throw new Error(
124
+ `Cannot use both ${property} file and ${property} property`,
125
+ );
126
+ }
127
+ return content ?? config[property];
128
+ }
129
+ }
130
+
98
131
  /**
99
132
  * Creates asset configuration object from provided config or defaults
100
133
  */
@@ -351,6 +351,7 @@ export namespace WorkerBundleSource {
351
351
  ".js": "jsx",
352
352
  ".mjs": "jsx",
353
353
  ".cjs": "jsx",
354
+ ".sql": "text",
354
355
  },
355
356
  format,
356
357
  sourceRoot: this.props.outdir,
@@ -51,11 +51,17 @@ import {
51
51
  import {
52
52
  type WorkerScriptMetadata,
53
53
  bumpMigrationTagVersion,
54
+ getWorkerSettings,
54
55
  prepareWorkerMetadata,
55
56
  } from "./worker-metadata.ts";
56
57
  import { WorkerSubdomain, disableWorkerSubdomain } from "./worker-subdomain.ts";
57
58
  import { createTail } from "./worker-tail.ts";
58
- import { Workflow, isWorkflow, upsertWorkflow } from "./workflow.ts";
59
+ import {
60
+ Workflow,
61
+ deleteWorkflow,
62
+ isWorkflow,
63
+ upsertWorkflow,
64
+ } from "./workflow.ts";
59
65
 
60
66
  // Previous versions of `Worker` used the `Bundle` resource.
61
67
  // This import is here to avoid errors when destroying the `Bundle` resource.
@@ -71,11 +77,13 @@ import { createEmptyWorker, exists } from "./worker-stub.ts";
71
77
  export interface AssetsConfig {
72
78
  /**
73
79
  * The contents of a _headers file (used to attach custom headers on asset responses)
80
+ * @default the `_headers` file in the assets directory, if present
74
81
  */
75
82
  _headers?: string;
76
83
 
77
84
  /**
78
85
  * The contents of a _redirects file (used to apply redirects or proxy paths ahead of asset serving)
86
+ * @default the `_redirects` file in the assets directory, if present
79
87
  */
80
88
  _redirects?: string;
81
89
 
@@ -949,7 +957,10 @@ const _Worker = Resource(
949
957
  await createEmptyWorker(api, options.name, props.version);
950
958
  }
951
959
  } else {
952
- await deleteQueueConsumers(api, options.name);
960
+ await Promise.all([
961
+ deleteQueueConsumers(api, options.name),
962
+ deleteWorkflows(api, options.name),
963
+ ]);
953
964
  await deleteWorker(api, {
954
965
  scriptName: options.name,
955
966
  dispatchNamespace: options.dispatchNamespace,
@@ -1706,6 +1717,20 @@ async function deleteQueueConsumers(api: CloudflareApi, scriptName: string) {
1706
1717
  );
1707
1718
  }
1708
1719
 
1720
+ async function deleteWorkflows(api: CloudflareApi, scriptName: string) {
1721
+ const settings = await getWorkerSettings(api, scriptName);
1722
+ await Promise.all(
1723
+ (settings?.bindings ?? []).map(async (binding) => {
1724
+ if (
1725
+ binding.type === "workflow" &&
1726
+ (binding.script_name === scriptName || !binding.script_name)
1727
+ ) {
1728
+ await deleteWorkflow(api, binding.workflow_name);
1729
+ }
1730
+ }),
1731
+ );
1732
+ }
1733
+
1709
1734
  export async function deleteWorker(
1710
1735
  api: CloudflareApi,
1711
1736
  props: {
@@ -116,3 +116,12 @@ export async function upsertWorkflow(
116
116
 
117
117
  return body.result;
118
118
  }
119
+
120
+ export async function deleteWorkflow(api: CloudflareApi, name: string) {
121
+ const response = await api.delete(
122
+ `/accounts/${api.accountId}/workflows/${name}`,
123
+ );
124
+ if (!response.ok && response.status !== 404) {
125
+ await handleApiError(response, "delete", "workflow", name);
126
+ }
127
+ }
package/src/docker/api.ts CHANGED
@@ -134,7 +134,8 @@ export class DockerApi {
134
134
  } catch (error: any) {
135
135
  const message = stderr || error.message || "Command failed";
136
136
  if (
137
- message.includes("unexpected status from HEAD request") &&
137
+ (message.includes("unexpected status from HEAD request") ||
138
+ message.includes("502 Bad Gateway")) &&
138
139
  remainingAttempts > 0
139
140
  ) {
140
141
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -2,26 +2,41 @@ export interface LogPushProps {
2
2
  maxFooBar: string;
3
3
  }
4
4
 
5
- export function camelToSnakeObjectDeep<T extends object | undefined>(
5
+ export function camelToSnakeObjectDeep<T>(
6
6
  obj: T,
7
- ): T extends undefined ? undefined : CamelToSnake<T> {
8
- return (
9
- obj
10
- ? Object.fromEntries(
11
- Object.entries(obj).map(([key, value]) => [
12
- key
13
- .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2") // Handle consecutive capitals: "FOOBar" -> "FOO_Bar"
14
- .replace(/([a-z])([A-Z])/g, "$1_$2") // Handle normal camelCase: "fooBar" -> "foo_Bar"
15
- .toLowerCase(),
16
- Array.isArray(value)
17
- ? value.map(camelToSnakeObjectDeep)
18
- : typeof value === "object" && value !== null
19
- ? camelToSnakeObjectDeep(value)
20
- : value,
21
- ]),
22
- )
23
- : undefined
24
- ) as T extends undefined ? undefined : CamelToSnake<T>;
7
+ ): T extends undefined ? undefined : T extends object ? CamelToSnake<T> : T {
8
+ if (obj === undefined || obj === null) {
9
+ return obj as any;
10
+ }
11
+
12
+ // If it's not an object (primitive types), return as-is
13
+ if (typeof obj !== "object") {
14
+ return obj as any;
15
+ }
16
+
17
+ if (obj instanceof RegExp) {
18
+ return obj as any;
19
+ }
20
+
21
+ // Handle arrays
22
+ if (Array.isArray(obj)) {
23
+ return obj.map(camelToSnakeObjectDeep) as any;
24
+ }
25
+
26
+ // Handle objects
27
+ return Object.fromEntries(
28
+ Object.entries(obj).map(([key, value]) => [
29
+ key
30
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2") // Handle consecutive capitals: "FOOBar" -> "FOO_Bar"
31
+ .replace(/([a-z])([A-Z])/g, "$1_$2") // Handle normal camelCase: "fooBar" -> "foo_Bar"
32
+ .toLowerCase(),
33
+ Array.isArray(value)
34
+ ? value.map(camelToSnakeObjectDeep)
35
+ : typeof value === "object" && value !== null
36
+ ? camelToSnakeObjectDeep(value)
37
+ : value,
38
+ ]),
39
+ ) as any;
25
40
  }
26
41
 
27
42
  // Helper to check if a character is uppercase
@@ -6,7 +6,5 @@ export type Runtime = "bun" | "deno" | "node";
6
6
  export function detectRuntime(): Runtime {
7
7
  if (typeof Bun !== "undefined" && Bun !== null) return "bun";
8
8
  if (typeof Deno !== "undefined" && Deno !== null) return "deno";
9
- if (typeof process !== "undefined" && process.release?.name === "node")
10
- return "node";
11
9
  return "node";
12
10
  }