effect-cf 0.23.0 → 0.24.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/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { Cause, Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Function as Function$1, Layer, ManagedRuntime, Option, Predicate, Queue, Result, Schema } from "effect";
2
+ import { a as DurableObjectWebSocket_exports, c as causeMessage, d as WorkerConfig, f as WorkerEnvironment, i as fromExecutionContext, l as violationsMessage, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState, u as Environment_exports } from "./DurableObjectState-8sgBJB0s.mjs";
3
+ import { Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Function as Function$1, Layer, ManagedRuntime, Option, Predicate, Queue, Result, Schema } from "effect";
3
4
  import { FetchHttpClient, HttpClient, HttpClientRequest, HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
4
5
  import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
5
6
  import { D1Client } from "@effect/sql-d1";
@@ -8,29 +9,6 @@ import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
8
9
  import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
9
10
  import * as RpcServer from "effect/unstable/rpc/RpcServer";
10
11
  import { SqliteClient } from "@effect/sql-sqlite-do";
11
- //#region src/Environment.ts
12
- var Environment_exports = /* @__PURE__ */ __exportAll({
13
- WorkerConfig: () => WorkerConfig,
14
- WorkerEnvironment: () => WorkerEnvironment
15
- });
16
- /**
17
- * Context service for reading worker bindings from the current `env` object.
18
- */
19
- var WorkerEnvironment = class extends Context.Service()("effect-cf/WorkerEnvironment") {};
20
- let WorkerConfig;
21
- (function(_WorkerConfig) {
22
- _WorkerConfig.string = (name) => Config.string(name);
23
- _WorkerConfig.redacted = (name) => Config.redacted(name);
24
- _WorkerConfig.number = (name) => Config.number(name);
25
- _WorkerConfig.integer = (name) => Config.int(name);
26
- _WorkerConfig.boolean = (name) => Config.boolean(name);
27
- const providerFromEnv = _WorkerConfig.providerFromEnv = (env, options) => ConfigProvider.fromUnknown(env, options);
28
- const providerWith = _WorkerConfig.providerWith = (makeProvider) => Effect.map(WorkerEnvironment, makeProvider);
29
- const provider = _WorkerConfig.provider = providerWith(providerFromEnv);
30
- _WorkerConfig.layer = _WorkerConfig.providerLayer = ConfigProvider.layer(provider);
31
- _WorkerConfig.layerWith = (makeProvider) => ConfigProvider.layer(providerWith(makeProvider));
32
- })(WorkerConfig || (WorkerConfig = {}));
33
- //#endregion
34
12
  //#region src/Binding.ts
35
13
  var Binding_exports = /* @__PURE__ */ __exportAll({
36
14
  BindingNotFoundError: () => BindingNotFoundError,
@@ -149,25 +127,6 @@ const Service$2 = () => {
149
127
  return makeService;
150
128
  };
151
129
  //#endregion
152
- //#region src/internal/ErrorMessage.ts
153
- /**
154
- * Renders the most useful human-readable description of an unknown `cause`
155
- * for use in tagged error `message` getters.
156
- */
157
- const causeMessage = (cause) => {
158
- if (typeof cause === "object" && cause !== null) {
159
- const message = Reflect.get(cause, "message");
160
- if (typeof message === "string" && message.length > 0) return message;
161
- }
162
- try {
163
- return String(cause);
164
- } catch {
165
- return "unknown cause";
166
- }
167
- };
168
- /** Renders a violation list as a single `path: message; ...` line. */
169
- const violationsMessage = (violations) => violations.map((violation) => `${violation.path}: ${violation.message}`).join("; ");
170
- //#endregion
171
130
  //#region src/WorkersAi.ts
172
131
  var WorkersAi_exports = /* @__PURE__ */ __exportAll({
173
132
  Tag: () => Tag$16,
@@ -734,345 +693,6 @@ const layerFrom = (storage) => Layer.succeed(CacheStorage, makeClient$11(storage
734
693
  /** Provides Cache API services from Cloudflare's global `caches` object. */
735
694
  const layer$14 = Layer.sync(CacheStorage, () => makeClient$11(caches));
736
695
  //#endregion
737
- //#region src/DurableObjectStorage.ts
738
- var DurableObjectStorage_exports = /* @__PURE__ */ __exportAll({
739
- StorageOperationError: () => StorageOperationError,
740
- fromDurableObjectStorage: () => fromDurableObjectStorage
741
- });
742
- /** Error type used when a storage operation throws or rejects. */
743
- var StorageOperationError = class extends Data.TaggedError("StorageOperationError") {
744
- get message() {
745
- return `Durable Object storage ${this.operation} failed: ${causeMessage(this.cause)}`;
746
- }
747
- };
748
- const storageError = (operation, cause) => new StorageOperationError({
749
- operation,
750
- cause
751
- });
752
- const tryStorageSync = (operation, evaluate) => Effect.try({
753
- try: evaluate,
754
- catch: (cause) => storageError(operation, cause)
755
- });
756
- const tryStoragePromise = (operation, evaluate) => Effect.tryPromise({
757
- try: evaluate,
758
- catch: (cause) => storageError(operation, cause)
759
- });
760
- const fromSqlCursor = (cursor) => ({
761
- next: () => tryStorageSync("sql.next", () => cursor.next()),
762
- toArray: () => tryStorageSync("sql.toArray", () => cursor.toArray()),
763
- one: () => tryStorageSync("sql.one", () => cursor.one()),
764
- raw: () => tryStorageSync("sql.raw", () => cursor.raw()),
765
- get columnNames() {
766
- return cursor.columnNames;
767
- },
768
- rowsRead: tryStorageSync("sql.rowsRead", () => cursor.rowsRead),
769
- rowsWritten: tryStorageSync("sql.rowsWritten", () => cursor.rowsWritten)
770
- });
771
- const fromSqlStorage = (sql) => ({
772
- exec: (query, ...bindings) => tryStorageSync("sql.exec", () => fromSqlCursor(sql.exec(query, ...bindings))),
773
- get databaseSize() {
774
- return sql.databaseSize;
775
- }
776
- });
777
- const schemaBackedSyncKvStorage = (kv, definition) => {
778
- const encodeKey = Schema.encodeEffect(definition.key);
779
- const decodeKey = Schema.decodeUnknownEffect(definition.key);
780
- const encodeValue = Schema.encodeEffect(definition.value);
781
- const decodeValue = Schema.decodeUnknownEffect(definition.value);
782
- return {
783
- get: (key) => Effect.gen(function* () {
784
- const encodedKey = yield* encodeKey(key);
785
- const encodedValue = yield* tryStorageSync("kv.get", () => kv.get(encodedKey));
786
- if (encodedValue === void 0) return Option.none();
787
- return yield* decodeValue(encodedValue).pipe(Effect.map(Option.some));
788
- }),
789
- put: (key, value) => Effect.gen(function* () {
790
- const encodedKey = yield* encodeKey(key);
791
- const encodedValue = yield* encodeValue(value);
792
- yield* tryStorageSync("kv.put", () => kv.put(encodedKey, encodedValue));
793
- }),
794
- delete: (key) => Effect.gen(function* () {
795
- const encodedKey = yield* encodeKey(key);
796
- return yield* tryStorageSync("kv.delete", () => kv.delete(encodedKey));
797
- }),
798
- list: (options) => Effect.gen(function* () {
799
- const entries = Array.from(yield* tryStorageSync("kv.list", () => kv.list(options)));
800
- const decoded = [];
801
- for (const [key, value] of entries) decoded.push([yield* decodeKey(key), yield* decodeValue(value)]);
802
- return decoded;
803
- })
804
- };
805
- };
806
- const fromSyncKvStorage = (kv) => ({
807
- get: (key) => tryStorageSync("kv.get", () => kv.get(key)),
808
- put: (key, value) => tryStorageSync("kv.put", () => kv.put(key, value)),
809
- delete: (key) => tryStorageSync("kv.delete", () => kv.delete(key)),
810
- list: (options) => tryStorageSync("kv.list", () => Array.from(kv.list(options))),
811
- schema: (definition) => schemaBackedSyncKvStorage(kv, definition)
812
- });
813
- const fromDurableObjectTransaction = (txn) => ({
814
- get: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)) : tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)),
815
- list: (options) => tryStoragePromise("transaction.list", () => txn.list(options)),
816
- put: (keyOrEntries, valueOrOptions, maybeOptions) => tryStoragePromise("transaction.put", () => typeof keyOrEntries === "string" ? txn.put(keyOrEntries, valueOrOptions, maybeOptions) : txn.put(keyOrEntries, valueOrOptions)),
817
- delete: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)) : tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)),
818
- rollback: () => tryStorageSync("transaction.rollback", () => txn.rollback()),
819
- getAlarm: (options) => tryStoragePromise("transaction.getAlarm", () => txn.getAlarm(options)),
820
- setAlarm: (scheduledTime, options) => tryStoragePromise("transaction.setAlarm", () => txn.setAlarm(scheduledTime, options)),
821
- deleteAlarm: (options) => tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options))
822
- });
823
- /**
824
- * Wraps native Cloudflare storage APIs as Effect-returning helpers.
825
- */
826
- const fromDurableObjectStorage = (storage) => ({
827
- get: (key, options) => tryStoragePromise("get", () => storage.get(key, options)),
828
- put: (key, value, options) => tryStoragePromise("put", () => storage.put(key, value, options)),
829
- delete: (key, options) => tryStoragePromise("delete", () => storage.delete(key, options)),
830
- deleteAll: (options) => tryStoragePromise("deleteAll", () => storage.deleteAll(options)),
831
- getAlarm: (options) => tryStoragePromise("getAlarm", () => storage.getAlarm(options)),
832
- setAlarm: (scheduledTime, options) => tryStoragePromise("setAlarm", () => storage.setAlarm(scheduledTime, options)),
833
- deleteAlarm: (options) => tryStoragePromise("deleteAlarm", () => storage.deleteAlarm(options)),
834
- transactionSync: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.suspend(() => {
835
- try {
836
- return Effect.succeed(storage.transactionSync(() => {
837
- const exit = Effect.runSyncExitWith(context)(closure());
838
- if (Exit.isSuccess(exit)) return exit.value;
839
- throw exit;
840
- }));
841
- } catch (cause) {
842
- if (Exit.isExit(cause) && Exit.isFailure(cause)) return Effect.failCause(cause.cause);
843
- return Effect.fail(storageError("transactionSync", cause));
844
- }
845
- }))),
846
- transaction: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.callback((resume) => {
847
- storage.transaction(async (txn) => {
848
- const exit = await Effect.runPromiseExitWith(context)(closure(fromDurableObjectTransaction(txn)));
849
- if (Exit.isSuccess(exit)) return exit.value;
850
- throw exit;
851
- }).then((value) => resume(Effect.succeed(value)), (cause) => {
852
- if (Exit.isExit(cause) && Exit.isFailure(cause)) resume(Effect.failCause(cause.cause));
853
- else resume(Effect.fail(storageError("transaction", cause)));
854
- });
855
- }))),
856
- sync: () => tryStoragePromise("sync", () => storage.sync()),
857
- getCurrentBookmark: () => tryStoragePromise("getCurrentBookmark", () => storage.getCurrentBookmark()),
858
- onNextSessionRestoreBookmark: (bookmark) => tryStoragePromise("onNextSessionRestoreBookmark", () => storage.onNextSessionRestoreBookmark(bookmark)),
859
- sql: fromSqlStorage(storage.sql),
860
- kv: fromSyncKvStorage(storage.kv)
861
- });
862
- //#endregion
863
- //#region src/DurableObjectWebSocket.ts
864
- var DurableObjectWebSocket_exports = /* @__PURE__ */ __exportAll({
865
- DurableWebSocketAttachmentError: () => DurableWebSocketAttachmentError,
866
- DurableWebSocketCloseError: () => DurableWebSocketCloseError,
867
- DurableWebSocketSendError: () => DurableWebSocketSendError,
868
- acceptUpgrade: () => acceptUpgrade,
869
- attachment: () => attachment,
870
- fromWebSocket: () => fromWebSocket,
871
- handlers: () => handlers
872
- });
873
- /** Error raised when sending on a Durable Object websocket fails. */
874
- var DurableWebSocketSendError = class extends Data.TaggedError("DurableWebSocketSendError") {
875
- get message() {
876
- return `Durable Object websocket send failed: ${causeMessage(this.cause)}`;
877
- }
878
- };
879
- /** Error raised when closing a Durable Object websocket fails. */
880
- var DurableWebSocketCloseError = class extends Data.TaggedError("DurableWebSocketCloseError") {
881
- get message() {
882
- return `Durable Object websocket close failed: ${causeMessage(this.cause)}`;
883
- }
884
- };
885
- /** Error raised when serializing or deserializing a websocket attachment fails. */
886
- var DurableWebSocketAttachmentError = class extends Data.TaggedError("DurableWebSocketAttachmentError") {
887
- get message() {
888
- return `Durable Object websocket attachment ${this.operation} failed: ${causeMessage(this.cause)}`;
889
- }
890
- };
891
- const wrappers = /* @__PURE__ */ new WeakMap();
892
- /** Wraps a native Cloudflare websocket in the Effect-native Durable Object API. */
893
- const fromWebSocket = (raw) => {
894
- const existing = wrappers.get(raw);
895
- if (existing !== void 0) return existing;
896
- const socket = {
897
- raw,
898
- send: (data) => Effect.try({
899
- try: () => raw.send(data),
900
- catch: (cause) => new DurableWebSocketSendError({ cause })
901
- }),
902
- close: (code, reason) => Effect.try({
903
- try: () => raw.close(code, reason),
904
- catch: (cause) => new DurableWebSocketCloseError({ cause })
905
- }),
906
- serializeAttachment: (value) => Effect.try({
907
- try: () => raw.serializeAttachment(value),
908
- catch: (cause) => new DurableWebSocketAttachmentError({
909
- operation: "serialize",
910
- cause
911
- })
912
- }),
913
- deserializeAttachment: Effect.try({
914
- try: () => raw.deserializeAttachment(),
915
- catch: (cause) => new DurableWebSocketAttachmentError({
916
- operation: "deserialize",
917
- cause
918
- })
919
- })
920
- };
921
- wrappers.set(raw, socket);
922
- return socket;
923
- };
924
- /**
925
- * Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
926
- *
927
- * @example
928
- * ```ts
929
- * const response = yield* DurableObjectWebSocket.acceptUpgrade({
930
- * tags: ["room:general"],
931
- * });
932
- *
933
- * return response.response;
934
- * ```
935
- */
936
- const acceptUpgrade = Effect.fn("DurableObjectWebSocket.acceptUpgrade")(function* (options = {}) {
937
- const state = yield* DurableObjectState;
938
- const pair = new WebSocketPair();
939
- const client = pair[0];
940
- const server = fromWebSocket(pair[1]);
941
- if (options.attachment !== void 0) yield* server.serializeAttachment(options.attachment);
942
- yield* state.acceptWebSocket(server, options.tags === void 0 ? void 0 : [...options.tags]);
943
- return {
944
- client,
945
- server,
946
- response: new Response(null, {
947
- status: 101,
948
- webSocket: client
949
- })
950
- };
951
- });
952
- /** Creates typed attachment helpers for accepted and rehydrated sockets. */
953
- const attachment = (schema) => {
954
- const serialize = (socket, value) => Schema.encodeEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
955
- operation: "serialize",
956
- cause
957
- })), Effect.flatMap((encoded) => socket.serializeAttachment(encoded)));
958
- const deserialize = (socket) => Effect.gen(function* () {
959
- const value = yield* socket.deserializeAttachment;
960
- if (value === null || value === void 0) return Option.none();
961
- return Option.some(yield* Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
962
- operation: "deserialize",
963
- cause
964
- }))));
965
- });
966
- const rehydrate = (options = {}) => Effect.gen(function* () {
967
- const sockets = yield* (yield* DurableObjectState).getWebSockets(options.tag);
968
- const restored = [];
969
- const onInvalid = options.onInvalid ?? "ignore";
970
- for (const socket of sockets) {
971
- const decoded = yield* Effect.result(deserialize(socket));
972
- if (Result.isSuccess(decoded) && Option.isSome(decoded.success)) {
973
- restored.push({
974
- socket,
975
- attachment: decoded.success.value
976
- });
977
- continue;
978
- }
979
- if (Result.isFailure(decoded) && onInvalid === "fail") return yield* Effect.fail(decoded.failure);
980
- if (Result.isFailure(decoded) && onInvalid === "ignore-and-close") yield* socket.close(1008, "invalid websocket attachment").pipe(Effect.ignore);
981
- }
982
- return restored;
983
- });
984
- return {
985
- serialize,
986
- deserialize,
987
- rehydrate,
988
- schema
989
- };
990
- };
991
- /** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
992
- const handlers = (options) => ({
993
- webSocketMessage: options.message,
994
- webSocketClose: options.close,
995
- webSocketError: options.error
996
- });
997
- //#endregion
998
- //#region src/internal/WorkerContext.ts
999
- const causeError = (cause) => {
1000
- const squashed = Cause.squash(cause);
1001
- return squashed instanceof Error ? squashed : new Error(Cause.pretty(cause), { cause: squashed });
1002
- };
1003
- const failureHandler = (label, cause, options) => (options?.onFailure?.(cause) ?? Effect.logError(`${label} failed`, Cause.pretty(cause))).pipe(Effect.catchCause((handlerCause) => Effect.logError(`${label} failure handler failed`, Cause.pretty(cause), Cause.pretty(handlerCause))));
1004
- /**
1005
- * Builds a `waitUntil` scheduler for any Cloudflare lifecycle that accepts
1006
- * background promises (`ExecutionContext`, `DurableObjectState`).
1007
- *
1008
- * Background effects capture the calling fiber's context via `Effect.context`
1009
- * before being registered, so the default module-level `Effect.runPromiseExit`
1010
- * runner is sufficient; entrypoints may still pass a runtime-bound runner.
1011
- */
1012
- const makeWaitUntilScheduler = (label, register, runPromiseExit = (effect) => Effect.runPromiseExit(effect)) => {
1013
- return (effect, options, mode) => Effect.context().pipe(Effect.flatMap((context) => Effect.sync(() => {
1014
- const runHandler = (cause) => runPromiseExit(Effect.scoped(Effect.provideContext(failureHandler(label, cause, options), context))).then((exit) => {
1015
- if (Exit.isFailure(exit)) console.error(`${label} failure handler failed`, Cause.pretty(exit.cause));
1016
- });
1017
- register(runPromiseExit(Effect.scoped(Effect.provideContext(effect, context))).then(async (exit) => {
1018
- if (Exit.isSuccess(exit)) return;
1019
- await runHandler(exit.cause);
1020
- if (mode === "propagate") throw causeError(exit.cause);
1021
- }));
1022
- })));
1023
- };
1024
- /**
1025
- * Builds the `WorkerContext` service from a native `ExecutionContext`.
1026
- */
1027
- const fromExecutionContext = (ctx, runPromiseExit = (effect) => Effect.runPromiseExit(effect)) => {
1028
- const schedule = makeWaitUntilScheduler("WorkerContext.waitUntil", (promise) => ctx.waitUntil(promise), runPromiseExit);
1029
- return {
1030
- raw: ctx,
1031
- waitUntil: (effect, options) => schedule(effect, options, options?.mode ?? "observe"),
1032
- waitUntilPropagating: (effect, options) => schedule(effect, options, "propagate"),
1033
- passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
1034
- };
1035
- };
1036
- //#endregion
1037
- //#region src/DurableObjectState.ts
1038
- var DurableObjectState_exports = /* @__PURE__ */ __exportAll({
1039
- DurableObjectState: () => DurableObjectState,
1040
- fromDurableObjectState: () => fromDurableObjectState
1041
- });
1042
- /**
1043
- * Context tag for accessing the current Durable Object state service.
1044
- */
1045
- var DurableObjectState = class extends Context.Service()("effect-cf/DurableObjectState") {};
1046
- /**
1047
- * Wraps a native Cloudflare `DurableObjectState` as a {@link DurableObjectStateService}.
1048
- */
1049
- const fromDurableObjectState = (state) => {
1050
- const scheduleWaitUntil = makeWaitUntilScheduler("DurableObjectState.waitUntil", (promise) => state.waitUntil(promise));
1051
- const waitUntil = ((input, options) => Effect.isEffect(input) ? scheduleWaitUntil(input, options, options?.mode ?? "observe") : Effect.sync(() => state.waitUntil(input)));
1052
- return {
1053
- raw: state,
1054
- id: state.id,
1055
- storage: fromDurableObjectStorage(state.storage),
1056
- waitUntil,
1057
- blockConcurrencyWhile: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => runPromiseExitPreservingTypedFailures(context, effect)))), Effect.flatten),
1058
- blockConcurrencyWhileOrReset: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => Effect.runPromiseWith(context)(effect))))),
1059
- acceptWebSocket: (ws, tags) => Effect.sync(() => state.acceptWebSocket(ws.raw, tags)),
1060
- getWebSockets: (tag) => Effect.sync(() => state.getWebSockets(tag).map((socket) => fromWebSocket(socket))),
1061
- setWebSocketAutoResponse: (pair) => Effect.sync(() => state.setWebSocketAutoResponse(pair)),
1062
- getWebSocketAutoResponse: Effect.sync(() => state.getWebSocketAutoResponse()),
1063
- getWebSocketAutoResponseTimestamp: (ws) => Effect.sync(() => state.getWebSocketAutoResponseTimestamp(ws.raw)),
1064
- setHibernatableWebSocketEventTimeout: (timeoutMs) => Effect.sync(() => state.setHibernatableWebSocketEventTimeout(timeoutMs)),
1065
- getHibernatableWebSocketEventTimeout: Effect.sync(() => state.getHibernatableWebSocketEventTimeout()),
1066
- getTags: (ws) => Effect.sync(() => state.getTags(ws.raw)),
1067
- abort: (reason) => Effect.sync(() => state.abort(reason))
1068
- };
1069
- };
1070
- const runPromiseExitPreservingTypedFailures = async (context, effect) => {
1071
- const exit = await Effect.runPromiseExitWith(context)(effect);
1072
- if (Exit.isFailure(exit) && (Cause.hasDies(exit.cause) || Cause.hasInterrupts(exit.cause))) throw Cause.squash(exit.cause);
1073
- return exit;
1074
- };
1075
- //#endregion
1076
696
  //#region src/CloudflareOtlp.ts
1077
697
  /**
1078
698
  * OTLP telemetry layers for Cloudflare Workers and Durable Objects.
@@ -3745,7 +3365,7 @@ const makeClient = (definition) => {
3745
3365
  terminate: operation("terminate", () => raw.terminate()),
3746
3366
  restart: (options) => operation("restart", () => raw.restart(options)),
3747
3367
  status: operation("status", () => raw.status()).pipe(Effect.flatMap((status) => Effect.gen(function* () {
3748
- const output = status.output === void 0 ? Option.none() : Option.some(yield* decodeResult(status.output).pipe(Effect.mapError((cause) => new WorkflowResultDecodeError({
3368
+ const output = status.output === void 0 || status.output === null && status.status !== "complete" ? Option.none() : Option.some(yield* decodeResult(status.output).pipe(Effect.mapError((cause) => new WorkflowResultDecodeError({
3749
3369
  binding: definition.binding,
3750
3370
  instanceId: raw.id,
3751
3371
  cause
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,6 +27,11 @@
27
27
  "import": "./dist/HyperdrivePg.mjs",
28
28
  "default": "./dist/HyperdrivePg.mjs"
29
29
  },
30
+ "./vitest": {
31
+ "types": "./dist/Vitest.d.mts",
32
+ "import": "./dist/Vitest.mjs",
33
+ "default": "./dist/Vitest.mjs"
34
+ },
30
35
  "./package.json": "./package.json"
31
36
  },
32
37
  "publishConfig": {
@@ -53,6 +58,7 @@
53
58
  "vitest": "catalog:"
54
59
  },
55
60
  "peerDependencies": {
61
+ "@cloudflare/vitest-pool-workers": "^0.21.3",
56
62
  "@cloudflare/workers-types": "^4.20260611.1",
57
63
  "@effect/sql-d1": "4.0.0-beta.105",
58
64
  "@effect/sql-pg": "4.0.0-beta.105",
@@ -60,6 +66,9 @@
60
66
  "effect": "4.0.0-beta.105"
61
67
  },
62
68
  "peerDependenciesMeta": {
69
+ "@cloudflare/vitest-pool-workers": {
70
+ "optional": true
71
+ },
63
72
  "@cloudflare/workers-types": {
64
73
  "optional": true
65
74
  },