alchemy 2.0.0-beta.3 → 2.0.0-beta.4

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 (67) hide show
  1. package/bin/{alchemy-effect.js → alchemy.js} +170 -170
  2. package/bin/alchemy.js.map +1 -0
  3. package/bin/{alchemy-effect.sh → alchemy.sh} +2 -2
  4. package/lib/cli/index.d.ts.map +1 -1
  5. package/lib/cli/index.js +167 -167
  6. package/lib/cli/index.js.map +1 -1
  7. package/package.json +38 -38
  8. package/src/AWS/AGENTS.md +10 -10
  9. package/src/AWS/Assets.ts +1 -1
  10. package/src/AWS/AuthProvider.ts +392 -0
  11. package/src/AWS/Credentials.ts +0 -1
  12. package/src/AWS/DynamoDB/Table.ts +63 -10
  13. package/src/AWS/EC2/VpcEndpoint.ts +4 -4
  14. package/src/AWS/EC2/hosted.ts +1 -1
  15. package/src/AWS/ECS/Task.ts +1 -1
  16. package/src/AWS/Kinesis/Stream.ts +44 -8
  17. package/src/AWS/Lambda/Function.ts +218 -10
  18. package/src/AWS/S3/Bucket.ts +26 -19
  19. package/src/AWS/S3/BucketNotifications.ts +1 -1
  20. package/src/AWS/SNS/Topic.ts +47 -10
  21. package/src/AWS/SQS/Queue.ts +66 -0
  22. package/src/Auth/AuthProvider.ts +33 -0
  23. package/src/Auth/Credentials.ts +56 -0
  24. package/src/Auth/Env.ts +45 -0
  25. package/src/Auth/Profile.ts +72 -0
  26. package/src/Auth/index.ts +2 -0
  27. package/src/Cloudflare/Auth/AuthProvider.ts +670 -0
  28. package/src/Cloudflare/Auth/OAuthClient.ts +315 -0
  29. package/src/Cloudflare/Container/ContainerApplication.ts +3 -3
  30. package/src/Cloudflare/Container/ContainerBinding.ts +2 -4
  31. package/src/Cloudflare/Container/StartContainer.ts +1 -1
  32. package/src/Cloudflare/Providers.ts +1 -6
  33. package/src/Cloudflare/R2/R2Bucket.ts +2 -2
  34. package/src/Cloudflare/Website/StaticSite.ts +44 -15
  35. package/src/Cloudflare/Website/Vite.ts +34 -12
  36. package/src/Cloudflare/Workers/Assets.ts +170 -207
  37. package/src/Cloudflare/Workers/DurableObjectNamespace.ts +230 -370
  38. package/src/Cloudflare/Workers/DurableObjectState.ts +63 -0
  39. package/src/Cloudflare/Workers/DurableObjectStorage.ts +256 -0
  40. package/src/Cloudflare/Workers/InferEnv.ts +11 -7
  41. package/src/Cloudflare/Workers/Rpc.ts +13 -2
  42. package/src/Cloudflare/Workers/ScheduledEvents.ts +185 -0
  43. package/src/Cloudflare/Workers/WebSocket.ts +1 -1
  44. package/src/Cloudflare/Workers/Worker.ts +261 -61
  45. package/src/Cloudflare/Workers/index.ts +3 -0
  46. package/src/Construct.ts +2 -2
  47. package/src/GitHub/Secret.ts +52 -7
  48. package/src/GitHub/Variable.ts +45 -2
  49. package/src/Kubernetes/client.ts +2 -2
  50. package/src/Output.ts +1 -1
  51. package/src/Platform.ts +10 -5
  52. package/src/Resource.ts +4 -4
  53. package/src/Test/Vitest.ts +4 -3
  54. package/src/Util/Clank.ts +77 -0
  55. package/src/Util/PlatformServices.ts +21 -0
  56. package/src/Util/dedent.ts +4 -1
  57. package/bin/alchemy-effect.js.map +0 -1
  58. package/src/Daemon/Client.ts +0 -116
  59. package/src/Daemon/Config.ts +0 -28
  60. package/src/Daemon/Errors.ts +0 -48
  61. package/src/Daemon/Lock.ts +0 -162
  62. package/src/Daemon/ProcessRegistry.ts +0 -284
  63. package/src/Daemon/RpcSchema.ts +0 -43
  64. package/src/Daemon/RpcServer.ts +0 -231
  65. package/src/Daemon/index.ts +0 -27
  66. package/src/Spawn.ts +0 -23
  67. /package/bin/{alchemy-effect.ts → alchemy.ts} +0 -0
@@ -9,8 +9,12 @@ import type { HttpEffect } from "../../Http.ts";
9
9
  import * as Output from "../../Output.ts";
10
10
  import type { PlatformServices } from "../../Platform.ts";
11
11
  import { effectClass, taggedFunction } from "../../Util/effect.ts";
12
+ import {
13
+ DurableObjectState,
14
+ fromDurableObjectState,
15
+ } from "./DurableObjectState.ts";
12
16
  import { makeRpcStub } from "./Rpc.ts";
13
- import { fromWebSocket, type DurableWebSocket } from "./WebSocket.ts";
17
+ import { type DurableWebSocket } from "./WebSocket.ts";
14
18
  import { Worker, WorkerEnvironment, type WorkerServices } from "./Worker.ts";
15
19
 
16
20
  export interface DurableObjectExport {
@@ -39,7 +43,26 @@ export type AlarmInvocationInfo = cf.AlarmInvocationInfo;
39
43
  type TypeId = "Cloudflare.DurableObjectNamespace";
40
44
  const TypeId = "Cloudflare.DurableObjectNamespace";
41
45
 
42
- export interface DurableObjectNamespace<Shape = unknown> {
46
+ export const isDurableObjectNamespaceLike = (
47
+ value: unknown,
48
+ ): value is DurableObjectNamespaceLike =>
49
+ typeof value === "object" &&
50
+ value !== null &&
51
+ "kind" in value &&
52
+ value.kind === TypeId;
53
+
54
+ export interface DurableObjectNamespaceLike<Shape = any> {
55
+ kind: TypeId;
56
+ name: string;
57
+ /** @internal phantom */
58
+ className?: string;
59
+ /** @internal phantom */
60
+ Shape?: Shape;
61
+ }
62
+
63
+ export interface DurableObjectNamespace<
64
+ Shape = unknown,
65
+ > extends DurableObjectNamespaceLike<Shape> {
43
66
  Type: TypeId;
44
67
  name: string;
45
68
  namespaceId: Output.Output<string>;
@@ -63,7 +86,7 @@ export interface DurableObjectShape {
63
86
  ) => Effect.Effect<void, never, never>;
64
87
  webSocketMessage?: (
65
88
  socket: DurableWebSocket,
66
- message: string | Uint8Array,
89
+ message: string | ArrayBuffer,
67
90
  ) => Effect.Effect<void>;
68
91
  webSocketClose?: (
69
92
  socket: DurableWebSocket,
@@ -79,6 +102,17 @@ export type DurableObjectServices =
79
102
  | WorkerServices
80
103
  | PlatformServices;
81
104
 
105
+ export interface DurableObjectNamespaceProps {
106
+ /**
107
+ * @default name
108
+ */
109
+ className: string;
110
+ // scriptName?: string | undefined;
111
+ // environment?: string | undefined;
112
+ // sqlite?: boolean | undefined;
113
+ // namespaceId?: string | undefined;
114
+ }
115
+
82
116
  export interface DurableObjectNamespaceClass extends Effect.Effect<
83
117
  DurableObjectNamespace,
84
118
  never,
@@ -100,6 +134,10 @@ export interface DurableObjectNamespaceClass extends Effect.Effect<
100
134
  new (_: never): Shape;
101
135
  };
102
136
  };
137
+ <Shape>(
138
+ name: string,
139
+ props?: DurableObjectNamespaceProps,
140
+ ): DurableObjectNamespaceLike<Shape>;
103
141
  <Shape, InitReq = never>(
104
142
  name: string,
105
143
  impl: Effect.Effect<
@@ -360,11 +398,59 @@ export class DurableObjectNamespaceScope extends Context.Service<
360
398
  * }),
361
399
  * };
362
400
  * ```
401
+ *
402
+ * @section Binding in an Async Worker
403
+ * When using an Async Worker (plain `async fetch` handler, no Effect
404
+ * runtime), declare Durable Objects in the `bindings` prop of the
405
+ * Worker resource. Pass a `DurableObjectNamespace` reference with a
406
+ * `className` matching the exported `DurableObject` subclass in your
407
+ * worker source file. Use `Cloudflare.InferEnv` to get a fully typed
408
+ * `env` object that includes the namespace.
409
+ *
410
+ * @example Declaring a DO binding in the stack
411
+ * ```typescript
412
+ * // alchemy.run.ts
413
+ * import type { Counter } from "./src/worker.ts";
414
+ *
415
+ * export type WorkerEnv = Cloudflare.InferEnv<typeof Worker>;
416
+ *
417
+ * export const Worker = Cloudflare.Worker("Worker", {
418
+ * main: "./src/worker.ts",
419
+ * bindings: {
420
+ * Counter: Cloudflare.DurableObjectNamespace<Counter>("Counter", {
421
+ * className: "Counter",
422
+ * }),
423
+ * },
424
+ * });
425
+ * ```
426
+ *
427
+ * @example Using the DO from a plain async handler
428
+ * ```typescript
429
+ * // src/worker.ts
430
+ * import { DurableObject } from "cloudflare:workers";
431
+ * import type { WorkerEnv } from "../alchemy.run.ts";
432
+ *
433
+ * export default {
434
+ * async fetch(request: Request, env: WorkerEnv) {
435
+ * const counter = env.Counter.getByName("my-counter");
436
+ * const count = await counter.increment();
437
+ * return new Response(JSON.stringify({ count }));
438
+ * },
439
+ * };
440
+ *
441
+ * export class Counter extends DurableObject {
442
+ * private counter = 0;
443
+ * async increment() {
444
+ * return ++this.counter;
445
+ * }
446
+ * }
447
+ * ```
363
448
  */
364
449
  export const DurableObjectNamespace: DurableObjectNamespaceClass =
365
450
  taggedFunction(DurableObjectNamespaceScope, ((
366
451
  ...args:
367
452
  | []
453
+ | [name: string, props?: DurableObjectNamespaceProps]
368
454
  | [
369
455
  name: string,
370
456
  impl: Effect.Effect<
@@ -378,137 +464,156 @@ export const DurableObjectNamespace: DurableObjectNamespaceClass =
378
464
  ) =>
379
465
  args.length === 0
380
466
  ? DurableObjectNamespace
381
- : effectClass(
382
- Effect.gen(function* () {
383
- const [namespace, impl] = args;
384
- const worker = yield* Worker;
467
+ : !Effect.isEffect(args[1])
468
+ ? ({
469
+ kind: TypeId,
470
+ name: args[0],
471
+ className: (args[1] as DurableObjectNamespaceProps | undefined)
472
+ ?.className,
473
+ } satisfies DurableObjectNamespaceLike<any>)
474
+ : effectClass(
475
+ Effect.gen(function* () {
476
+ const [namespace, impl] = args as any as [
477
+ name: string,
478
+ impl: Effect.Effect<
479
+ Effect.Effect<
480
+ DurableObjectNamespace<any>,
481
+ never,
482
+ DurableObjectState
483
+ >
484
+ >,
485
+ ];
486
+ const worker = yield* Worker;
385
487
 
386
- yield* worker.bind`${namespace}`({
387
- // TODO(sam): automate class migrations, probably in the provider
388
- bindings: [
389
- {
390
- type: "durable_object_namespace",
391
- name: namespace,
392
- className: namespace,
393
- // scriptName:
394
- // binding.scriptName === props.workerName
395
- // ? undefined
396
- // : binding.scriptName,
397
- // environment: binding.environment,
398
- // namespaceId: binding.namespaceId,
399
- },
400
- ],
401
- });
488
+ yield* worker.bind`${namespace}`({
489
+ // TODO(sam): automate class migrations, probably in the provider
490
+ bindings: [
491
+ {
492
+ type: "durable_object_namespace",
493
+ name: namespace,
494
+ className: namespace,
495
+ // scriptName:
496
+ // binding.scriptName === props.workerName
497
+ // ? undefined
498
+ // : binding.scriptName,
499
+ // environment: binding.environment,
500
+ // namespaceId: binding.namespaceId,
501
+ },
502
+ ],
503
+ });
402
504
 
403
- const services =
404
- yield* Effect.context<Effect.Services<typeof impl>>();
505
+ const services =
506
+ yield* Effect.context<Effect.Services<typeof impl>>();
405
507
 
406
- yield* worker.export(namespace, {
407
- kind: "durableObject",
408
- make: (state: cf.DurableObjectState, env: any) => {
409
- const doState = fromDurableObjectState(state);
410
- return constructor.pipe(
411
- Effect.provideContext(services),
412
- Effect.provideService(DurableObjectState, doState),
413
- Effect.provideService(WorkerEnvironment, env),
414
- Effect.map((methods: any) => {
415
- console.log(
416
- "[DurableObject] wrapping methods:",
417
- Object.keys(methods),
418
- "own:",
419
- Object.getOwnPropertyNames(methods),
420
- );
421
- const wrapped: Record<string, unknown> = {};
422
- for (const key of Object.getOwnPropertyNames(methods)) {
423
- const value = methods[key];
424
- if (Effect.isEffect(value)) {
425
- wrapped[key] = (
426
- value as Effect.Effect<any, any, any>
427
- ).pipe(
428
- Effect.provideService(DurableObjectState, doState),
429
- );
430
- } else if (typeof value === "function") {
431
- wrapped[key] = (...args: unknown[]) => {
432
- const result = (value as Function)(...args);
433
- if (Effect.isEffect(result)) {
434
- return (
435
- result as Effect.Effect<any, any, any>
436
- ).pipe(
437
- Effect.provideService(
438
- DurableObjectState,
439
- doState,
440
- ),
441
- );
442
- }
443
- return result;
444
- };
445
- } else {
446
- wrapped[key] = value;
508
+ yield* worker.export(namespace, {
509
+ kind: "durableObject",
510
+ make: (state: cf.DurableObjectState, env: any) => {
511
+ const doState = fromDurableObjectState(state);
512
+ return constructor.pipe(
513
+ Effect.provideContext(services),
514
+ Effect.provideService(DurableObjectState, doState),
515
+ Effect.provideService(WorkerEnvironment, env),
516
+ Effect.map((methods: any) => {
517
+ console.log(
518
+ "[DurableObject] wrapping methods:",
519
+ Object.keys(methods),
520
+ "own:",
521
+ Object.getOwnPropertyNames(methods),
522
+ );
523
+ const wrapped: Record<string, unknown> = {};
524
+ for (const key of Object.getOwnPropertyNames(methods)) {
525
+ const value = methods[key];
526
+ if (Effect.isEffect(value)) {
527
+ wrapped[key] = (
528
+ value as Effect.Effect<any, any, any>
529
+ ).pipe(
530
+ Effect.provideService(DurableObjectState, doState),
531
+ );
532
+ } else if (typeof value === "function") {
533
+ wrapped[key] = (...args: unknown[]) => {
534
+ const result = (value as Function)(...args);
535
+ if (Effect.isEffect(result)) {
536
+ return (
537
+ result as Effect.Effect<any, any, any>
538
+ ).pipe(
539
+ Effect.provideService(
540
+ DurableObjectState,
541
+ doState,
542
+ ),
543
+ );
544
+ }
545
+ return result;
546
+ };
547
+ } else {
548
+ wrapped[key] = value;
549
+ }
447
550
  }
448
- }
449
- return wrapped;
450
- }),
451
- );
452
- },
453
- } satisfies DurableObjectExport);
454
-
455
- const binding = yield* Effect.serviceOption(WorkerEnvironment).pipe(
456
- Effect.map(Option.getOrUndefined),
457
- Effect.flatMap((env) => {
458
- if (env === undefined) {
459
- // should be fine to return undefined here (it is only undefined at plantime)
460
- return Effect.succeed(undefined);
461
- }
462
- const ns = env[namespace];
463
- if (!ns) {
464
- return Effect.die(
465
- new Error(
466
- `DurableObjectNamespace '${namespace}' not found`,
467
- ),
551
+ return wrapped;
552
+ }),
468
553
  );
469
- } else if (typeof ns.getByName === "function") {
470
- return Effect.succeed(ns);
471
- } else {
472
- return Effect.die(
473
- new Error(
474
- `DurableObjectNamespace '${namespace}' is not a DurableObjectNamespace`,
475
- ),
476
- );
477
- }
478
- }),
479
- );
554
+ },
555
+ } satisfies DurableObjectExport);
480
556
 
481
- const namespaceId = worker.durableObjectNamespaces.pipe(
482
- Output.map(
483
- (durableObjectNamespaces) =>
484
- durableObjectNamespaces?.[namespace],
485
- ),
486
- );
557
+ const binding = yield* Effect.serviceOption(
558
+ WorkerEnvironment,
559
+ ).pipe(
560
+ Effect.map(Option.getOrUndefined),
561
+ Effect.flatMap((env) => {
562
+ if (env === undefined) {
563
+ // should be fine to return undefined here (it is only undefined at plantime)
564
+ return Effect.succeed(undefined);
565
+ }
566
+ const ns = env[namespace];
567
+ if (!ns) {
568
+ return Effect.die(
569
+ new Error(
570
+ `DurableObjectNamespace '${namespace}' not found`,
571
+ ),
572
+ );
573
+ } else if (typeof ns.getByName === "function") {
574
+ return Effect.succeed(ns);
575
+ } else {
576
+ return Effect.die(
577
+ new Error(
578
+ `DurableObjectNamespace '${namespace}' is not a DurableObjectNamespace`,
579
+ ),
580
+ );
581
+ }
582
+ }),
583
+ );
584
+
585
+ const namespaceId = worker.durableObjectNamespaces.pipe(
586
+ Output.map(
587
+ (durableObjectNamespaces) =>
588
+ durableObjectNamespaces?.[namespace],
589
+ ),
590
+ );
487
591
 
488
- const self = {
489
- Type: TypeId,
490
- LogicalId: namespace,
491
- name: namespace,
492
- namespaceId,
493
- getByName: (name: string) => makeRpcStub(binding.getByName(name)),
494
- // newUniqueId: () => use((ns) => ns.newUniqueId()),
495
- // idFromName: (name: string) => use((ns) => ns.idFromName(name)),
496
- // idFromString: (id: string) => use((ns) => ns.idFromString(id)),
497
- // get: (
498
- // id: cf.DurableObjectId,
499
- // options?: cf.DurableObjectNamespaceGetDurableObjectOptions,
500
- // ) => use((ns) => makeRpcStub(ns.get(id, options))),
501
- // jurisdiction: (jurisdiction: cf.DurableObjectJurisdiction) =>
502
- // use((ns) => ns.jurisdiction(jurisdiction) as any),
503
- };
592
+ const self = {
593
+ Type: TypeId,
594
+ LogicalId: namespace,
595
+ name: namespace,
596
+ namespaceId,
597
+ getByName: (name: string) =>
598
+ makeRpcStub(binding.getByName(name)),
599
+ // newUniqueId: () => use((ns) => ns.newUniqueId()),
600
+ // idFromName: (name: string) => use((ns) => ns.idFromName(name)),
601
+ // idFromString: (id: string) => use((ns) => ns.idFromString(id)),
602
+ // get: (
603
+ // id: cf.DurableObjectId,
604
+ // options?: cf.DurableObjectNamespaceGetDurableObjectOptions,
605
+ // ) => use((ns) => makeRpcStub(ns.get(id, options))),
606
+ // jurisdiction: (jurisdiction: cf.DurableObjectJurisdiction) =>
607
+ // use((ns) => ns.jurisdiction(jurisdiction) as any),
608
+ };
504
609
 
505
- const constructor = yield* impl.pipe(
506
- Effect.provideService(DurableObjectNamespaceScope, self as any),
507
- );
610
+ const constructor = yield* impl.pipe(
611
+ Effect.provideService(DurableObjectNamespaceScope, self as any),
612
+ );
508
613
 
509
- return self;
510
- }),
511
- )) as any);
614
+ return self;
615
+ }),
616
+ )) as any);
512
617
 
513
618
  export type DurableObjectStub<Shape> = {
514
619
  // TODO(sam): do we need to transform? hopefully not
@@ -522,248 +627,3 @@ export type DurableObjectStub<Shape> = {
522
627
  never
523
628
  >;
524
629
  };
525
-
526
- export class DurableObjectState extends Context.Service<
527
- DurableObjectState,
528
- {
529
- // TODO(sam): is this needed when we have Effect?
530
- // waitUntil(promise: Promise<any>): Effect.Effect<void>;
531
-
532
- // TODO(sam): what are these? Where do they come from?
533
- // readonly props: Props;
534
-
535
- readonly id: cf.DurableObjectId;
536
- readonly storage: DurableObjectStorage;
537
- // TODO(sam): effect-native interface for container
538
- container?: cf.Container;
539
- blockConcurrencyWhile<T>(
540
- callback: () => Effect.Effect<T>,
541
- ): Effect.Effect<T>;
542
- acceptWebSocket(ws: DurableWebSocket, tags?: string[]): Effect.Effect<void>;
543
- getWebSockets(tag?: string): Effect.Effect<DurableWebSocket[]>;
544
- setWebSocketAutoResponse(
545
- maybeReqResp?: cf.WebSocketRequestResponsePair,
546
- ): Effect.Effect<void>;
547
- getWebSocketAutoResponse(): Effect.Effect<cf.WebSocketRequestResponsePair | null>;
548
- getWebSocketAutoResponseTimestamp(
549
- ws: cf.WebSocket,
550
- ): Effect.Effect<Date | null>;
551
- setHibernatableWebSocketEventTimeout(
552
- timeoutMs?: number,
553
- ): Effect.Effect<void>;
554
- getHibernatableWebSocketEventTimeout(): Effect.Effect<number | null>;
555
- getTags(ws: cf.WebSocket): Effect.Effect<string[]>;
556
- abort(reason?: string): Effect.Effect<void>;
557
- }
558
- >()("Cloudflare.DurableObjectState") {}
559
-
560
- export interface DurableObjectTransaction {
561
- get<T = unknown>(
562
- key: string,
563
- options?: cf.DurableObjectGetOptions,
564
- ): Effect.Effect<T | undefined>;
565
- get<T = unknown>(
566
- keys: string[],
567
- options?: cf.DurableObjectGetOptions,
568
- ): Effect.Effect<Map<string, T>>;
569
- list<T = unknown>(
570
- options?: cf.DurableObjectListOptions,
571
- ): Effect.Effect<Map<string, T>>;
572
- put<T>(
573
- key: string,
574
- value: T,
575
- options?: cf.DurableObjectPutOptions,
576
- ): Effect.Effect<void>;
577
- put<T>(
578
- entries: Record<string, T>,
579
- options?: cf.DurableObjectPutOptions,
580
- ): Effect.Effect<void>;
581
- delete(
582
- key: string,
583
- options?: cf.DurableObjectPutOptions,
584
- ): Effect.Effect<boolean>;
585
- delete(
586
- keys: string[],
587
- options?: cf.DurableObjectPutOptions,
588
- ): Effect.Effect<number>;
589
- rollback(): Effect.Effect<void>;
590
- getAlarm(
591
- options?: cf.DurableObjectGetAlarmOptions,
592
- ): Effect.Effect<number | null>;
593
- setAlarm(
594
- scheduledTime: number | Date,
595
- options?: cf.DurableObjectSetAlarmOptions,
596
- ): Effect.Effect<void>;
597
- deleteAlarm(options?: cf.DurableObjectSetAlarmOptions): Effect.Effect<void>;
598
- }
599
- export interface DurableObjectStorage {
600
- get<T = unknown>(
601
- key: string,
602
- options?: cf.DurableObjectGetOptions,
603
- ): Effect.Effect<T | undefined>;
604
- get<T = unknown>(
605
- keys: string[],
606
- options?: cf.DurableObjectGetOptions,
607
- ): Effect.Effect<Map<string, T>>;
608
- list<T = unknown>(
609
- options?: cf.DurableObjectListOptions,
610
- ): Effect.Effect<Map<string, T>>;
611
- put<T>(
612
- key: string,
613
- value: T,
614
- options?: cf.DurableObjectPutOptions,
615
- ): Effect.Effect<void>;
616
- put<T>(
617
- entries: Record<string, T>,
618
- options?: cf.DurableObjectPutOptions,
619
- ): Effect.Effect<void>;
620
- delete(
621
- key: string,
622
- options?: cf.DurableObjectPutOptions,
623
- ): Effect.Effect<boolean>;
624
- delete(
625
- keys: string[],
626
- options?: cf.DurableObjectPutOptions,
627
- ): Effect.Effect<number>;
628
- deleteAll(options?: cf.DurableObjectPutOptions): Effect.Effect<void>;
629
- transaction<T>(
630
- closure: (txn: DurableObjectTransaction) => Effect.Effect<T>,
631
- ): Effect.Effect<T>;
632
- getAlarm(
633
- options?: cf.DurableObjectGetAlarmOptions,
634
- ): Effect.Effect<number | null>;
635
- setAlarm(
636
- scheduledTime: number | Date,
637
- options?: cf.DurableObjectSetAlarmOptions,
638
- ): Effect.Effect<void>;
639
- deleteAlarm(options?: cf.DurableObjectSetAlarmOptions): Effect.Effect<void>;
640
- sync(): Effect.Effect<void>;
641
- sql: cf.SqlStorage;
642
- kv: cf.SyncKvStorage;
643
- transactionSync<T>(closure: () => T): T;
644
- getCurrentBookmark(): Effect.Effect<string>;
645
- getBookmarkForTime(timestamp: number | Date): Effect.Effect<string>;
646
- onNextSessionRestoreBookmark(bookmark: string): Effect.Effect<string>;
647
- }
648
-
649
- const fromDurableObjectState = (
650
- state: cf.DurableObjectState,
651
- ): DurableObjectState["Service"] => ({
652
- id: state.id,
653
- container: state.container,
654
- storage: fromDurableObjectStorage(state.storage),
655
- blockConcurrencyWhile: <T>(callback: () => Effect.Effect<T>) =>
656
- Effect.tryPromise(() =>
657
- state.blockConcurrencyWhile(() => Effect.runPromise(callback())),
658
- ),
659
- acceptWebSocket: (ws: DurableWebSocket, tags?: string[]) =>
660
- Effect.sync(() => state.acceptWebSocket(ws.ws, tags)),
661
- getWebSockets: (tag?: string) =>
662
- Effect.sync(() => state.getWebSockets(tag).map(fromWebSocket)),
663
- setWebSocketAutoResponse: (maybeReqResp?: cf.WebSocketRequestResponsePair) =>
664
- Effect.sync(() => state.setWebSocketAutoResponse(maybeReqResp)),
665
- getWebSocketAutoResponse: () =>
666
- Effect.sync(() => state.getWebSocketAutoResponse()),
667
- getWebSocketAutoResponseTimestamp: (ws: cf.WebSocket) =>
668
- Effect.sync(() => state.getWebSocketAutoResponseTimestamp(ws)),
669
- setHibernatableWebSocketEventTimeout: (timeoutMs?: number) =>
670
- Effect.sync(() => state.setHibernatableWebSocketEventTimeout(timeoutMs)),
671
- getHibernatableWebSocketEventTimeout: () =>
672
- Effect.sync(() => state.getHibernatableWebSocketEventTimeout()),
673
- getTags: (ws: cf.WebSocket) => Effect.sync(() => state.getTags(ws)),
674
- abort: (reason?: string) => Effect.sync(() => state.abort(reason)),
675
- });
676
-
677
- const fromDurableObjectTransaction = (
678
- txn: cf.DurableObjectTransaction,
679
- ): DurableObjectTransaction => ({
680
- get: ((keyOrKeys: string | string[], options?: cf.DurableObjectGetOptions) =>
681
- Effect.tryPromise(() => txn.get(keyOrKeys as any, options))) as any,
682
- list: (options?: cf.DurableObjectListOptions) =>
683
- Effect.tryPromise(() => txn.list(options)),
684
- put: ((
685
- keyOrEntries: string | Record<string, unknown>,
686
- valueOrOptions?: unknown,
687
- maybeOptions?: cf.DurableObjectPutOptions,
688
- ) =>
689
- typeof keyOrEntries === "string"
690
- ? Effect.tryPromise(() =>
691
- txn.put(keyOrEntries, valueOrOptions, maybeOptions),
692
- )
693
- : Effect.tryPromise(() =>
694
- txn.put(
695
- keyOrEntries,
696
- valueOrOptions as cf.DurableObjectPutOptions | undefined,
697
- ),
698
- )) as any,
699
- delete: ((
700
- keyOrKeys: string | string[],
701
- options?: cf.DurableObjectPutOptions,
702
- ) => Effect.tryPromise(() => txn.delete(keyOrKeys as any, options))) as any,
703
- rollback: () => Effect.sync(() => txn.rollback()),
704
- getAlarm: (options?: cf.DurableObjectGetAlarmOptions) =>
705
- Effect.tryPromise(() => txn.getAlarm(options)),
706
- setAlarm: (
707
- scheduledTime: number | Date,
708
- options?: cf.DurableObjectSetAlarmOptions,
709
- ) => Effect.tryPromise(() => txn.setAlarm(scheduledTime, options)),
710
- deleteAlarm: (options?: cf.DurableObjectSetAlarmOptions) =>
711
- Effect.tryPromise(() => txn.deleteAlarm(options)),
712
- });
713
-
714
- const fromDurableObjectStorage = (
715
- storage: cf.DurableObjectStorage,
716
- ): DurableObjectStorage => ({
717
- get: ((keyOrKeys: string | string[], options?: cf.DurableObjectGetOptions) =>
718
- Effect.tryPromise(() => storage.get(keyOrKeys as any, options))) as any,
719
- list: (options?: cf.DurableObjectListOptions) =>
720
- Effect.tryPromise(() => storage.list(options)),
721
- put: ((
722
- keyOrEntries: string | Record<string, unknown>,
723
- valueOrOptions?: unknown,
724
- maybeOptions?: cf.DurableObjectPutOptions,
725
- ) =>
726
- typeof keyOrEntries === "string"
727
- ? Effect.tryPromise(() =>
728
- storage.put(keyOrEntries, valueOrOptions, maybeOptions),
729
- )
730
- : Effect.tryPromise(() =>
731
- storage.put(
732
- keyOrEntries,
733
- valueOrOptions as cf.DurableObjectPutOptions | undefined,
734
- ),
735
- )) as any,
736
- delete: ((
737
- keyOrKeys: string | string[],
738
- options?: cf.DurableObjectPutOptions,
739
- ) =>
740
- Effect.tryPromise(() => storage.delete(keyOrKeys as any, options))) as any,
741
- deleteAll: (options?: cf.DurableObjectPutOptions) =>
742
- Effect.tryPromise(() => storage.deleteAll(options)),
743
- transaction: <T>(
744
- closure: (txn: DurableObjectTransaction) => Effect.Effect<T>,
745
- ) =>
746
- Effect.tryPromise(() =>
747
- storage.transaction((txn) =>
748
- Effect.runPromise(closure(fromDurableObjectTransaction(txn))),
749
- ),
750
- ),
751
- getAlarm: (options?: cf.DurableObjectGetAlarmOptions) =>
752
- Effect.tryPromise(() => storage.getAlarm(options)),
753
- setAlarm: (
754
- scheduledTime: number | Date,
755
- options?: cf.DurableObjectSetAlarmOptions,
756
- ) => Effect.tryPromise(() => storage.setAlarm(scheduledTime, options)),
757
- deleteAlarm: (options?: cf.DurableObjectSetAlarmOptions) =>
758
- Effect.tryPromise(() => storage.deleteAlarm(options)),
759
- sync: () => Effect.tryPromise(() => storage.sync()),
760
- sql: storage.sql,
761
- kv: storage.kv,
762
- transactionSync: <T>(closure: () => T) => storage.transactionSync(closure),
763
- getCurrentBookmark: () =>
764
- Effect.tryPromise(() => storage.getCurrentBookmark()),
765
- getBookmarkForTime: (timestamp: number | Date) =>
766
- Effect.tryPromise(() => storage.getBookmarkForTime(timestamp)),
767
- onNextSessionRestoreBookmark: (bookmark: string) =>
768
- Effect.tryPromise(() => storage.onNextSessionRestoreBookmark(bookmark)),
769
- });