alchemy 2.0.0-beta.53 → 2.0.0-beta.55

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 (94) hide show
  1. package/bin/exec.js +1 -1
  2. package/bin/exec.js.map +1 -1
  3. package/lib/Cloudflare/AiGateway/AiGatewaySpendingLimit.d.ts +165 -0
  4. package/lib/Cloudflare/AiGateway/AiGatewaySpendingLimit.d.ts.map +1 -0
  5. package/lib/Cloudflare/AiGateway/AiGatewaySpendingLimit.js +232 -0
  6. package/lib/Cloudflare/AiGateway/AiGatewaySpendingLimit.js.map +1 -0
  7. package/lib/Cloudflare/AiGateway/index.d.ts +1 -0
  8. package/lib/Cloudflare/AiGateway/index.d.ts.map +1 -1
  9. package/lib/Cloudflare/AiGateway/index.js +1 -0
  10. package/lib/Cloudflare/AiGateway/index.js.map +1 -1
  11. package/lib/Cloudflare/Bridge.d.ts +1 -0
  12. package/lib/Cloudflare/Bridge.d.ts.map +1 -1
  13. package/lib/Cloudflare/Bridge.js +1 -0
  14. package/lib/Cloudflare/Bridge.js.map +1 -1
  15. package/lib/Cloudflare/Fetcher.d.ts +2 -2
  16. package/lib/Cloudflare/Fetcher.d.ts.map +1 -1
  17. package/lib/Cloudflare/Fetcher.js.map +1 -1
  18. package/lib/Cloudflare/Hyperdrive/Hyperdrive.d.ts.map +1 -1
  19. package/lib/Cloudflare/Hyperdrive/Hyperdrive.js +6 -6
  20. package/lib/Cloudflare/Hyperdrive/Hyperdrive.js.map +1 -1
  21. package/lib/Cloudflare/Local.js +5 -2
  22. package/lib/Cloudflare/Local.js.map +1 -1
  23. package/lib/Cloudflare/LocalRuntime.d.ts +21 -0
  24. package/lib/Cloudflare/LocalRuntime.d.ts.map +1 -0
  25. package/lib/Cloudflare/LocalRuntime.js +40 -0
  26. package/lib/Cloudflare/LocalRuntime.js.map +1 -0
  27. package/lib/Cloudflare/Providers.d.ts +1 -1
  28. package/lib/Cloudflare/Providers.d.ts.map +1 -1
  29. package/lib/Cloudflare/Providers.js +3 -1
  30. package/lib/Cloudflare/Providers.js.map +1 -1
  31. package/lib/Cloudflare/Queue/Queue.d.ts +4 -1
  32. package/lib/Cloudflare/Queue/Queue.d.ts.map +1 -1
  33. package/lib/Cloudflare/Queue/Queue.js +61 -2
  34. package/lib/Cloudflare/Queue/Queue.js.map +1 -1
  35. package/lib/Cloudflare/Queue/QueueConsumer.d.ts +32 -26
  36. package/lib/Cloudflare/Queue/QueueConsumer.d.ts.map +1 -1
  37. package/lib/Cloudflare/Queue/QueueConsumer.js +73 -3
  38. package/lib/Cloudflare/Queue/QueueConsumer.js.map +1 -1
  39. package/lib/Cloudflare/Workers/Assets.js +2 -2
  40. package/lib/Cloudflare/Workers/Assets.js.map +1 -1
  41. package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts +3 -5
  42. package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
  43. package/lib/Cloudflare/Workers/LocalWorkerProvider.js +32 -25
  44. package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
  45. package/lib/Cloudflare/Workers/Worker.d.ts +2 -4
  46. package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
  47. package/lib/Cloudflare/Workers/Worker.js +5 -7
  48. package/lib/Cloudflare/Workers/Worker.js.map +1 -1
  49. package/lib/Local/ProviderLayer.d.ts +10 -0
  50. package/lib/Local/ProviderLayer.d.ts.map +1 -0
  51. package/lib/Local/ProviderLayer.js +7 -0
  52. package/lib/Local/ProviderLayer.js.map +1 -0
  53. package/lib/Local/RpcProvider.d.ts +4 -3
  54. package/lib/Local/RpcProvider.d.ts.map +1 -1
  55. package/lib/Local/RpcProvider.js +6 -2
  56. package/lib/Local/RpcProvider.js.map +1 -1
  57. package/lib/Local/RpcProviderProxy.js.map +1 -1
  58. package/lib/Local/RpcSerialization.js +2 -2
  59. package/lib/Local/RpcSerialization.js.map +1 -1
  60. package/lib/Planetscale/Branch.d.ts.map +1 -1
  61. package/lib/Planetscale/Branch.js +25 -3
  62. package/lib/Planetscale/Branch.js.map +1 -1
  63. package/lib/Planetscale/Database.d.ts +1 -1
  64. package/lib/Planetscale/Postgres/PostgresClusterSize.d.ts +1 -1
  65. package/lib/Planetscale/Postgres/PostgresClusterSize.d.ts.map +1 -1
  66. package/lib/Planetscale/Postgres/PostgresClusterSize.js +13 -3
  67. package/lib/Planetscale/Postgres/PostgresClusterSize.js.map +1 -1
  68. package/lib/Planetscale/Util.d.ts +1 -1
  69. package/lib/Planetscale/Util.d.ts.map +1 -1
  70. package/lib/Planetscale/Util.js +7 -5
  71. package/lib/Planetscale/Util.js.map +1 -1
  72. package/lib/tsconfig.test.tsbuildinfo +1 -1
  73. package/package.json +12 -12
  74. package/src/Cloudflare/AiGateway/AiGatewaySpendingLimit.ts +368 -0
  75. package/src/Cloudflare/AiGateway/index.ts +1 -0
  76. package/src/Cloudflare/Bridge.ts +1 -0
  77. package/src/Cloudflare/Fetcher.ts +8 -4
  78. package/src/Cloudflare/Hyperdrive/Hyperdrive.ts +6 -8
  79. package/src/Cloudflare/Local.ts +9 -5
  80. package/src/Cloudflare/LocalRuntime.ts +70 -0
  81. package/src/Cloudflare/Providers.ts +4 -0
  82. package/src/Cloudflare/Queue/Queue.ts +73 -2
  83. package/src/Cloudflare/Queue/QueueConsumer.ts +130 -28
  84. package/src/Cloudflare/Workers/Assets.ts +2 -2
  85. package/src/Cloudflare/Workers/LocalWorkerProvider.ts +39 -30
  86. package/src/Cloudflare/Workers/Worker.ts +5 -26
  87. package/src/Local/ProviderLayer.ts +22 -0
  88. package/src/Local/RpcProvider.ts +11 -5
  89. package/src/Local/RpcProviderProxy.ts +2 -2
  90. package/src/Local/RpcSerialization.ts +2 -2
  91. package/src/Planetscale/Branch.ts +38 -10
  92. package/src/Planetscale/Database.ts +1 -1
  93. package/src/Planetscale/Postgres/PostgresClusterSize.ts +16 -2
  94. package/src/Planetscale/Util.ts +7 -5
@@ -1,6 +1,7 @@
1
1
  import * as planetscale from "@distilled.cloud/planetscale";
2
2
  import { Credentials } from "@distilled.cloud/planetscale/Credentials";
3
3
  import * as Effect from "effect/Effect";
4
+ import * as Schedule from "effect/Schedule";
4
5
  import { Unowned } from "../AdoptPolicy.ts";
5
6
  import { isResolved } from "../Diff.ts";
6
7
  import { createPhysicalName } from "../PhysicalName.ts";
@@ -157,6 +158,20 @@ export interface BranchMigrationRunners {
157
158
 
158
159
  const rootDir = Effect.sync(() => process.cwd());
159
160
 
161
+ /**
162
+ * Matches the UnprocessableEntity errors PlanetScale returns when a
163
+ * branch promotion/demotion races an in-flight cluster resize, e.g.
164
+ * "Branches with a cluster resize in progress cannot be demoted."
165
+ */
166
+ const isResizeInProgress = (error: unknown): boolean =>
167
+ typeof error === "object" &&
168
+ error !== null &&
169
+ (error as { readonly _tag?: unknown })._tag === "UnprocessableEntity" &&
170
+ typeof (error as { readonly message?: unknown }).message === "string" &&
171
+ (error as { readonly message: string }).message.includes(
172
+ "cluster resize in progress",
173
+ );
174
+
160
175
  /**
161
176
  * Build a branch provider for a specific PlanetScale engine. The
162
177
  * caller supplies the typed `Resource` token and the engine's migration
@@ -369,17 +384,30 @@ export const makeBranchProvider = <R extends ResourceLike>(opts: {
369
384
  if (opts.expectedKind === "mysql") {
370
385
  const desiredProduction = news.isProduction ?? false;
371
386
  if (current.production !== desiredProduction) {
387
+ // A keyspace can report `resizing: false` while the resize
388
+ // workflow is still finalizing, during which promote/demote is
389
+ // rejected with an UnprocessableEntity. Retry until it clears.
390
+ const retryWhileResizing = Effect.retry({
391
+ while: isResizeInProgress,
392
+ schedule: Schedule.spaced("5 seconds").pipe(
393
+ Schedule.both(Schedule.recurs(120)),
394
+ ),
395
+ });
372
396
  current = desiredProduction
373
- ? yield* planetscale.promoteBranch({
374
- organization,
375
- database: databaseName,
376
- branch: branchName,
377
- })
378
- : yield* planetscale.demoteBranch({
379
- organization,
380
- database: databaseName,
381
- branch: branchName,
382
- });
397
+ ? yield* planetscale
398
+ .promoteBranch({
399
+ organization,
400
+ database: databaseName,
401
+ branch: branchName,
402
+ })
403
+ .pipe(retryWhileResizing)
404
+ : yield* planetscale
405
+ .demoteBranch({
406
+ organization,
407
+ database: databaseName,
408
+ branch: branchName,
409
+ })
410
+ .pipe(retryWhileResizing);
383
411
  }
384
412
  }
385
413
 
@@ -65,7 +65,7 @@ export interface BaseDatabaseProps {
65
65
 
66
66
  /**
67
67
  * Name of the table used to track applied migrations.
68
- * @default "planetscale_migrations"
68
+ * @default "__alchemy_migrations"
69
69
  */
70
70
  migrationsTable?: string;
71
71
 
@@ -1,6 +1,7 @@
1
1
  import * as planetscale from "@distilled.cloud/planetscale";
2
2
  import * as Effect from "effect/Effect";
3
- import { pollUntil } from "../Util.ts";
3
+ import * as Schedule from "effect/Schedule";
4
+ import { pollUntil, waitForBranchReady } from "../Util.ts";
4
5
 
5
6
  /**
6
7
  * Available PlanetScale PostgreSQL cluster sizes.
@@ -54,6 +55,15 @@ export function toPostgresClusterSku(input: {
54
55
  return `${size}_${provider}_${arch}`;
55
56
  }
56
57
 
58
+ /**
59
+ * Schedule for polling branch change requests. Postgres cluster resizes
60
+ * routinely take longer than the default 10-minute polling budget, so
61
+ * give change requests a 60-minute budget (720 × 5s).
62
+ */
63
+ const changeRequestSchedule = Schedule.spaced("5 seconds").pipe(
64
+ Schedule.both(Schedule.recurs(720)),
65
+ );
66
+
57
67
  /**
58
68
  * Polls branch change requests until all visible changes are in a terminal
59
69
  * state (`completed` or `canceled`), or — if `changeId` is provided — until
@@ -85,6 +95,7 @@ export const waitForPendingPostgresChanges = Effect.fn(function* (
85
95
 
86
96
  return page.data.every((change) => isTerminal(change.state));
87
97
  },
98
+ changeRequestSchedule,
88
99
  );
89
100
  });
90
101
 
@@ -98,7 +109,10 @@ export const ensurePostgresProductionBranchClusterSize = Effect.fn(function* (
98
109
  branch: string,
99
110
  expectedClusterSize: PostgresClusterSize,
100
111
  ) {
101
- const data = yield* planetscale.getBranch({ organization, database, branch });
112
+ // A freshly-forked branch can't accept (or complete) change requests
113
+ // until it has finished provisioning — queueing a resize against it
114
+ // just leaves the change pending until the poll budget runs out.
115
+ const data = yield* waitForBranchReady(organization, database, branch);
102
116
 
103
117
  const sku = toPostgresClusterSku({
104
118
  size: expectedClusterSize,
@@ -12,7 +12,7 @@ export const DEFAULT_MIGRATIONS_TABLE = "__alchemy_migrations";
12
12
  * been reached. Used internally with `Effect.retry` to drive long-running
13
13
  * status waits.
14
14
  */
15
- class NotReady extends Data.TaggedError("Planetscale::NotReady")<{
15
+ export class NotReady extends Data.TaggedError("Planetscale::NotReady")<{
16
16
  description: string;
17
17
  }> {}
18
18
 
@@ -29,12 +29,14 @@ export class PlanetscaleConflict extends Data.TaggedError(
29
29
  }> {}
30
30
 
31
31
  /**
32
- * Default polling schedule: 5s spaced retries with a 10-minute total
33
- * budget (120 × 5s). Avoids the exponential-blowup trap where later
34
- * iterations would wait hours, indistinguishable from a hang.
32
+ * Default polling schedule: 5s spaced retries with a 30-minute total
33
+ * budget (360 × 5s). Avoids the exponential-blowup trap where later
34
+ * iterations would wait hours, indistinguishable from a hang. Postgres
35
+ * database creates routinely run 10-12 minutes, so a 10-minute budget
36
+ * regularly false-positives as "stuck".
35
37
  */
36
38
  const defaultSchedule = Schedule.spaced("5 seconds").pipe(
37
- Schedule.both(Schedule.recurs(120)),
39
+ Schedule.both(Schedule.recurs(360)),
38
40
  );
39
41
 
40
42
  /**