alchemy 0.76.0 → 0.77.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 (107) hide show
  1. package/bin/alchemy.js +111 -30
  2. package/bin/services/execute-alchemy.ts +10 -1
  3. package/lib/aws/ec2/index.d.ts +1 -0
  4. package/lib/aws/ec2/index.d.ts.map +1 -1
  5. package/lib/aws/ec2/index.js +1 -0
  6. package/lib/aws/ec2/index.js.map +1 -1
  7. package/lib/aws/index.d.ts +1 -7
  8. package/lib/aws/index.d.ts.map +1 -1
  9. package/lib/aws/index.js +1 -8
  10. package/lib/aws/index.js.map +1 -1
  11. package/lib/cloudflare/auth.d.ts.map +1 -1
  12. package/lib/cloudflare/auth.js +1 -0
  13. package/lib/cloudflare/auth.js.map +1 -1
  14. package/lib/cloudflare/bucket-custom-domain.d.ts +90 -0
  15. package/lib/cloudflare/bucket-custom-domain.d.ts.map +1 -0
  16. package/lib/cloudflare/bucket-custom-domain.js +81 -0
  17. package/lib/cloudflare/bucket-custom-domain.js.map +1 -0
  18. package/lib/cloudflare/bucket.d.ts +28 -4
  19. package/lib/cloudflare/bucket.d.ts.map +1 -1
  20. package/lib/cloudflare/bucket.js +41 -14
  21. package/lib/cloudflare/bucket.js.map +1 -1
  22. package/lib/cloudflare/cloudflare-env-proxy.d.ts.map +1 -1
  23. package/lib/cloudflare/cloudflare-env-proxy.js +0 -3
  24. package/lib/cloudflare/cloudflare-env-proxy.js.map +1 -1
  25. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  26. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  27. package/lib/cloudflare/index.d.ts +1 -0
  28. package/lib/cloudflare/index.d.ts.map +1 -1
  29. package/lib/cloudflare/index.js +1 -0
  30. package/lib/cloudflare/index.js.map +1 -1
  31. package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
  32. package/lib/cloudflare/miniflare/build-worker-options.js +3 -1
  33. package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
  34. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
  35. package/lib/cloudflare/miniflare/remote-binding-proxy.js +73 -9
  36. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
  37. package/lib/cloudflare/react-router/plugin.d.ts +2 -1
  38. package/lib/cloudflare/react-router/plugin.d.ts.map +1 -1
  39. package/lib/cloudflare/react-router/plugin.js +6 -14
  40. package/lib/cloudflare/react-router/plugin.js.map +1 -1
  41. package/lib/cloudflare/vite/plugin.d.ts.map +1 -1
  42. package/lib/cloudflare/vite/plugin.js +0 -3
  43. package/lib/cloudflare/vite/plugin.js.map +1 -1
  44. package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
  45. package/lib/cloudflare/worker-bundle.js +17 -0
  46. package/lib/cloudflare/worker-bundle.js.map +1 -1
  47. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  48. package/lib/cloudflare/worker-metadata.js +6 -4
  49. package/lib/cloudflare/worker-metadata.js.map +1 -1
  50. package/lib/cloudflare/worker-subdomain.d.ts.map +1 -1
  51. package/lib/cloudflare/worker-subdomain.js +0 -1
  52. package/lib/cloudflare/worker-subdomain.js.map +1 -1
  53. package/lib/cloudflare/worker.d.ts.map +1 -1
  54. package/lib/cloudflare/worker.js +28 -38
  55. package/lib/cloudflare/worker.js.map +1 -1
  56. package/lib/cloudflare/wrangler.json.d.ts +2 -281
  57. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  58. package/lib/cloudflare/wrangler.json.js +23 -11
  59. package/lib/cloudflare/wrangler.json.js.map +1 -1
  60. package/lib/encrypt.d.ts +28 -3
  61. package/lib/encrypt.d.ts.map +1 -1
  62. package/lib/encrypt.js +77 -3
  63. package/lib/encrypt.js.map +1 -1
  64. package/lib/planetscale/role.d.ts +9 -0
  65. package/lib/planetscale/role.d.ts.map +1 -1
  66. package/lib/planetscale/role.js +18 -3
  67. package/lib/planetscale/role.js.map +1 -1
  68. package/lib/prisma-postgres/api.d.ts.map +1 -1
  69. package/lib/prisma-postgres/api.js +1 -0
  70. package/lib/prisma-postgres/api.js.map +1 -1
  71. package/lib/scope.d.ts +5 -0
  72. package/lib/scope.d.ts.map +1 -1
  73. package/lib/scope.js +23 -0
  74. package/lib/scope.js.map +1 -1
  75. package/lib/serde.js +1 -1
  76. package/lib/serde.js.map +1 -1
  77. package/lib/util/telemetry.js +4 -0
  78. package/lib/util/telemetry.js.map +1 -1
  79. package/package.json +12 -10
  80. package/src/aws/ec2/index.ts +1 -0
  81. package/src/aws/index.ts +1 -9
  82. package/src/cloudflare/auth.ts +1 -0
  83. package/src/cloudflare/bucket-custom-domain.ts +281 -0
  84. package/src/cloudflare/bucket.ts +85 -18
  85. package/src/cloudflare/cloudflare-env-proxy.ts +0 -3
  86. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  87. package/src/cloudflare/index.ts +1 -0
  88. package/src/cloudflare/miniflare/build-worker-options.ts +3 -1
  89. package/src/cloudflare/miniflare/remote-binding-proxy.ts +80 -9
  90. package/src/cloudflare/react-router/plugin.ts +9 -21
  91. package/src/cloudflare/vite/plugin.ts +0 -3
  92. package/src/cloudflare/worker-bundle.ts +28 -1
  93. package/src/cloudflare/worker-metadata.ts +8 -4
  94. package/src/cloudflare/worker-subdomain.ts +0 -1
  95. package/src/cloudflare/worker.ts +32 -45
  96. package/src/cloudflare/wrangler.json.ts +62 -397
  97. package/src/encrypt.ts +115 -3
  98. package/src/planetscale/role.ts +30 -3
  99. package/src/prisma-postgres/api.ts +1 -0
  100. package/src/scope.ts +27 -0
  101. package/src/serde.ts +1 -1
  102. package/src/util/telemetry.ts +5 -0
  103. package/workers/cloudflare-state-store.js +4802 -8
  104. package/workers/dofs-state-store.js +632 -2
  105. package/workers/remote-binding-proxy.js +1929 -3
  106. package/workers/tunnel-proxy.js +58 -6
  107. package/workers/tunnel-proxy.ts +1 -1
@@ -1,32 +1,20 @@
1
1
  import type { PluginConfig } from "@cloudflare/vite-plugin";
2
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
3
- import { dirname } from "pathe";
4
- import { getDefaultConfigPath } from "../miniflare/paths.ts";
2
+ import type { PluginOption } from "vite";
5
3
  import alchemyVite from "../vite/plugin.ts";
6
4
 
7
- const alchemy = (config?: PluginConfig) => {
8
- const configPath = config?.configPath ?? getDefaultConfigPath();
9
- // react-router type generation requries a wrangler.json and creates a chicken and egg problem
10
- // we create a dummy wrangler.json file so that clean builds can be performed
11
- if (!existsSync(configPath)) {
12
- mkdirSync(dirname(configPath), { recursive: true });
13
- writeFileSync(
14
- configPath,
15
- JSON.stringify(
16
- {
17
- name: "dummy",
18
- compatibility_date: "2025-09-23",
19
- },
20
- null,
21
- 2,
22
- ),
23
- );
5
+ const alchemy = (config: PluginConfig = {}): PluginOption => {
6
+ // plugin is not required for react-router typegen, so return a no-op to avoid errors
7
+ if (
8
+ process.argv.some((arg) => arg.includes("react-router")) &&
9
+ process.argv.includes("typegen")
10
+ ) {
11
+ return null;
24
12
  }
25
13
  return alchemyVite({
26
- ...config,
27
14
  viteEnvironment: {
28
15
  name: "ssr",
29
16
  },
17
+ ...config,
30
18
  });
31
19
  };
32
20
 
@@ -26,9 +26,6 @@ const alchemy = (config?: PluginConfig): PluginOption => {
26
26
  config?.configPath ?? getDefaultConfigPath(),
27
27
  ),
28
28
  persistState,
29
- experimental: config?.experimental ?? {
30
- remoteBindings: true,
31
- },
32
29
  }),
33
30
  {
34
31
  name: "alchemy-supress-watch",
@@ -308,8 +308,14 @@ export namespace WorkerBundleSource {
308
308
 
309
309
  for await (const result of hotReload.iterator) {
310
310
  count++;
311
+ if (result.errors.length > 0 || result.metafile == null) {
312
+ logger.error(
313
+ `Error bundling worker \`${this.props.id}\`, see detailed logs above.`,
314
+ );
315
+ continue;
316
+ }
311
317
  const { entrypoint, root, modules } = await this.formatBuildOutput(
312
- result.metafile!,
318
+ result.metafile,
313
319
  );
314
320
  yield {
315
321
  entrypoint,
@@ -416,12 +422,16 @@ export namespace WorkerBundleSource {
416
422
  );
417
423
  const paths: string[] = [];
418
424
  let entrypoint: string | undefined;
425
+ let sourcemap: string | undefined;
419
426
  for (const [key, value] of Object.entries(metafile.outputs)) {
420
427
  const name = path.relative(outdir, path.resolve(this.props.cwd, key));
421
428
  paths.push(name);
422
429
  if (value.entryPoint === this.props.entrypoint) {
423
430
  entrypoint = name;
424
431
  }
432
+ if (name.endsWith(".map")) {
433
+ sourcemap = name;
434
+ }
425
435
  }
426
436
  if (!entrypoint) {
427
437
  throw new Error(
@@ -433,6 +443,23 @@ export namespace WorkerBundleSource {
433
443
  .join(", ")}`,
434
444
  );
435
445
  }
446
+ if (sourcemap != null) {
447
+ const map = JSON.parse(
448
+ await fs.readFile(path.join(outdir, sourcemap), "utf-8"),
449
+ ) as { sources: Array<string> };
450
+ map.sources = map.sources.map((source) => {
451
+ const originalPath = path.join(outdir, source);
452
+ const entrypointDir = path.dirname(
453
+ path.resolve(this.props.cwd, this.props.entrypoint),
454
+ );
455
+ return path.relative(entrypointDir, originalPath);
456
+ });
457
+ await fs.writeFile(
458
+ path.join(outdir, sourcemap),
459
+ JSON.stringify(map),
460
+ "utf-8",
461
+ );
462
+ }
436
463
  return {
437
464
  entrypoint,
438
465
  root: outdir,
@@ -312,7 +312,10 @@ export async function prepareWorkerMetadata(
312
312
  // let's now apply a herusitic based on binding name (assume binding name is consistent)
313
313
  // TODO(sam): this has a chance of being wrong, is that OK? Users should be encouraged to upgrade alchemy version and re-deploy
314
314
  const object = props.bindings?.[oldBinding.name];
315
- if (object && isDurableObjectNamespace(object)) {
315
+ if (
316
+ object &&
317
+ (isDurableObjectNamespace(object) || isContainer(object))
318
+ ) {
316
319
  if (object.className === oldBinding.class_name) {
317
320
  // this is relatively safe to assume is the right match, do not delete
318
321
  return [];
@@ -683,10 +686,11 @@ export async function prepareWorkerMetadata(
683
686
 
684
687
  export function bumpMigrationTagVersion(tag?: string) {
685
688
  if (tag) {
686
- if (!tag.match(/^v\d+$/)) {
687
- throw new Error(`Invalid tag format: ${tag}. Expected format: v<number>`);
689
+ const version = tag.match(/^(alchemy:)?v(\d+)$/)?.[2];
690
+ if (!version) {
691
+ return "alchemy:v1";
688
692
  }
689
- return `v${Number.parseInt(tag.slice(1), 10) + 1}`;
693
+ return `alchemy:v${Number.parseInt(version, 10) + 1}`;
690
694
  }
691
695
  return undefined;
692
696
  }
@@ -126,7 +126,6 @@ export async function getWorkerSubdomain(
126
126
  `/accounts/${api.accountId}/workers/scripts/${scriptName}/subdomain`,
127
127
  ),
128
128
  ).catch((error): SubdomainResponse => {
129
- console.log("error", error);
130
129
  if (error.status === 404) {
131
130
  return { enabled: false, previews_enabled: false };
132
131
  }
@@ -61,6 +61,7 @@ import { Workflow, isWorkflow, upsertWorkflow } from "./workflow.ts";
61
61
  // This import is here to avoid errors when destroying the `Bundle` resource.
62
62
  import "../esbuild/bundle.ts";
63
63
  import { Scope } from "../scope.ts";
64
+ import { extractCloudflareResult } from "./api-response.ts";
64
65
  import type { WorkerRef } from "./worker-ref.ts";
65
66
  import { createEmptyWorker, exists } from "./worker-stub.ts";
66
67
 
@@ -1586,54 +1587,40 @@ export async function putWorker(
1586
1587
  return withExponentialBackoff(
1587
1588
  async () => {
1588
1589
  const { body, endpoint, method } = await prepareWorkerUpload(api, props);
1589
- const uploadResponse = await api.fetch(endpoint, {
1590
- method,
1591
- headers: {
1592
- "Content-Type": "multipart/form-data",
1593
- },
1594
- body,
1595
- });
1596
-
1597
- // Check if the upload was successful
1598
- if (!uploadResponse.ok) {
1599
- try {
1600
- return await handleApiError(
1601
- uploadResponse,
1602
- version ? "uploading worker version" : "uploading worker script",
1603
- "worker",
1604
- workerName,
1605
- );
1606
- } catch (error) {
1607
- if (error instanceof CloudflareApiError && error.status === 412) {
1608
- // this happens when adopting a Worker managed with Wrangler
1609
- // because wrangler includes a migration tag and we do not
1610
- // currently, the only way to discover the old_tag is through the error message
1611
- // Get Worker Script Settings is meant to return it (according to the docs)
1612
- // but it doesn't work at runtime
1613
- //
1614
- // so, we catch the error and parse out the tag and then retry
1615
- if (error.message.includes("when expected tag is")) {
1616
- const newTag = error.message.match(
1617
- /when expected tag is ['"]?(v\d+)['"]?/,
1618
- )?.[1];
1619
- if (newTag) {
1620
- return await putWorker(api, {
1621
- ...props,
1622
- migrationTag: newTag,
1623
- });
1624
- }
1625
- } else {
1626
- throw error;
1627
- }
1628
- } else {
1629
- throw error;
1590
+ try {
1591
+ return await extractCloudflareResult<PutWorkerResult>(
1592
+ version
1593
+ ? `upload version for worker "${workerName}"`
1594
+ : `upload worker script "${workerName}"`,
1595
+ api.fetch(endpoint, {
1596
+ method,
1597
+ headers: {
1598
+ "Content-Type": "multipart/form-data",
1599
+ },
1600
+ body,
1601
+ }),
1602
+ );
1603
+ } catch (error) {
1604
+ if (error instanceof CloudflareApiError && error.status === 412) {
1605
+ // this happens when adopting a Worker managed with Wrangler
1606
+ // because wrangler includes a migration tag and we do not
1607
+ // currently, the only way to discover the old_tag is through the error message
1608
+ // Get Worker Script Settings is meant to return it (according to the docs)
1609
+ // but it doesn't work at runtime
1610
+ //
1611
+ // so, we catch the error and parse out the tag and then retry
1612
+ const newTag = error.message.match(
1613
+ /when expected tag is ['"]?([^'"]+)['"]?/,
1614
+ )?.[1];
1615
+ if (newTag) {
1616
+ return await putWorker(api, {
1617
+ ...props,
1618
+ migrationTag: newTag,
1619
+ });
1630
1620
  }
1631
1621
  }
1622
+ throw error;
1632
1623
  }
1633
- const responseData = (await uploadResponse.json()) as {
1634
- result: PutWorkerResult;
1635
- };
1636
- return responseData.result;
1637
1624
  },
1638
1625
  (err) =>
1639
1626
  err.status === 404 ||