alchemy 0.15.3 → 0.15.5

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.
package/lib/serde.js CHANGED
@@ -11,7 +11,7 @@ export async function serialize(scope, value, options) {
11
11
  if (Array.isArray(value)) {
12
12
  return Promise.all(value.map((value) => serialize(scope, value, options)));
13
13
  }
14
- if (value instanceof Secret) {
14
+ else if (value instanceof Secret) {
15
15
  if (!scope.password) {
16
16
  throw new Error("Cannot serialize secret without password");
17
17
  }
@@ -21,26 +21,42 @@ export async function serialize(scope, value, options) {
21
21
  : value.unencrypted,
22
22
  };
23
23
  }
24
- if (isType(value)) {
24
+ else if (isType(value)) {
25
25
  return {
26
26
  "@schema": value.toJSON(),
27
27
  };
28
28
  }
29
- if (value instanceof Date) {
29
+ else if (value instanceof Date) {
30
30
  return {
31
31
  "@date": value.toISOString(),
32
32
  };
33
33
  }
34
- if (value instanceof Scope) {
35
- return undefined;
34
+ else if (typeof value === "symbol") {
35
+ assertNotUniqueSymbol(value);
36
+ return {
37
+ "@symbol": value.toString(),
38
+ };
36
39
  }
37
- if (value && typeof value === "object") {
38
- return Object.fromEntries(await Promise.all(Object.entries(value).map(async ([key, value]) => [
39
- key,
40
- await serialize(scope, value, options),
40
+ else if (value instanceof Scope) {
41
+ return {
42
+ "@scope": null,
43
+ };
44
+ }
45
+ else if (value && typeof value === "object") {
46
+ for (const symbol of Object.getOwnPropertySymbols(value)) {
47
+ assertNotUniqueSymbol(symbol);
48
+ }
49
+ for (const key of Object.keys(value)) {
50
+ if (parseSymbol(key)) {
51
+ throw new Error(`Cannot serialize property '${key}' because it looks like a stringified symbol.`);
52
+ }
53
+ }
54
+ return Object.fromEntries(await Promise.all([...Object.getOwnPropertySymbols(value), ...Object.keys(value)].map(async (key) => [
55
+ key.toString(),
56
+ await serialize(scope, value[key], options),
41
57
  ])));
42
58
  }
43
- if (typeof value === "function") {
59
+ else if (typeof value === "function") {
44
60
  // can't serialize functions
45
61
  return undefined;
46
62
  }
@@ -57,17 +73,37 @@ export async function deserialize(scope, value) {
57
73
  }
58
74
  return new Secret(await decryptWithKey(value["@secret"], scope.password));
59
75
  }
60
- if ("@schema" in value) {
76
+ else if ("@schema" in value) {
61
77
  return value["@schema"];
62
78
  }
63
- if ("@date" in value) {
79
+ else if ("@date" in value) {
64
80
  return new Date(value["@date"]);
65
81
  }
82
+ else if ("@symbol" in value) {
83
+ return parseSymbol(value["@symbol"]);
84
+ }
85
+ else if ("@scope" in value) {
86
+ return scope;
87
+ }
66
88
  return Object.fromEntries(await Promise.all(Object.entries(value).map(async ([key, value]) => [
67
- key,
89
+ parseSymbol(key) ?? key,
68
90
  await deserialize(scope, value),
69
91
  ])));
70
92
  }
71
93
  return value;
72
94
  }
95
+ const symbolPattern = /^Symbol\((.*)\)$/;
96
+ function parseSymbol(value) {
97
+ const match = value.match(symbolPattern);
98
+ if (!match) {
99
+ return undefined;
100
+ }
101
+ return Symbol.for(match[1]);
102
+ }
103
+ function assertNotUniqueSymbol(symbol) {
104
+ if (symbol.description === undefined ||
105
+ symbol !== Symbol.for(symbol.description)) {
106
+ throw new Error(`Cannot serialize unique symbol: ${symbol.description}`);
107
+ }
108
+ }
73
109
  //# sourceMappingURL=serde.js.map
package/lib/serde.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"serde.js","sourceRoot":"","sources":["../src/serde.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serde.js","sourceRoot":"","sources":["../src/serde.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemy",
3
- "version": "0.15.3",
3
+ "version": "0.15.5",
4
4
  "type": "module",
5
5
  "module": "./lib/index.js",
6
6
  "scripts": {
@@ -49,7 +49,11 @@ export type Binding =
49
49
  | VectorizeIndex
50
50
  | Worker
51
51
  | Workflow
52
- | BrowserRendering;
52
+ | BrowserRendering
53
+ | Self;
54
+
55
+ export type Self = typeof Self;
56
+ export const Self = Symbol.for("Self");
53
57
 
54
58
  /**
55
59
  * Union type for all Worker binding types (API spec)
@@ -3,7 +3,7 @@ import type { Secret } from "../secret.js";
3
3
  import type { AiGateway as _AiGateway } from "./ai-gateway.js";
4
4
  import type { Ai as _Ai } from "./ai.js";
5
5
  import type { Assets } from "./assets.js";
6
- import type { Binding } from "./bindings.js";
6
+ import type { Binding, Self } from "./bindings.js";
7
7
  import type { BrowserRendering } from "./browser-rendering.js";
8
8
  import type { R2Bucket as _R2Bucket } from "./bucket.js";
9
9
  import type { D1Database as _D1Database } from "./d1-database.js";
@@ -48,4 +48,6 @@ export type Bound<T extends Binding> = T extends _DurableObjectNamespace
48
48
  ? Fetcher
49
49
  : T extends _Ai<infer M>
50
50
  ? Ai<M>
51
- : Service;
51
+ : T extends Self
52
+ ? Service
53
+ : Service;
@@ -13,7 +13,7 @@ import {
13
13
  createCloudflareApi,
14
14
  } from "./api.js";
15
15
  import type { Assets } from "./assets.js";
16
- import type { Bindings, WorkerBindingSpec } from "./bindings.js";
16
+ import { type Bindings, Self, type WorkerBindingSpec } from "./bindings.js";
17
17
  import type { Bound } from "./bound.js";
18
18
  import { bundleWorkerScript } from "./bundle/bundle-worker.js";
19
19
  import type { DurableObjectNamespace } from "./durable-object-namespace.js";
@@ -207,7 +207,7 @@ export interface WorkerProps<B extends Bindings = Bindings>
207
207
  */
208
208
  export interface Worker<B extends Bindings = Bindings>
209
209
  extends Resource<"cloudflare::Worker">,
210
- Omit<WorkerProps<B>, "url"> {
210
+ Omit<WorkerProps<B>, "url" | "script"> {
211
211
  type: "service";
212
212
 
213
213
  /**
@@ -358,143 +358,182 @@ export const Worker = Resource(
358
358
  id: string,
359
359
  props: WorkerProps<B>,
360
360
  ): Promise<Worker<B>> {
361
- // Create Cloudflare API client with automatic account discovery
362
- const api = await createCloudflareApi(props);
363
-
364
- // Use the provided name
365
- const workerName = props.name ?? id;
366
-
367
361
  // Validate input - we need either script, entryPoint, or bundle
368
362
  if (!props.script && !props.entrypoint) {
369
363
  throw new Error("One of script or entryPoint must be provided");
370
364
  }
371
365
 
372
- if (this.phase === "delete") {
373
- await deleteWorker(this, api, workerName);
374
- return this.destroy();
375
- }
376
- if (this.phase === "create") {
377
- if (!props.adopt) {
378
- await assertWorkerDoesNotExist(this, api, workerName);
379
- }
380
- }
366
+ // Create Cloudflare API client with automatic account discovery
367
+ const api = await createCloudflareApi(props);
368
+
369
+ // Use the provided name
370
+ const workerName = props.name ?? id;
381
371
 
382
372
  const oldBindings = await this.get<Bindings>("bindings");
383
373
 
384
374
  const compatibilityDate = props.compatibilityDate ?? "2025-04-20";
385
375
  const compatibilityFlags = props.compatibilityFlags ?? [];
386
376
 
387
- // Get the script content - either from props.script, or by bundling
388
- const scriptContent =
389
- props.script ??
390
- (await bundleWorkerScript({
391
- ...props,
392
- compatibilityDate,
393
- compatibilityFlags,
394
- }));
395
-
396
- // Find any assets bindings
397
- const assetsBindings: { name: string; assets: Assets }[] = [];
398
- const workflowsBindings: Workflow[] = [];
399
-
400
- if (props.bindings) {
401
- for (const [bindingName, binding] of Object.entries(props.bindings)) {
402
- if (typeof binding === "object") {
403
- if (binding.type === "assets") {
404
- assetsBindings.push({ name: bindingName, assets: binding });
405
- } else if (binding.type === "workflow") {
406
- workflowsBindings.push(binding);
377
+ const uploadWorkerScript = async (props: WorkerProps<B>) => {
378
+ // Get the script content - either from props.script, or by bundling
379
+ const scriptContent =
380
+ props.script ??
381
+ (await bundleWorkerScript({
382
+ ...props,
383
+ compatibilityDate,
384
+ compatibilityFlags,
385
+ }));
386
+
387
+ // Find any assets bindings
388
+ const assetsBindings: { name: string; assets: Assets }[] = [];
389
+ const workflowsBindings: Workflow[] = [];
390
+
391
+ if (props.bindings) {
392
+ for (const [bindingName, binding] of Object.entries(props.bindings)) {
393
+ if (typeof binding === "object") {
394
+ if (binding.type === "assets") {
395
+ assetsBindings.push({ name: bindingName, assets: binding });
396
+ } else if (binding.type === "workflow") {
397
+ workflowsBindings.push(binding);
398
+ }
407
399
  }
408
400
  }
409
401
  }
410
- }
411
402
 
412
- // Upload any assets and get completion tokens
413
- let assetUploadResult: AssetUploadResult | undefined;
414
- if (assetsBindings.length > 0) {
415
- // We'll use the first asset binding for now
416
- // In the future, we might want to support multiple asset bindings
417
- const assetBinding = assetsBindings[0];
403
+ // Upload any assets and get completion tokens
404
+ let assetUploadResult: AssetUploadResult | undefined;
405
+ if (assetsBindings.length > 0) {
406
+ // We'll use the first asset binding for now
407
+ // In the future, we might want to support multiple asset bindings
408
+ const assetBinding = assetsBindings[0];
409
+
410
+ // Upload the assets and get the completion token
411
+ assetUploadResult = await uploadAssets(
412
+ api,
413
+ workerName,
414
+ assetBinding.assets,
415
+ props.assets,
416
+ );
417
+ }
418
+
419
+ // Prepare metadata with bindings
420
+ const scriptMetadata = await prepareWorkerMetadata(
421
+ this,
422
+ oldBindings,
423
+ {
424
+ ...props,
425
+ compatibilityDate,
426
+ compatibilityFlags,
427
+ workerName,
428
+ },
429
+ assetUploadResult,
430
+ );
431
+
432
+ await putWorker(api, workerName, scriptContent, scriptMetadata);
433
+
434
+ for (const workflow of workflowsBindings) {
435
+ await upsertWorkflow(api, {
436
+ workflowName: workflow.workflowName,
437
+ className: workflow.className,
438
+ scriptName: workerName,
439
+ });
440
+ }
441
+
442
+ await Promise.all(
443
+ props.eventSources?.map((eventSource) => {
444
+ if (isQueue(eventSource) || isQueueEventSource(eventSource)) {
445
+ const queue = isQueue(eventSource)
446
+ ? eventSource
447
+ : eventSource.queue;
448
+ return QueueConsumer(`${queue.id}-consumer`, {
449
+ queue,
450
+ scriptName: workerName,
451
+ accountId: api.accountId,
452
+ settings: isQueueEventSource(eventSource)
453
+ ? eventSource.settings
454
+ : undefined,
455
+ });
456
+ }
457
+ throw new Error(`Unsupported event source type: ${eventSource}`);
458
+ }) ?? [],
459
+ );
418
460
 
419
- // Upload the assets and get the completion token
420
- assetUploadResult = await uploadAssets(
461
+ // TODO: it is less than ideal that this can fail, resulting in state problem
462
+ await this.set("bindings", props.bindings);
463
+
464
+ // Handle worker URL if requested
465
+ const workerUrl = await configureURL(
466
+ this,
421
467
  api,
422
468
  workerName,
423
- assetBinding.assets,
424
- props.assets,
469
+ props.url ?? false,
425
470
  );
426
- }
427
471
 
428
- // Prepare metadata with bindings
429
- const scriptMetadata = await prepareWorkerMetadata(
430
- this,
431
- oldBindings,
432
- {
433
- ...props,
434
- compatibilityDate,
435
- compatibilityFlags,
436
- },
437
- assetUploadResult,
438
- );
472
+ // Get current timestamp
473
+ const now = Date.now();
439
474
 
440
- await putWorker(api, workerName, scriptContent, scriptMetadata);
441
-
442
- for (const workflow of workflowsBindings) {
443
- await upsertWorkflow(api, {
444
- workflowName: workflow.workflowName,
445
- className: workflow.className,
446
- scriptName: workerName,
447
- });
448
- }
475
+ // Update cron triggers
476
+ if (props.crons) {
477
+ const res = await api.put(
478
+ `/accounts/${api.accountId}/workers/scripts/${workerName}/schedules`,
479
+ props.crons.map((cron) => ({ cron })),
480
+ );
449
481
 
450
- await Promise.all(
451
- props.eventSources?.map((eventSource) => {
452
- if (isQueue(eventSource) || isQueueEventSource(eventSource)) {
453
- const queue = isQueue(eventSource) ? eventSource : eventSource.queue;
454
- return QueueConsumer(`${queue.id}-consumer`, {
455
- queue,
456
- scriptName: workerName,
457
- accountId: api.accountId,
458
- settings: isQueueEventSource(eventSource)
459
- ? eventSource.settings
460
- : undefined,
461
- });
482
+ if (!res.ok) {
483
+ await handleApiError(
484
+ res,
485
+ "updating cron triggers",
486
+ "worker",
487
+ workerName,
488
+ );
462
489
  }
463
- throw new Error(`Unsupported event source type: ${eventSource}`);
464
- }) ?? [],
465
- );
466
-
467
- // TODO: it is less than ideal that this can fail, resulting in state problem
468
- await this.set("bindings", props.bindings);
490
+ }
469
491
 
470
- // Handle worker URL if requested
471
- const workerUrl = await configureURL(
472
- this,
473
- api,
474
- workerName,
475
- props.url ?? false,
476
- );
492
+ return { scriptMetadata, workerUrl, now };
493
+ };
477
494
 
478
- // Get current timestamp
479
- const now = Date.now();
495
+ if (this.phase === "delete") {
496
+ if (
497
+ Object.values(props.bindings ?? {}).some((binding) => binding === Self)
498
+ ) {
499
+ // remove the Self bindings or else we can't remove (LOL)
500
+ await uploadWorkerScript({
501
+ ...props,
502
+ bindings: Object.fromEntries(
503
+ Object.entries(props.bindings ?? {}).filter(
504
+ ([_, binding]) => binding !== Self,
505
+ ),
506
+ ) as B,
507
+ });
508
+ }
480
509
 
481
- // Update cron triggers
482
- if (props.crons) {
483
- const res = await api.put(
484
- `/accounts/${api.accountId}/workers/scripts/${workerName}/schedules`,
485
- props.crons.map((cron) => ({ cron })),
510
+ await withExponentialBackoff(
511
+ () =>
512
+ deleteWorker(this, api, {
513
+ ...props,
514
+ workerName,
515
+ }),
516
+ (err) =>
517
+ (err.status === 400 &&
518
+ err.message.includes(
519
+ "is still referenced by service bindings in Workers",
520
+ )) ||
521
+ err.status === 500 ||
522
+ err.status === 503,
523
+ 10,
524
+ 100,
486
525
  );
487
526
 
488
- if (!res.ok) {
489
- await handleApiError(
490
- res,
491
- "updating cron triggers",
492
- "worker",
493
- workerName,
494
- );
527
+ return this.destroy();
528
+ }
529
+ if (this.phase === "create") {
530
+ if (!props.adopt) {
531
+ await assertWorkerDoesNotExist(this, api, workerName);
495
532
  }
496
533
  }
497
534
 
535
+ const { scriptMetadata, workerUrl, now } = await uploadWorkerScript(props);
536
+
498
537
  // Construct the output
499
538
  return this({
500
539
  ...props,
@@ -504,7 +543,6 @@ export const Worker = Resource(
504
543
  name: workerName,
505
544
  compatibilityDate,
506
545
  compatibilityFlags,
507
- script: scriptContent,
508
546
  format: props.format || "esm", // Include format in the output
509
547
  bindings: props.bindings ?? ({} as B),
510
548
  env: props.env,
@@ -526,8 +564,9 @@ export const Worker = Resource(
526
564
  async function deleteWorker<B extends Bindings>(
527
565
  ctx: Context<Worker<B>>,
528
566
  api: CloudflareApi,
529
- workerName: string,
567
+ props: WorkerProps<B> & { workerName: string },
530
568
  ) {
569
+ const workerName = props.workerName;
531
570
  // Delete any queue consumers attached to this worker first
532
571
  await deleteQueueConsumers(ctx, api, workerName);
533
572
 
@@ -538,13 +577,7 @@ async function deleteWorker<B extends Bindings>(
538
577
 
539
578
  // Check for success (2xx status code)
540
579
  if (!deleteResponse.ok && deleteResponse.status !== 404) {
541
- const errorData: any = await deleteResponse
542
- .json()
543
- .catch(() => ({ errors: [{ message: deleteResponse.statusText }] }));
544
- console.error(
545
- "Error deleting worker:",
546
- errorData.errors?.[0]?.message || deleteResponse.statusText,
547
- );
580
+ await handleApiError(deleteResponse, "delete", "worker", workerName);
548
581
  }
549
582
 
550
583
  // Disable the URL if it was enabled
@@ -698,6 +731,7 @@ async function prepareWorkerMetadata<B extends Bindings>(
698
731
  props: WorkerProps & {
699
732
  compatibilityDate: string;
700
733
  compatibilityFlags: string[];
734
+ workerName: string;
701
735
  },
702
736
  assetUploadResult?: AssetUploadResult,
703
737
  ): Promise<WorkerMetadata> {
@@ -752,6 +786,12 @@ async function prepareWorkerMetadata<B extends Bindings>(
752
786
  name: bindingName,
753
787
  text: binding,
754
788
  });
789
+ } else if (binding === Self) {
790
+ meta.bindings.push({
791
+ type: "service",
792
+ name: bindingName,
793
+ service: props.workerName,
794
+ });
755
795
  } else if (binding.type === "d1") {
756
796
  meta.bindings.push({
757
797
  type: "d1",
@@ -807,7 +847,7 @@ async function prepareWorkerMetadata<B extends Bindings>(
807
847
  // script_name: ??,
808
848
  });
809
849
  // it's unclear whether this is needed, but it works both ways
810
- configureClassMigration(binding, binding.id, binding.className);
850
+ // configureClassMigration(binding, binding.id, binding.className);
811
851
  } else if (binding.type === "queue") {
812
852
  meta.bindings.push({
813
853
  type: "queue",
@@ -1,7 +1,7 @@
1
1
  import type { Context } from "../context.js";
2
2
  import { StaticJsonFile } from "../fs/static-json-file.js";
3
3
  import { Resource } from "../resource.js";
4
- import type { Bindings } from "./bindings.js";
4
+ import { Self, type Bindings } from "./bindings.js";
5
5
  import type { DurableObjectNamespace } from "./durable-object-namespace.js";
6
6
  import type { EventSource } from "./event-source.js";
7
7
  import { isQueueEventSource } from "./event-source.js";
@@ -95,7 +95,7 @@ export const WranglerJson = Resource(
95
95
 
96
96
  // Process bindings if they exist
97
97
  if (worker.bindings) {
98
- processBindings(spec, worker.bindings, worker.eventSources);
98
+ processBindings(spec, worker.bindings, worker.eventSources, worker.name);
99
99
  }
100
100
 
101
101
  // Add environment variables as vars
@@ -170,6 +170,10 @@ export interface WranglerJsonSpec {
170
170
  kv_namespaces?: {
171
171
  binding: string;
172
172
  id: string;
173
+ /**
174
+ * The ID of the KV namespace used during `wrangler dev`
175
+ */
176
+ preview_id?: string;
173
177
  }[];
174
178
 
175
179
  /**
@@ -190,6 +194,10 @@ export interface WranglerJsonSpec {
190
194
  r2_buckets?: {
191
195
  binding: string;
192
196
  bucket_name: string;
197
+ /**
198
+ * The preview name of this R2 bucket at the edge.
199
+ */
200
+ preview_bucket_name?: string;
193
201
  }[];
194
202
 
195
203
  /**
@@ -246,6 +254,10 @@ export interface WranglerJsonSpec {
246
254
  database_id: string;
247
255
  database_name: string;
248
256
  migrations_dir?: string;
257
+ /**
258
+ * The ID of the D1 database used during `wrangler dev`
259
+ */
260
+ preview_database_id?: string;
249
261
  }[];
250
262
 
251
263
  /**
@@ -279,6 +291,7 @@ function processBindings(
279
291
  spec: WranglerJsonSpec,
280
292
  bindings: Bindings,
281
293
  eventSources: EventSource[] | undefined,
294
+ workerName: string,
282
295
  ): void {
283
296
  // Arrays to collect different binding types
284
297
  const kvNamespaces: { binding: string; id: string }[] = [];
@@ -340,6 +353,18 @@ function processBindings(
340
353
  spec.vars = {};
341
354
  }
342
355
  spec.vars[bindingName] = binding;
356
+ } else if (binding === Self) {
357
+ // Self(service) binding
358
+ services.push({
359
+ binding: bindingName,
360
+ service: workerName,
361
+ });
362
+ } else if (binding.type === "service") {
363
+ // Service binding
364
+ services.push({
365
+ binding: bindingName,
366
+ service: binding.id,
367
+ });
343
368
  } else if (binding.type === "kv_namespace") {
344
369
  // KV Namespace binding
345
370
  kvNamespaces.push({
@@ -363,12 +388,6 @@ function processBindings(
363
388
  binding: bindingName,
364
389
  bucket_name: binding.name,
365
390
  });
366
- } else if (binding.type === "service") {
367
- // Service binding
368
- services.push({
369
- binding: bindingName,
370
- service: binding.id,
371
- });
372
391
  } else if (binding.type === "secret") {
373
392
  // Secret binding
374
393
  secrets.push(bindingName);