effect-cf 0.48.0 → 0.50.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.
package/src/Sandbox.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Adapter for the legacy `@cloudflare/sandbox` 0.13 namespace/client API.
3
+ * SDK 1.x utilities can instead use `DurableObjectContainer`'s native `raw` handle.
4
+ */
1
5
  import type {
2
6
  BackupOptions,
3
7
  CheckChangesOptions,
@@ -240,7 +244,7 @@ export interface SandboxTunnelsClient {
240
244
  }
241
245
 
242
246
  export interface SandboxInstanceClient {
243
- readonly rawUnsafe: Effect.Effect<SandboxClientResource>;
247
+ readonly rawUnsafe: Effect.Effect<SandboxClientResource, SandboxOperationError>;
244
248
  readonly exec: (
245
249
  command: SandboxCommand,
246
250
  options?: ExecOptions,
@@ -610,45 +614,77 @@ export const fromSandboxClient = (
610
614
  client: SandboxClientResource,
611
615
  definition: SandboxDefinition,
612
616
  instance: string,
613
- ): SandboxInstanceClient => makeSandboxClient(client, definition, instance, client);
617
+ ): SandboxInstanceClient =>
618
+ makeSandboxClient(Effect.succeed({ client, target: client }), definition, instance);
614
619
 
615
620
  const makeSandboxClient = (
616
- client: SandboxClientResource,
621
+ resolve: Effect.Effect<
622
+ {
623
+ readonly client: SandboxClientResource;
624
+ readonly target: SandboxClientResource | SandboxNamespaceResource;
625
+ },
626
+ SandboxOperationError
627
+ >,
617
628
  definition: SandboxDefinition,
618
629
  instance: string,
619
- target: SandboxClientResource | SandboxNamespaceResource,
620
630
  ): SandboxInstanceClient => {
621
- const attempt = <A>(operation: string, evaluate: (signal: AbortSignal) => PromiseLike<A>) =>
622
- trySandboxPromise(definition, instance, operation, evaluate, target);
631
+ const attempt = <A>(
632
+ operation: string,
633
+ evaluate: (
634
+ client: SandboxClientResource,
635
+ signal: AbortSignal,
636
+ target: SandboxClientResource | SandboxNamespaceResource,
637
+ ) => PromiseLike<A>,
638
+ ) =>
639
+ Effect.flatMap(resolve, ({ client, target }) =>
640
+ trySandboxPromise(
641
+ definition,
642
+ instance,
643
+ operation,
644
+ (signal) => evaluate(client, signal, target),
645
+ target,
646
+ ),
647
+ );
623
648
  const stream = <A>(
624
649
  operation: string,
625
- acquire: (signal: AbortSignal) => PromiseLike<ReadableStream<A>>,
626
- ) => sandboxStream(definition, instance, operation, acquire, target);
650
+ acquire: (client: SandboxClientResource, signal: AbortSignal) => PromiseLike<ReadableStream<A>>,
651
+ ) =>
652
+ Stream.unwrap(
653
+ Effect.map(resolve, ({ client, target }) =>
654
+ sandboxStream(definition, instance, operation, (signal) => acquire(client, signal), target),
655
+ ),
656
+ );
627
657
  const spanOptions = (operation: string) => ({
628
658
  attributes: { binding: definition.binding, instance, operation },
629
659
  });
630
660
 
631
661
  return {
632
- rawUnsafe: Effect.succeed(client),
662
+ rawUnsafe: Effect.map(resolve, ({ client }) => client),
633
663
  exec: Effect.fn(
634
664
  "Sandbox.exec",
635
665
  spanOptions("exec"),
636
666
  )(function* (command: SandboxCommand, options?: ExecOptions) {
637
- const process = yield* attempt("exec", () => client.exec(command, options));
638
-
639
- return makeProcessHandle(definition, instance, process, target);
667
+ return yield* attempt("exec", (client, _signal, target) =>
668
+ client
669
+ .exec(command, options)
670
+ .then((process) => makeProcessHandle(definition, instance, process, target)),
671
+ );
640
672
  }),
641
673
  getProcess: Effect.fn(
642
674
  "Sandbox.getProcess",
643
675
  spanOptions("getProcess"),
644
676
  )(function* (id: string) {
645
- const process = yield* attempt("getProcess", () => client.getProcess(id));
646
-
647
- return Option.map(Option.fromNullishOr(process), (found) =>
648
- makeProcessHandle(definition, instance, found, target),
677
+ return yield* attempt("getProcess", (client, _signal, target) =>
678
+ client
679
+ .getProcess(id)
680
+ .then((process) =>
681
+ Option.map(Option.fromNullishOr(process), (found) =>
682
+ makeProcessHandle(definition, instance, found, target),
683
+ ),
684
+ ),
649
685
  );
650
686
  }),
651
- listProcesses: attempt("listProcesses", () => client.listProcesses()).pipe(
687
+ listProcesses: attempt("listProcesses", (client) => client.listProcesses()).pipe(
652
688
  Effect.withSpan("Sandbox.listProcesses", spanOptions("listProcesses")),
653
689
  ),
654
690
  writeFile: Effect.fn(
@@ -661,7 +697,7 @@ const makeSandboxClient = (
661
697
  ) {
662
698
  yield* Effect.annotateCurrentSpan("path", path);
663
699
 
664
- return yield* attempt("writeFile", () => client.writeFile(path, content, options));
700
+ return yield* attempt("writeFile", (client) => client.writeFile(path, content, options));
665
701
  }),
666
702
  readFile: Effect.fn(
667
703
  "Sandbox.readFile",
@@ -669,16 +705,17 @@ const makeSandboxClient = (
669
705
  )(function* (path: string, options?: { readonly encoding?: ReadFileEncoding }) {
670
706
  yield* Effect.annotateCurrentSpan("path", path);
671
707
 
672
- return yield* attempt("readFile", () => client.readFile(path, options));
708
+ return yield* attempt("readFile", (client) => client.readFile(path, options));
673
709
  }),
674
- readFileStream: (path: string) => stream("readFileStream", () => client.readFileStream(path)),
710
+ readFileStream: (path: string) =>
711
+ stream("readFileStream", (client) => client.readFileStream(path)),
675
712
  mkdir: Effect.fn(
676
713
  "Sandbox.mkdir",
677
714
  spanOptions("mkdir"),
678
715
  )(function* (path: string, options?: { readonly recursive?: boolean }) {
679
716
  yield* Effect.annotateCurrentSpan("path", path);
680
717
 
681
- return yield* attempt("mkdir", () => client.mkdir(path, options));
718
+ return yield* attempt("mkdir", (client) => client.mkdir(path, options));
682
719
  }),
683
720
  deleteFile: Effect.fn(
684
721
  "Sandbox.deleteFile",
@@ -686,7 +723,7 @@ const makeSandboxClient = (
686
723
  )(function* (path: string) {
687
724
  yield* Effect.annotateCurrentSpan("path", path);
688
725
 
689
- return yield* attempt("deleteFile", () => client.deleteFile(path));
726
+ return yield* attempt("deleteFile", (client) => client.deleteFile(path));
690
727
  }),
691
728
  renameFile: Effect.fn(
692
729
  "Sandbox.renameFile",
@@ -694,7 +731,7 @@ const makeSandboxClient = (
694
731
  )(function* (oldPath: string, newPath: string) {
695
732
  yield* Effect.annotateCurrentSpan({ oldPath, newPath });
696
733
 
697
- return yield* attempt("renameFile", () => client.renameFile(oldPath, newPath));
734
+ return yield* attempt("renameFile", (client) => client.renameFile(oldPath, newPath));
698
735
  }),
699
736
  moveFile: Effect.fn(
700
737
  "Sandbox.moveFile",
@@ -702,7 +739,7 @@ const makeSandboxClient = (
702
739
  )(function* (sourcePath: string, destinationPath: string) {
703
740
  yield* Effect.annotateCurrentSpan({ sourcePath, destinationPath });
704
741
 
705
- return yield* attempt("moveFile", () => client.moveFile(sourcePath, destinationPath));
742
+ return yield* attempt("moveFile", (client) => client.moveFile(sourcePath, destinationPath));
706
743
  }),
707
744
  listFiles: Effect.fn(
708
745
  "Sandbox.listFiles",
@@ -710,7 +747,7 @@ const makeSandboxClient = (
710
747
  )(function* (path: string, options?: ListFilesOptions) {
711
748
  yield* Effect.annotateCurrentSpan("path", path);
712
749
 
713
- return yield* attempt("listFiles", () => client.listFiles(path, options));
750
+ return yield* attempt("listFiles", (client) => client.listFiles(path, options));
714
751
  }),
715
752
  exists: Effect.fn(
716
753
  "Sandbox.exists",
@@ -718,11 +755,11 @@ const makeSandboxClient = (
718
755
  )(function* (path: string) {
719
756
  yield* Effect.annotateCurrentSpan("path", path);
720
757
 
721
- return yield* attempt("exists", () => client.exists(path));
758
+ return yield* attempt("exists", (client) => client.exists(path));
722
759
  }),
723
760
  watch: (path: string, options?: WatchOptions) =>
724
761
  decodeSseEvents<FileWatchSSEEvent, SandboxOperationError, never>(
725
- stream("watch", () => client.watch(path, options)),
762
+ stream("watch", (client) => client.watch(path, options)),
726
763
  ),
727
764
  checkChanges: Effect.fn(
728
765
  "Sandbox.checkChanges",
@@ -730,13 +767,13 @@ const makeSandboxClient = (
730
767
  )(function* (path: string, options?: CheckChangesOptions) {
731
768
  yield* Effect.annotateCurrentSpan("path", path);
732
769
 
733
- return yield* attempt("checkChanges", () => client.checkChanges(path, options));
770
+ return yield* attempt("checkChanges", (client) => client.checkChanges(path, options));
734
771
  }),
735
772
  setEnvVars: Effect.fn(
736
773
  "Sandbox.setEnvVars",
737
774
  spanOptions("setEnvVars"),
738
775
  )(function* (envVars: Record<string, string | undefined>) {
739
- return yield* attempt("setEnvVars", () => client.setEnvVars(envVars));
776
+ return yield* attempt("setEnvVars", (client) => client.setEnvVars(envVars));
740
777
  }),
741
778
  exposePort: Effect.fn(
742
779
  "Sandbox.exposePort",
@@ -744,7 +781,7 @@ const makeSandboxClient = (
744
781
  )(function* (port: number, options: ExposePortOptions) {
745
782
  yield* Effect.annotateCurrentSpan("port", port);
746
783
 
747
- return yield* attempt("exposePort", () => client.exposePort(port, options));
784
+ return yield* attempt("exposePort", (client) => client.exposePort(port, options));
748
785
  }),
749
786
  unexposePort: Effect.fn(
750
787
  "Sandbox.unexposePort",
@@ -752,13 +789,13 @@ const makeSandboxClient = (
752
789
  )(function* (port: number) {
753
790
  yield* Effect.annotateCurrentSpan("port", port);
754
791
 
755
- return yield* attempt("unexposePort", () => client.unexposePort(port));
792
+ return yield* attempt("unexposePort", (client) => client.unexposePort(port));
756
793
  }),
757
794
  getExposedPorts: Effect.fn(
758
795
  "Sandbox.getExposedPorts",
759
796
  spanOptions("getExposedPorts"),
760
797
  )(function* (hostname: string) {
761
- return yield* attempt("getExposedPorts", () => client.getExposedPorts(hostname));
798
+ return yield* attempt("getExposedPorts", (client) => client.getExposedPorts(hostname));
762
799
  }),
763
800
  isPortExposed: Effect.fn(
764
801
  "Sandbox.isPortExposed",
@@ -766,7 +803,7 @@ const makeSandboxClient = (
766
803
  )(function* (port: number) {
767
804
  yield* Effect.annotateCurrentSpan("port", port);
768
805
 
769
- return yield* attempt("isPortExposed", () => client.isPortExposed(port));
806
+ return yield* attempt("isPortExposed", (client) => client.isPortExposed(port));
770
807
  }),
771
808
  validatePortToken: Effect.fn(
772
809
  "Sandbox.validatePortToken",
@@ -774,13 +811,15 @@ const makeSandboxClient = (
774
811
  )(function* (port: number, token: string) {
775
812
  yield* Effect.annotateCurrentSpan("port", port);
776
813
 
777
- return yield* attempt("validatePortToken", () => client.validatePortToken(port, token));
814
+ return yield* attempt("validatePortToken", (client) => client.validatePortToken(port, token));
778
815
  }),
779
816
  containerFetch: Effect.fn(
780
817
  "Sandbox.containerFetch",
781
818
  spanOptions("containerFetch"),
782
819
  )(function* (requestOrUrl: Request | string | URL, port?: number) {
783
- return yield* attempt("containerFetch", () => client.containerFetch(requestOrUrl, port));
820
+ return yield* attempt("containerFetch", (client) =>
821
+ client.containerFetch(requestOrUrl, port),
822
+ );
784
823
  }),
785
824
  wsConnect: Effect.fn(
786
825
  "Sandbox.wsConnect",
@@ -788,7 +827,7 @@ const makeSandboxClient = (
788
827
  )(function* (request: Request, port: number) {
789
828
  yield* Effect.annotateCurrentSpan("port", port);
790
829
 
791
- return yield* attempt("wsConnect", () => client.wsConnect(request, port));
830
+ return yield* attempt("wsConnect", (client) => client.wsConnect(request, port));
792
831
  }),
793
832
  mountBucket: Effect.fn(
794
833
  "Sandbox.mountBucket",
@@ -796,7 +835,9 @@ const makeSandboxClient = (
796
835
  )(function* (bucket: string, mountPath: string, options: MountBucketOptions) {
797
836
  yield* Effect.annotateCurrentSpan({ bucket, mountPath });
798
837
 
799
- return yield* attempt("mountBucket", () => client.mountBucket(bucket, mountPath, options));
838
+ return yield* attempt("mountBucket", (client) =>
839
+ client.mountBucket(bucket, mountPath, options),
840
+ );
800
841
  }),
801
842
  unmountBucket: Effect.fn(
802
843
  "Sandbox.unmountBucket",
@@ -804,7 +845,7 @@ const makeSandboxClient = (
804
845
  )(function* (mountPath: string) {
805
846
  yield* Effect.annotateCurrentSpan("mountPath", mountPath);
806
847
 
807
- return yield* attempt("unmountBucket", () => client.unmountBucket(mountPath));
848
+ return yield* attempt("unmountBucket", (client) => client.unmountBucket(mountPath));
808
849
  }),
809
850
  createBackup: Effect.fn(
810
851
  "Sandbox.createBackup",
@@ -812,7 +853,7 @@ const makeSandboxClient = (
812
853
  )(function* (options: BackupOptions) {
813
854
  yield* Effect.annotateCurrentSpan("dir", options.dir);
814
855
 
815
- return yield* attempt("createBackup", () => client.createBackup(options));
856
+ return yield* attempt("createBackup", (client) => client.createBackup(options));
816
857
  }),
817
858
  restoreBackup: Effect.fn(
818
859
  "Sandbox.restoreBackup",
@@ -820,32 +861,39 @@ const makeSandboxClient = (
820
861
  )(function* (backup: DirectoryBackup) {
821
862
  yield* Effect.annotateCurrentSpan({ backupId: backup.id, dir: backup.dir });
822
863
 
823
- return yield* attempt("restoreBackup", () => client.restoreBackup(backup));
864
+ return yield* attempt("restoreBackup", (client) => client.restoreBackup(backup));
824
865
  }),
825
866
  createTerminal: Effect.fn(
826
867
  "Sandbox.createTerminal",
827
868
  spanOptions("createTerminal"),
828
869
  )(function* (options: CreateTerminalOptions) {
829
- const terminal = yield* attempt("createTerminal", () => client.createTerminal(options));
830
-
831
- return makeTerminalHandle(definition, instance, terminal, target);
870
+ return yield* attempt("createTerminal", (client, _signal, target) =>
871
+ client
872
+ .createTerminal(options)
873
+ .then((terminal) => makeTerminalHandle(definition, instance, terminal, target)),
874
+ );
832
875
  }),
833
876
  getTerminal: Effect.fn(
834
877
  "Sandbox.getTerminal",
835
878
  spanOptions("getTerminal"),
836
879
  )(function* (id: string) {
837
- const terminal = yield* attempt("getTerminal", () => client.getTerminal(id));
838
-
839
- return Option.map(Option.fromNullishOr(terminal), (found) =>
840
- makeTerminalHandle(definition, instance, found, target),
880
+ return yield* attempt("getTerminal", (client, _signal, target) =>
881
+ client
882
+ .getTerminal(id)
883
+ .then((terminal) =>
884
+ Option.map(Option.fromNullishOr(terminal), (found) =>
885
+ makeTerminalHandle(definition, instance, found, target),
886
+ ),
887
+ ),
841
888
  );
842
889
  }),
843
- listTerminals: attempt("listTerminals", () => client.listTerminals()).pipe(
844
- Effect.map((terminals) =>
845
- terminals.map((terminal) => makeTerminalHandle(definition, instance, terminal, target)),
846
- ),
847
- Effect.withSpan("Sandbox.listTerminals", spanOptions("listTerminals")),
848
- ),
890
+ listTerminals: attempt("listTerminals", (client, _signal, target) =>
891
+ client
892
+ .listTerminals()
893
+ .then((terminals) =>
894
+ terminals.map((terminal) => makeTerminalHandle(definition, instance, terminal, target)),
895
+ ),
896
+ ).pipe(Effect.withSpan("Sandbox.listTerminals", spanOptions("listTerminals"))),
849
897
  tunnels: {
850
898
  get: Effect.fn(
851
899
  "Sandbox.tunnels.get",
@@ -853,31 +901,31 @@ const makeSandboxClient = (
853
901
  )(function* (port: number, options?: TunnelOptions) {
854
902
  yield* Effect.annotateCurrentSpan("port", port);
855
903
 
856
- return yield* attempt("tunnels.get", () => client.tunnels.get(port, options));
904
+ return yield* attempt("tunnels.get", (client) => client.tunnels.get(port, options));
857
905
  }),
858
- list: attempt("tunnels.list", () => client.tunnels.list()).pipe(
906
+ list: attempt("tunnels.list", (client) => client.tunnels.list()).pipe(
859
907
  Effect.withSpan("Sandbox.tunnels.list", spanOptions("tunnels.list")),
860
908
  ),
861
909
  destroy: Effect.fn(
862
910
  "Sandbox.tunnels.destroy",
863
911
  spanOptions("tunnels.destroy"),
864
912
  )(function* (portOrInfo: number | TunnelInfo) {
865
- return yield* attempt("tunnels.destroy", () => client.tunnels.destroy(portOrInfo));
913
+ return yield* attempt("tunnels.destroy", (client) => client.tunnels.destroy(portOrInfo));
866
914
  }),
867
915
  },
868
916
  start: Effect.fn(
869
917
  "Sandbox.start",
870
918
  spanOptions("start"),
871
919
  )(function* (options?: ContainerStartOptions) {
872
- return yield* attempt("start", () => client.start(options));
920
+ return yield* attempt("start", (client) => client.start(options));
873
921
  }),
874
922
  stop: Effect.fn(
875
923
  "Sandbox.stop",
876
924
  spanOptions("stop"),
877
925
  )(function* (signal?: ContainerStopSignal) {
878
- return yield* attempt("stop", () => client.stop(signal));
926
+ return yield* attempt("stop", (client) => client.stop(signal));
879
927
  }),
880
- destroy: attempt("destroy", () => client.destroy()).pipe(
928
+ destroy: attempt("destroy", (client) => client.destroy()).pipe(
881
929
  Effect.withSpan("Sandbox.destroy", spanOptions("destroy")),
882
930
  ),
883
931
  };
@@ -921,52 +969,58 @@ export const makeClient =
921
969
  yield* Effect.annotateCurrentSpan("instance", name);
922
970
 
923
971
  const sandboxModule = yield* importSandboxModule(definition, name);
924
- const targets = yield* Effect.serviceOption(CurrentTargets);
925
- const scopedNamespace = yield* RpcTargets.get(namespace, "sandbox-namespace", () => {
926
- const adapter: SandboxNamespaceResource = {
927
- idFromName: (name) => namespace.idFromName(name),
928
- get: (id, options) =>
929
- Option.isSome(targets)
930
- ? targets.value.get(adapter, JSON.stringify([id.toString(), options]), () =>
931
- namespace.get(id, options),
932
- )
933
- : namespace.get(id, options),
934
- };
935
-
936
- return adapter;
937
- }).pipe(
938
- Effect.mapError(
939
- (error) =>
972
+ // Resolve through the invocation cache on each operation. A retained client
973
+ // must observe invalidation after a native stub fails; failed work is not replayed.
974
+ const resolve = Effect.gen(function* () {
975
+ const targets = yield* Effect.serviceOption(CurrentTargets);
976
+ const scopedNamespace = yield* RpcTargets.get(namespace, "sandbox-namespace", () => {
977
+ const adapter: SandboxNamespaceResource = {
978
+ idFromName: (name) => namespace.idFromName(name),
979
+ get: (id, options) =>
980
+ Option.isSome(targets)
981
+ ? targets.value.get(adapter, JSON.stringify([id.toString(), options]), () =>
982
+ namespace.get(id, options),
983
+ )
984
+ : namespace.get(id, options),
985
+ };
986
+
987
+ return adapter;
988
+ }).pipe(
989
+ Effect.mapError(
990
+ (error) =>
991
+ new SandboxOperationError({
992
+ binding: definition.binding,
993
+ instance: name,
994
+ operation: "get",
995
+ cause: error.cause,
996
+ }),
997
+ ),
998
+ );
999
+ const nativeNamespace: unknown = scopedNamespace;
1000
+ const client = yield* Effect.try({
1001
+ try: () =>
1002
+ sandboxModule.getSandbox(
1003
+ // SAFETY: the layer validated the binding as a Durable Object
1004
+ // namespace, and getSandbox only requires idFromName() and get();
1005
+ // the structural namespace type is narrower than the SDK's nominal
1006
+ // one, so the conversion goes through unknown.
1007
+ nativeNamespace as Parameters<typeof sandboxModule.getSandbox>[0],
1008
+ name,
1009
+ options,
1010
+ ),
1011
+ catch: (cause) =>
940
1012
  new SandboxOperationError({
941
1013
  binding: definition.binding,
942
1014
  instance: name,
943
1015
  operation: "get",
944
- cause: error.cause,
1016
+ cause,
945
1017
  }),
946
- ),
947
- );
948
- const nativeNamespace: unknown = scopedNamespace;
949
- const client = yield* Effect.try({
950
- try: () =>
951
- sandboxModule.getSandbox(
952
- // SAFETY: the layer validated the binding as a Durable Object
953
- // namespace, and getSandbox only requires idFromName() and get();
954
- // the structural namespace type is narrower than the SDK's nominal
955
- // one, so the conversion goes through unknown.
956
- nativeNamespace as Parameters<typeof sandboxModule.getSandbox>[0],
957
- name,
958
- options,
959
- ),
960
- catch: (cause) =>
961
- new SandboxOperationError({
962
- binding: definition.binding,
963
- instance: name,
964
- operation: "get",
965
- cause,
966
- }),
1018
+ });
1019
+
1020
+ return { client, target: scopedNamespace };
967
1021
  });
968
1022
 
969
- return makeSandboxClient(client, definition, name, scopedNamespace);
1023
+ return makeSandboxClient(resolve, definition, name);
970
1024
  });
971
1025
 
972
1026
  return {
package/src/index.ts CHANGED
@@ -6,10 +6,12 @@ export * as BrowserRendering from "./BrowserRendering";
6
6
  export * as Cache from "./Cache";
7
7
  export * as CloudflareOtlp from "./CloudflareOtlp";
8
8
  export * as CloudflareTracer from "./CloudflareTracer";
9
+ export * as ContainerFiles from "./ContainerFiles";
9
10
  export * as ContainerNamespace from "./ContainerNamespace";
10
11
  export * as D1 from "./D1";
11
12
  export * as DurableObject from "./DurableObject";
12
13
  export * as DurableObjectAlarm from "./DurableObjectAlarm";
14
+ export * as DurableObjectContainer from "./DurableObjectContainer";
13
15
  export * as DurableObjectDefinition from "./DurableObjectDefinition";
14
16
  export * as DurableObjectNamespace from "./DurableObjectNamespace";
15
17
  export * as DurableObjectRpcWebSocket from "./DurableObjectRpcWebSocket";