alchemy 0.48.3 → 0.49.1

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 (113) hide show
  1. package/bin/alchemy.mjs +15 -15
  2. package/bin/commands/create.ts +0 -15
  3. package/bin/commands/deploy.ts +2 -0
  4. package/bin/commands/dev.ts +10 -1
  5. package/bin/services/execute-alchemy.ts +9 -0
  6. package/lib/alchemy.d.ts +13 -1
  7. package/lib/alchemy.d.ts.map +1 -1
  8. package/lib/alchemy.js +3 -1
  9. package/lib/alchemy.js.map +1 -1
  10. package/lib/apply.js +22 -18
  11. package/lib/apply.js.map +1 -1
  12. package/lib/aws/s3-state-store.d.ts +0 -1
  13. package/lib/aws/s3-state-store.d.ts.map +1 -1
  14. package/lib/aws/s3-state-store.js +1 -3
  15. package/lib/aws/s3-state-store.js.map +1 -1
  16. package/lib/cloudflare/bindings.d.ts +21 -2
  17. package/lib/cloudflare/bindings.d.ts.map +1 -1
  18. package/lib/cloudflare/bindings.js.map +1 -1
  19. package/lib/cloudflare/bound.d.ts +8 -1
  20. package/lib/cloudflare/bound.d.ts.map +1 -1
  21. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  22. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  23. package/lib/cloudflare/index.d.ts +1 -0
  24. package/lib/cloudflare/index.d.ts.map +1 -1
  25. package/lib/cloudflare/index.js +1 -0
  26. package/lib/cloudflare/index.js.map +1 -1
  27. package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +1 -1
  28. package/lib/cloudflare/miniflare/miniflare-worker-options.js +4 -0
  29. package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +1 -1
  30. package/lib/cloudflare/rate-limit.d.ts +63 -0
  31. package/lib/cloudflare/rate-limit.d.ts.map +1 -0
  32. package/lib/cloudflare/rate-limit.js +41 -0
  33. package/lib/cloudflare/rate-limit.js.map +1 -0
  34. package/lib/cloudflare/route.d.ts.map +1 -1
  35. package/lib/cloudflare/route.js +3 -0
  36. package/lib/cloudflare/route.js.map +1 -1
  37. package/lib/cloudflare/tanstack-start.d.ts.map +1 -1
  38. package/lib/cloudflare/tanstack-start.js +10 -1
  39. package/lib/cloudflare/tanstack-start.js.map +1 -1
  40. package/lib/cloudflare/website.d.ts +4 -0
  41. package/lib/cloudflare/website.d.ts.map +1 -1
  42. package/lib/cloudflare/website.js +14 -1
  43. package/lib/cloudflare/website.js.map +1 -1
  44. package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
  45. package/lib/cloudflare/worker-metadata.js +8 -0
  46. package/lib/cloudflare/worker-metadata.js.map +1 -1
  47. package/lib/cloudflare/worker.js +1 -1
  48. package/lib/cloudflare/worker.js.map +1 -1
  49. package/lib/cloudflare/wrangler.json.d.ts +11 -0
  50. package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
  51. package/lib/cloudflare/wrangler.json.js +15 -1
  52. package/lib/cloudflare/wrangler.json.js.map +1 -1
  53. package/lib/context.d.ts +2 -2
  54. package/lib/context.d.ts.map +1 -1
  55. package/lib/destroy.d.ts +3 -1
  56. package/lib/destroy.d.ts.map +1 -1
  57. package/lib/destroy.js +23 -4
  58. package/lib/destroy.js.map +1 -1
  59. package/lib/planetscale/password.js +1 -1
  60. package/lib/planetscale/password.js.map +1 -1
  61. package/lib/resource.d.ts +9 -0
  62. package/lib/resource.d.ts.map +1 -1
  63. package/lib/resource.js +2 -0
  64. package/lib/resource.js.map +1 -1
  65. package/lib/scope.d.ts +15 -0
  66. package/lib/scope.d.ts.map +1 -1
  67. package/lib/scope.js +9 -3
  68. package/lib/scope.js.map +1 -1
  69. package/lib/test/bun.d.ts +1 -24
  70. package/lib/test/bun.d.ts.map +1 -1
  71. package/lib/test/bun.js.map +1 -1
  72. package/lib/test/options.d.ts +37 -0
  73. package/lib/test/options.d.ts.map +1 -0
  74. package/lib/test/options.js +1 -0
  75. package/lib/test/options.js.map +1 -0
  76. package/lib/test/vitest.d.ts +1 -24
  77. package/lib/test/vitest.d.ts.map +1 -1
  78. package/lib/test/vitest.js.map +1 -1
  79. package/lib/util/ignore-matcher.d.ts.map +1 -1
  80. package/lib/util/ignore-matcher.js +1 -3
  81. package/lib/util/ignore-matcher.js.map +1 -1
  82. package/lib/util/safe-fetch.d.ts.map +1 -1
  83. package/lib/util/safe-fetch.js +9 -5
  84. package/lib/util/safe-fetch.js.map +1 -1
  85. package/package.json +2 -2
  86. package/src/alchemy.ts +16 -2
  87. package/src/apply.ts +23 -21
  88. package/src/aws/s3-state-store.ts +2 -2
  89. package/src/cloudflare/bindings.ts +22 -0
  90. package/src/cloudflare/bound.ts +29 -22
  91. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  92. package/src/cloudflare/index.ts +1 -0
  93. package/src/cloudflare/miniflare/miniflare-worker-options.ts +4 -0
  94. package/src/cloudflare/rate-limit.ts +70 -0
  95. package/src/cloudflare/route.ts +4 -0
  96. package/src/cloudflare/tanstack-start.ts +10 -1
  97. package/src/cloudflare/website.ts +20 -1
  98. package/src/cloudflare/worker-metadata.ts +7 -0
  99. package/src/cloudflare/worker.ts +1 -1
  100. package/src/cloudflare/wrangler.json.ts +30 -1
  101. package/src/context.ts +2 -2
  102. package/src/destroy.ts +27 -5
  103. package/src/planetscale/password.ts +1 -1
  104. package/src/resource.ts +11 -0
  105. package/src/scope.ts +21 -4
  106. package/src/test/bun.ts +1 -28
  107. package/src/test/options.ts +42 -0
  108. package/src/test/vitest.ts +1 -28
  109. package/src/util/ignore-matcher.ts +0 -1
  110. package/src/util/safe-fetch.ts +12 -5
  111. package/templates/tanstack-start/alchemy.run.ts +1 -3
  112. package/templates/tanstack-start/package.json +3 -3
  113. package/templates/tanstack-start/vite.config.ts +26 -25
package/src/scope.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import util from "node:util";
3
3
  import type { Phase } from "./alchemy.ts";
4
- import { destroy, destroyAll } from "./destroy.ts";
4
+ import { destroy, destroyAll, DestroyStrategy } from "./destroy.ts";
5
5
  import {
6
6
  ResourceFQN,
7
7
  ResourceID,
@@ -50,6 +50,18 @@ export interface ScopeOptions {
50
50
  * @default - `true` if ran with `alchemy dev`, `alchemy watch`, `bun --watch ./alchemy.run.ts`
51
51
  */
52
52
  watch?: boolean;
53
+ /**
54
+ * Apply updates to resources even if there are no changes.
55
+ *
56
+ * @default false
57
+ */
58
+ force?: boolean;
59
+ /**
60
+ * The strategy to use when destroying resources.
61
+ *
62
+ * @default "sequential"
63
+ */
64
+ destroyStrategy?: DestroyStrategy;
53
65
  telemetryClient?: ITelemetryClient;
54
66
  logger?: LoggerApi;
55
67
  }
@@ -120,6 +132,8 @@ export class Scope {
120
132
  public readonly phase: Phase;
121
133
  public readonly local: boolean;
122
134
  public readonly watch: boolean;
135
+ public readonly force: boolean;
136
+ public readonly destroyStrategy: DestroyStrategy;
123
137
  public readonly logger: LoggerApi;
124
138
  public readonly telemetryClient: ITelemetryClient;
125
139
  public readonly dataMutex: AsyncMutex;
@@ -177,7 +191,9 @@ export class Scope {
177
191
 
178
192
  this.local = options.local ?? this.parent?.local ?? false;
179
193
  this.watch = options.watch ?? this.parent?.watch ?? false;
180
-
194
+ this.force = options.force ?? this.parent?.force ?? false;
195
+ this.destroyStrategy =
196
+ options.destroyStrategy ?? this.parent?.destroyStrategy ?? "sequential";
181
197
  if (this.local) {
182
198
  this.logger.warnOnce(
183
199
  "Development mode is in beta. Please report any issues to https://github.com/sam-goodwin/alchemy/issues.",
@@ -314,6 +330,7 @@ export class Scope {
314
330
  [ResourceKind]: "alchemy::Scope",
315
331
  [ResourceScope]: this,
316
332
  [ResourceSeq]: this.seq(),
333
+ [DestroyStrategy]: this.destroyStrategy,
317
334
  },
318
335
  props: {},
319
336
  }
@@ -425,14 +442,14 @@ export class Scope {
425
442
  );
426
443
  await destroyAll(orphans, {
427
444
  quiet: this.quiet,
428
- strategy: "sequential",
445
+ strategy: this.destroyStrategy,
429
446
  force: shouldForce,
430
447
  });
431
448
  this.rootTelemetryClient?.record({
432
449
  event: "app.success",
433
450
  elapsed: performance.now() - this.startedAt,
434
451
  });
435
- } else {
452
+ } else if (this.isErrored) {
436
453
  this.logger.warn("Scope is in error, skipping finalize");
437
454
  this.rootTelemetryClient?.record({
438
455
  event: "app.error",
package/src/test/bun.ts CHANGED
@@ -4,8 +4,8 @@ import { afterAll, beforeAll, it } from "bun:test";
4
4
  import path from "node:path";
5
5
  import { alchemy } from "../alchemy.ts";
6
6
  import { Scope } from "../scope.ts";
7
- import type { StateStoreType } from "../state.ts";
8
7
  import { NoopTelemetryClient } from "../util/telemetry/index.ts";
8
+ import type { TestOptions } from "./options.ts";
9
9
 
10
10
  /**
11
11
  * Extend the Alchemy interface to include test functionality
@@ -21,33 +21,6 @@ declare module "../alchemy.ts" {
21
21
  */
22
22
  alchemy.test = test;
23
23
 
24
- /**
25
- * Options for configuring test behavior
26
- */
27
- export interface TestOptions {
28
- /**
29
- * Whether to suppress logging output.
30
- * @default false.
31
- */
32
- quiet?: boolean;
33
-
34
- /**
35
- * Password to use for test resources.
36
- * @default "test-password".
37
- */
38
- password?: string;
39
-
40
- /**
41
- * Override the default state store for the test.
42
- */
43
- stateStore?: StateStoreType;
44
-
45
- /**
46
- * Prefix to use for the scope to isolate tests and environments.
47
- */
48
- prefix?: string;
49
- }
50
-
51
24
  /**
52
25
  * Test function type definition with overloads
53
26
  */
@@ -0,0 +1,42 @@
1
+ import type { DestroyStrategy } from "../destroy.ts";
2
+ import type { StateStoreType } from "../state.ts";
3
+
4
+ /**
5
+ * Options for configuring test behavior
6
+ */
7
+ export interface TestOptions {
8
+ /**
9
+ * Whether to suppress logging output.
10
+ * @default false.
11
+ */
12
+ quiet?: boolean;
13
+
14
+ /**
15
+ * Apply updates to resources even if there are no changes.
16
+ * @default false
17
+ */
18
+ force?: boolean;
19
+
20
+ /**
21
+ * Password to use for test resources.
22
+ * @default "test-password".
23
+ */
24
+ password?: string;
25
+
26
+ /**
27
+ * Override the default state store for the test.
28
+ */
29
+ stateStore?: StateStoreType;
30
+
31
+ /**
32
+ * Prefix to use for the scope to isolate tests and environments.
33
+ */
34
+ prefix?: string;
35
+
36
+ /**
37
+ * The strategy to use when destroying resources.
38
+ *
39
+ * @default "sequential"
40
+ */
41
+ destroyStrategy?: DestroyStrategy;
42
+ }
@@ -2,7 +2,6 @@ import path from "node:path";
2
2
  import { afterAll, beforeAll, it } from "vitest";
3
3
  import { alchemy } from "../alchemy.ts";
4
4
  import { Scope } from "../scope.ts";
5
- import type { StateStoreType } from "../state.ts";
6
5
  import {
7
6
  CloudflareStateStore,
8
7
  D1StateStore,
@@ -10,6 +9,7 @@ import {
10
9
  SQLiteStateStore,
11
10
  } from "../state/index.ts";
12
11
  import { NoopTelemetryClient } from "../util/telemetry/client.ts";
12
+ import type { TestOptions } from "./options.ts";
13
13
 
14
14
  /**
15
15
  * Extend the Alchemy interface to include test functionality
@@ -25,33 +25,6 @@ declare module "../alchemy.ts" {
25
25
  */
26
26
  alchemy.test = test;
27
27
 
28
- /**
29
- * Options for configuring test behavior
30
- */
31
- export interface TestOptions {
32
- /**
33
- * Whether to suppress logging output.
34
- * @default false.
35
- */
36
- quiet?: boolean;
37
-
38
- /**
39
- * Password to use for test resources.
40
- * @default "test-password".
41
- */
42
- password?: string;
43
-
44
- /**
45
- * Override the default state store for the test.
46
- */
47
- stateStore?: StateStoreType;
48
-
49
- /**
50
- * Prefix to use for the scope to isolate tests and environments.
51
- */
52
- prefix?: string;
53
- }
54
-
55
28
  /**
56
29
  * Test function type definition with overloads
57
30
  */
@@ -835,7 +835,6 @@ const isPathValid = (path: string): boolean =>
835
835
  const setupWindows = (): void => {
836
836
  /* eslint no-control-regex: "off" */
837
837
  const makePosix = (str: string): string =>
838
- // biome-ignore lint/suspicious/noControlCharactersInRegex: adapted from node-ignore
839
838
  /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str)
840
839
  ? str
841
840
  : str.replace(/\\/g, "/");
@@ -15,13 +15,10 @@ export async function safeFetch(
15
15
  dispatcher: await dispatcher(),
16
16
  } as RequestInit);
17
17
  } catch (err: any) {
18
+ console.log("err", err);
18
19
  latestErr = err;
19
20
  const shouldRetry =
20
- err?.code === "UND_ERR_SOCKET" ||
21
- err?.code === "ECONNRESET" ||
22
- err?.code === "UND_ERR_CONNECT_TIMEOUT" ||
23
- err?.code === "EPIPE" ||
24
- err?.name === "FetchError";
21
+ isTransientNetworkError(err) || isTransientNetworkError(err.cause);
25
22
 
26
23
  if (!shouldRetry || attempt === retries) {
27
24
  throw err;
@@ -34,6 +31,16 @@ export async function safeFetch(
34
31
  throw latestErr;
35
32
  }
36
33
 
34
+ function isTransientNetworkError(err: any) {
35
+ return (
36
+ err?.code === "UND_ERR_SOCKET" ||
37
+ err?.code === "ECONNRESET" ||
38
+ err?.code === "UND_ERR_CONNECT_TIMEOUT" ||
39
+ err?.code === "EPIPE" ||
40
+ err?.name === "FetchError"
41
+ );
42
+ }
43
+
37
44
  let agent:
38
45
  | {
39
46
  value: Agent | undefined;
@@ -5,9 +5,7 @@ import { TanStackStart } from "alchemy/cloudflare";
5
5
 
6
6
  const app = await alchemy("my-alchemy-app");
7
7
 
8
- export const worker = await TanStackStart("website", {
9
- command: "bun run build",
10
- });
8
+ export const worker = await TanStackStart("website");
11
9
 
12
10
  console.log({
13
11
  url: worker.url,
@@ -11,9 +11,9 @@
11
11
  "start": "node .output/server/index.mjs"
12
12
  },
13
13
  "dependencies": {
14
- "@tanstack/react-router": "^1.121.27",
15
- "@tanstack/react-router-devtools": "^1.121.27",
16
- "@tanstack/react-start": "^1.121.32",
14
+ "@tanstack/react-router": "^1.128.3",
15
+ "@tanstack/react-router-devtools": "^1.128.3",
16
+ "@tanstack/react-start": "^1.128.3",
17
17
  "react": "^19.0.0",
18
18
  "react-dom": "^19.0.0",
19
19
  "tailwind-merge": "3",
@@ -5,29 +5,30 @@ import { defineConfig, PluginOption } from "vite";
5
5
  import tsConfigPaths from "vite-tsconfig-paths";
6
6
 
7
7
  export default defineConfig({
8
- server: {
9
- port: 3000,
10
- },
11
- build: {
12
- target: "esnext",
13
- rollupOptions: {
14
- external: ["node:async_hooks", "cloudflare:workers"],
15
- },
16
- },
17
- plugins: [
18
- tailwindcss() as PluginOption,
19
- cloudflareWorkersDevEnvironmentShim(),
20
- tsConfigPaths({
21
- projects: ["./tsconfig.json"],
22
- }),
23
- tanstackStart({
24
- target: "cloudflare-module",
25
- tsr: {
26
- routeTreeFileHeader: [
27
- "/** biome-ignore-all lint/suspicious/noExplicitAny: code generated by @tanstack/react-start */",
28
- ],
29
- quoteStyle: "double",
30
- },
31
- }),
32
- ],
8
+ server: {
9
+ port: 3000,
10
+ },
11
+ build: {
12
+ target: "esnext",
13
+ rollupOptions: {
14
+ external: ["node:async_hooks", "cloudflare:workers"],
15
+ },
16
+ },
17
+ plugins: [
18
+ tailwindcss() as PluginOption,
19
+ cloudflareWorkersDevEnvironmentShim(),
20
+ tsConfigPaths({
21
+ projects: ["./tsconfig.json"],
22
+ }),
23
+ tanstackStart({
24
+ target: "cloudflare-module",
25
+ customViteReactPlugin: true,
26
+ tsr: {
27
+ routeTreeFileHeader: [
28
+ "/** biome-ignore-all lint/suspicious/noExplicitAny: code generated by @tanstack/react-start */",
29
+ ],
30
+ quoteStyle: "double",
31
+ },
32
+ }),
33
+ ],
33
34
  });