@effect-agent/platform-cloudflare 0.1.0-beta.24 → 0.1.0-beta.26

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,13 +1,13 @@
1
- import { Clock, Context, Crypto, Deferred, Duration, Effect, Exit, Fiber, Layer, Option, PubSub, Queue, Random, Ref, Schema, Semaphore, Stream } from "effect";
1
+ import { Clock, Context, Crypto, Deferred, Duration, Effect, Exit, Fiber, Layer, Option, Predicate, PubSub, Queue, Random, Ref, Schema, Semaphore, Stream } from "effect";
2
2
  import { AbortCommand, AbortIntent, AdmissionConflict, AgentBindingResolver, AppendConflict, ApprovalConflict, ApprovalDecisionCommand, ApprovalDecisionIntent, CanonicalRecordEnvelope, CanonicalSequence, ConversationNotMaterialized, ConversationRead, ConversationStore, ConversationStoreError, DEFAULT_OWNERSHIP_LEASE_DURATION, DefinitionDigests, DeploymentId, DigestError, DurableAgentRuntime, DurableRuntimeConfig, DurableRuntimeFailpoint, DurableRuntimeFailpointError, FenceRejected, IdempotencyKey, IntegrityReport, JoinedToHost, LedgerError, ObligationReport, ObligationThresholds, OperationAuthorizationRequest, OperationAuthorizer, OperationDenied, OwnershipLost, PersistedJson, Principal, ProducerId, Receipt, RecoveryExplanation, RecoveryReport, RetryCommand, RetryRefused, RunJournalError, Settlement, SettlementConflict, SubmissionLedger, SubmissionLookupByKey, ToolReconciler, UnknownResolutionCommand, UnknownResolutionConflict, UnknownResolutionIntent, WakeScheduler, makeWakeSubscriptionHub, operationAuthorizerLayer } from "@effect-agent/session";
3
- import { ConversationPortTransport, DEFAULT_MAX_STORED_VALUE_BYTES, conversationStoreLayer, handleEncodedPortRequest, portTransportFailure, routedConversationStoreLayer, routedSubmissionLedgerLayer, storageConfigLayer, storageFailpointLayer, submissionLedgerLayer } from "@effect-agent/storage-cloudflare";
3
+ import { ConversationPortTransport, DEFAULT_MAX_STORED_VALUE_BYTES, conversationStoreLayer, decodePortRequest, encodePortResponse, executePortRequest, portTransportFailure, routedConversationStoreLayer, routedSubmissionLedgerLayer, storageConfigLayer, storageFailpointLayer, submissionLedgerLayer } from "@effect-agent/storage-cloudflare";
4
4
  import { AgentId, AgentInputError, ConversationId, SubmissionId } from "@effect-agent/core";
5
5
  import { RunContextPreparationPassthrough } from "@effect-agent/engine";
6
6
  import { BrowserCrypto } from "@effect/platform-browser";
7
7
  import { SqliteClient } from "@effect/sql-sqlite-do";
8
8
  import { DurableObject, DurableObjectState, WorkerEnvironment } from "effect-cf";
9
9
  import { CodeExecutionHost, CodeExecutionProtocolError, CodeExecutionResourceUse, CodeExecutionResult, CodeExecutionTimeoutError, CodeExecutor, CodeExecutorStartError, CodeExecutorTerminatedError, CodeExecutorUnsupportedError, CodeHostCall, CodeHostCallLimitError, CodeHostCallResult, CodeOutputLimitError, CodeProgramFailedError, CodeSourceError, SandboxImplementation } from "@effect-agent/sandbox";
10
- import { WorkerEntrypoint } from "cloudflare:workers";
10
+ import { RpcTarget } from "cloudflare:workers";
11
11
  //#region src/bindings.ts
12
12
  /**
13
13
  * Cloudflare platform bindings as Effect services (DEPLOY-010: "Cloudflare platform bindings
@@ -36,17 +36,29 @@ var ConversationObjectNamespace = class ConversationObjectNamespace extends Cont
36
36
  * narrowest-boundary check (structural probe for the namespace surface the transport uses);
37
37
  * a missing or misshaped binding fails typed before any Layer is built.
38
38
  */
39
- const conversationNamespaceFromEnv = (env, binding) => Effect.suspend(() => {
40
- if (typeof env !== "object" || env === null) return Effect.fail(CloudflareBindingError.make({
39
+ const conversationNamespaceFromEnv = Effect.fn("conversationNamespaceFromEnv")(function* (env, binding) {
40
+ if (!Predicate.isObjectKeyword(env)) return yield* CloudflareBindingError.make({
41
41
  binding,
42
42
  message: "The Worker environment is not an object; no bindings are available."
43
- }));
44
- const candidate = env[binding];
45
- if (typeof candidate === "object" && candidate !== null && "idFromName" in candidate && typeof candidate.idFromName === "function" && "get" in candidate && typeof candidate.get === "function") return Effect.succeed(candidate);
46
- return Effect.fail(CloudflareBindingError.make({
43
+ });
44
+ const candidate = yield* Effect.try({
45
+ try: () => {
46
+ const value = Reflect.get(env, binding);
47
+ if (!Predicate.isObjectKeyword(value)) return void 0;
48
+ const idFromName = Reflect.get(value, "idFromName");
49
+ const get = Reflect.get(value, "get");
50
+ return typeof idFromName === "function" && typeof get === "function" ? value : void 0;
51
+ },
52
+ catch: () => CloudflareBindingError.make({
53
+ binding,
54
+ message: `env.${binding} could not be inspected as a DurableObjectNamespace binding.`
55
+ })
56
+ });
57
+ if (candidate !== void 0) return candidate;
58
+ return yield* CloudflareBindingError.make({
47
59
  binding,
48
60
  message: `env.${binding} is not a DurableObjectNamespace binding; declare the Conversation Object class under this binding in the Worker configuration.`
49
- }));
61
+ });
50
62
  });
51
63
  /** `ConversationObjectNamespace` built from the untyped Worker `env` (fails typed). */
52
64
  const conversationNamespaceLayer = (env, binding) => Layer.effect(ConversationObjectNamespace)(Effect.map(conversationNamespaceFromEnv(env, binding), (namespace) => ({ namespace })));
@@ -174,6 +186,44 @@ const CLOUDFLARE_RUNTIME_DEFAULTS = {
174
186
  maxDatabaseBytes: DEFAULT_MAX_DATABASE_BYTES
175
187
  };
176
188
  //#endregion
189
+ //#region src/boundary.ts
190
+ const MAX_FOREIGN_DIAGNOSTIC_LENGTH = 8192;
191
+ const boundForeignDiagnostic = (message) => message.slice(0, MAX_FOREIGN_DIAGNOSTIC_LENGTH);
192
+ /** Render a foreign failure without trusting accessors or coercion hooks on the value. */
193
+ const safeCauseMessage = (cause, fallback) => {
194
+ try {
195
+ const message = cause instanceof Error ? cause.message : cause;
196
+ return boundForeignDiagnostic(typeof message === "string" ? message : String(message));
197
+ } catch {
198
+ return boundForeignDiagnostic(fallback);
199
+ }
200
+ };
201
+ /** Include an Error name when worker-failure classification needs it. */
202
+ const safeCauseDiagnostic = (cause, fallback) => {
203
+ try {
204
+ return cause instanceof Error ? boundForeignDiagnostic(`${cause.name}: ${cause.message}`) : safeCauseMessage(cause, fallback);
205
+ } catch {
206
+ return boundForeignDiagnostic(fallback);
207
+ }
208
+ };
209
+ /** Read Cloudflare RPC classifications without letting a hostile proxy defect the client. */
210
+ const cloudflareFailureSignals = (cause) => {
211
+ if (!Predicate.isObjectKeyword(cause)) return {};
212
+ try {
213
+ const retryableValue = Reflect.get(cause, "retryable");
214
+ const overloadedValue = Reflect.get(cause, "overloaded");
215
+ const resetValue = Reflect.get(cause, "durableObjectReset");
216
+ const retryable = typeof retryableValue === "boolean" ? retryableValue : resetValue === true ? true : void 0;
217
+ const overloaded = typeof overloadedValue === "boolean" ? overloadedValue : void 0;
218
+ return {
219
+ ...retryable === void 0 ? {} : { retryable },
220
+ ...overloaded === void 0 ? {} : { overloaded }
221
+ };
222
+ } catch {
223
+ return {};
224
+ }
225
+ };
226
+ //#endregion
177
227
  //#region src/alarm.ts
178
228
  /**
179
229
  * The single multiplexed Durable Object alarm (decision D-P6-2). A Durable Object has ONE
@@ -194,7 +244,7 @@ var DurableAlarmError = class extends Schema.TaggedError()("DurableAlarmError",
194
244
  }) {};
195
245
  const alarmFailure = (operation) => (cause) => DurableAlarmError.make({
196
246
  operation,
197
- message: cause instanceof Error ? cause.message : String(cause),
247
+ message: safeCauseMessage(cause, "The Cloudflare alarm API failed without a diagnostic"),
198
248
  cause
199
249
  });
200
250
  /** `ctx.storage` alarm slot as an Effect service; storage is truth, never a memory field. */
@@ -505,7 +555,7 @@ const cloudflareWakeSchedulerLayer = Layer.effect(WakeScheduler)(Effect.gen(func
505
555
  try: () => namespace.get(namespace.idFromName(conversationId)).wake(),
506
556
  catch: (cause) => RemoteWakeDropped.make({
507
557
  conversationId,
508
- message: cause instanceof Error ? cause.message : String(cause),
558
+ message: safeCauseMessage(cause, "The remote wake failed without a diagnostic"),
509
559
  cause
510
560
  })
511
561
  }).pipe(Effect.catch((error) => Effect.logWarning(`CloudflareWakeScheduler: remote wake of ${conversationId} dropped`, error)), Effect.asVoid);
@@ -605,10 +655,10 @@ const conversationPortTransportLayer = Layer.effect(ConversationPortTransport)(E
605
655
  //#endregion
606
656
  //#region src/layers.ts
607
657
  /**
608
- * Owner-side endpoint body for the Conversation Object's `portCall` (plan §1.3): decode,
609
- * execute against THIS Object's LOCAL port facets — never the routed decorators, so a
610
- * request cannot bounce between Objects — and answer the encoded response envelope. Total by
611
- * construction (protocol anomalies answer `PortFailed(PortProtocolError)`).
658
+ * Owner-side execution port for a `portCall` request the wire endpoint has already decoded.
659
+ * It executes against THIS Object's LOCAL port facets — never the routed decorators, so a
660
+ * request cannot bounce between Objects — and returns the typed response for the endpoint to
661
+ * encode.
612
662
  */
613
663
  var ConversationObjectPorts = class extends Context.Service()("@effect-agent/platform-cloudflare/ConversationObjectPorts") {};
614
664
  const decodeConfigValue = Schema.decodeUnknownEffect(CloudflareDurableRuntimeConfigValue);
@@ -645,10 +695,7 @@ const conversationIdFromState = (ctx) => ctx.id.name === void 0 ? Effect.fail(Cl
645
695
  message: `The Durable Object name is not a valid ConversationId: ${error.message}`,
646
696
  cause: error
647
697
  })));
648
- const resolveBindings = (source, context) => source === void 0 ? Effect.succeed([]) : Effect.isEffect(source) ? source : typeof source === "function" ? Effect.suspend(() => {
649
- const bindings = source(context);
650
- return Effect.isEffect(bindings) ? bindings : Effect.succeed(bindings);
651
- }) : Effect.succeed(source);
698
+ const resolveBindings = (source, context) => source === void 0 ? Effect.succeed([]) : Effect.suspend(() => source(context));
652
699
  const resolveRunContext = (source, context) => typeof source === "function" ? source(context) : source;
653
700
  /**
654
701
  * The DC Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint;
@@ -699,7 +746,7 @@ var CloudflareDurableRuntime = class {
699
746
  const localPorts = Layer.mergeAll(conversationStoreLayer, submissionLedgerLayer).pipe(Layer.provide(infrastructure));
700
747
  const portsEndpointLayer = Layer.effect(ConversationObjectPorts)(Effect.gen(function* () {
701
748
  const local = yield* Effect.context();
702
- return ConversationObjectPorts.of({ handle: (encoded) => handleEncodedPortRequest(encoded).pipe(Effect.provide(local)) });
749
+ return ConversationObjectPorts.of({ handle: (request) => executePortRequest(request).pipe(Effect.provide(local)) });
703
750
  })).pipe(Layer.provide(localPorts));
704
751
  const routedPorts = Layer.mergeAll(routedSubmissionLedgerLayer({ localConversationId: conversationId }), routedConversationStoreLayer({ localConversationId: conversationId })).pipe(Layer.provide(localPorts), Layer.provide(conversationPortTransportLayer));
705
752
  const runtimeConfigLayer = Layer.succeed(DurableRuntimeConfig)(DurableRuntimeConfig.make({
@@ -852,107 +899,88 @@ const decodeUnknownResolutionCommand = Schema.decodeUnknownEffect(UnknownResolut
852
899
  const encodeUnknownResolutionCommand = Schema.encodeEffect(UnknownResolutionCommand);
853
900
  const encodeHostResponse = Schema.encodeEffect(HostResponse);
854
901
  const decodeHostResponse = Schema.decodeUnknownEffect(HostResponse);
855
- const SUBMIT_FAILURE_TAGS = /* @__PURE__ */ new Set([
856
- "AgentInputError",
857
- "DigestError",
858
- "AdmissionConflict",
859
- "LedgerError",
860
- "ConversationStoreError",
861
- "ConversationNotMaterialized",
862
- "AppendConflict",
863
- "FenceRejected",
864
- "DurableRuntimeFailpointError",
865
- "AdmissionLimitExceeded",
866
- "DurableAlarmError",
867
- "HostProtocolError"
902
+ /** Failure surface of `CloudflareConversationClient.submit`. */
903
+ const ClientSubmitHostFailure = Schema.Union([
904
+ AgentInputError,
905
+ DigestError,
906
+ AdmissionConflict,
907
+ LedgerError,
908
+ ConversationStoreError,
909
+ ConversationNotMaterialized,
910
+ AppendConflict,
911
+ FenceRejected,
912
+ DurableRuntimeFailpointError,
913
+ AdmissionLimitExceeded,
914
+ DurableAlarmError,
915
+ HostProtocolError
868
916
  ]);
869
- const AWAIT_FAILURE_TAGS = /* @__PURE__ */ new Set([
870
- "LedgerError",
871
- "SettlementConflict",
872
- "HostProtocolError"
917
+ const ClientAwaitHostFailure = Schema.Union([
918
+ LedgerError,
919
+ SettlementConflict,
920
+ HostProtocolError
873
921
  ]);
874
- const OBSERVE_FAILURE_TAGS = /* @__PURE__ */ new Set([
875
- "ConversationStoreError",
876
- "ConversationNotMaterialized",
877
- "OperationDenied",
878
- "HostProtocolError"
922
+ const ClientObserveHostFailure = Schema.Union([
923
+ ConversationStoreError,
924
+ ConversationNotMaterialized,
925
+ OperationDenied,
926
+ HostProtocolError
879
927
  ]);
880
- const PROGRESS_FAILURE_TAGS = OBSERVE_FAILURE_TAGS;
881
- const ABORT_FAILURE_TAGS = /* @__PURE__ */ new Set([
882
- "LedgerError",
883
- "SettlementConflict",
884
- "JoinedToHost",
885
- "DurableRuntimeFailpointError",
886
- "DurableAlarmError",
887
- "HostProtocolError"
928
+ const ClientAbortHostFailure = Schema.Union([
929
+ LedgerError,
930
+ SettlementConflict,
931
+ JoinedToHost,
932
+ DurableRuntimeFailpointError,
933
+ DurableAlarmError,
934
+ HostProtocolError
888
935
  ]);
889
- const APPROVAL_FAILURE_TAGS = /* @__PURE__ */ new Set([
890
- "LedgerError",
891
- "SettlementConflict",
892
- "ApprovalConflict",
893
- "OperationDenied",
894
- "DurableAlarmError",
895
- "HostProtocolError"
936
+ const ClientApprovalHostFailure = Schema.Union([
937
+ LedgerError,
938
+ SettlementConflict,
939
+ ApprovalConflict,
940
+ OperationDenied,
941
+ DurableAlarmError,
942
+ HostProtocolError
896
943
  ]);
897
- const UNKNOWN_FAILURE_TAGS = /* @__PURE__ */ new Set([
898
- "LedgerError",
899
- "SettlementConflict",
900
- "UnknownResolutionConflict",
901
- "JoinedToHost",
902
- "DurableRuntimeFailpointError",
903
- "OperationDenied",
904
- "DurableAlarmError",
905
- "HostProtocolError"
944
+ const ClientUnknownHostFailure = Schema.Union([
945
+ LedgerError,
946
+ SettlementConflict,
947
+ UnknownResolutionConflict,
948
+ JoinedToHost,
949
+ DurableRuntimeFailpointError,
950
+ OperationDenied,
951
+ DurableAlarmError,
952
+ HostProtocolError
906
953
  ]);
907
954
  const outOfContract = (conversationId, operation, observed) => ConversationClientError.make({
908
955
  conversationId,
909
956
  message: boundHostDiagnostic(`The Conversation Object answered ${operation} with the out-of-contract ${observed}.`)
910
957
  });
911
- /**
912
- * Narrow one decoded `HostFailed.failure` to the operation's declared failure family; an
913
- * out-of-contract tag folds into `ConversationClientError` instead of being erased or
914
- * re-thrown raw (the WP2 discipline). The predicate is the single documented narrowing over
915
- * the closed `HostFailure` union.
916
- */
917
- const narrowFailure = (tags) => (failure) => tags.has(failure._tag);
918
958
  /** Worker-side client over the Conversation Object namespace (DEPLOY-010). */
919
959
  var CloudflareConversationClient = class CloudflareConversationClient extends Context.Service()("@effect-agent/platform-cloudflare/CloudflareConversationClient") {
920
960
  static layer = Layer.effect(CloudflareConversationClient)(Effect.gen(function* () {
921
961
  const { namespace } = yield* ConversationObjectNamespace;
922
962
  const crypto = yield* Crypto.Crypto;
923
- const platformSignals = (cause) => {
924
- let retryable;
925
- let overloaded;
926
- if (typeof cause === "object" && cause !== null) {
927
- if ("retryable" in cause && typeof cause.retryable === "boolean") retryable = cause.retryable;
928
- if ("overloaded" in cause && typeof cause.overloaded === "boolean") overloaded = cause.overloaded;
929
- if (retryable === void 0 && "durableObjectReset" in cause && cause.durableObjectReset === true) retryable = true;
930
- }
931
- return {
932
- ...retryable === void 0 ? {} : { retryable },
933
- ...overloaded === void 0 ? {} : { overloaded }
934
- };
935
- };
936
963
  const call = (conversationId, operation, invoke) => Effect.tryPromise({
937
964
  try: () => invoke(namespace.get(namespace.idFromName(conversationId))),
938
965
  catch: (cause) => ConversationClientError.make({
939
966
  conversationId,
940
- message: boundHostDiagnostic(`${operation} did not reach the Conversation Object: ${cause instanceof Error ? cause.message : String(cause)}`),
967
+ message: boundHostDiagnostic(`${operation} did not reach the Conversation Object: ${safeCauseMessage(cause, "the RPC failed without a diagnostic")}`),
941
968
  cause,
942
- ...platformSignals(cause)
969
+ ...cloudflareFailureSignals(cause)
943
970
  })
944
971
  }).pipe(Effect.flatMap((raw) => decodeHostResponse(raw).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`The ${operation} answer could not be decoded: ${error.message}`) })))), Effect.withSpan("CloudflareConversationClient.call", { attributes: {
945
972
  conversationId,
946
973
  operation
947
974
  } }));
948
- const expect = (conversationId, operation, resultTag, tags) => {
949
- const isExpected = narrowFailure(tags);
975
+ const expect = (conversationId, operation, resultSchema, failureSchema) => {
976
+ const isExpectedResult = Schema.is(resultSchema);
977
+ const isExpectedFailure = Schema.is(failureSchema);
950
978
  return (response) => {
951
979
  if (response._tag === "HostFailed") {
952
980
  const failure = response.failure;
953
- return isExpected(failure) ? Effect.fail(failure) : Effect.fail(outOfContract(conversationId, operation, `failure ${failure._tag}`));
981
+ return isExpectedFailure(failure) ? Effect.fail(failure) : Effect.fail(outOfContract(conversationId, operation, `failure ${failure._tag}`));
954
982
  }
955
- if (response._tag !== resultTag) return Effect.fail(outOfContract(conversationId, operation, `result ${response._tag}`));
983
+ if (!isExpectedResult(response)) return Effect.fail(outOfContract(conversationId, operation, `result ${response._tag}`));
956
984
  return Effect.succeed(response);
957
985
  };
958
986
  };
@@ -963,7 +991,7 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
963
991
  });
964
992
  const encoded = yield* encodeObservePageRequest(request).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`observePage request encode failed: ${error.message}`) })));
965
993
  const response = yield* call(conversationId, "observePage", (stub) => stub.observePage(encoded));
966
- return (yield* expect(conversationId, "observePage", "ObservedPage", OBSERVE_FAILURE_TAGS)(response)).records;
994
+ return (yield* expect(conversationId, "observePage", ObservedPage, ClientObserveHostFailure)(response)).records;
967
995
  });
968
996
  const cancelProgress = (conversationId, waiterId) => encodeCancelProgressRequest(CancelProgressRequest.make({ waiterId })).pipe(Effect.mapError(() => void 0), Effect.flatMap((encoded) => call(conversationId, "cancelProgress", (stub) => stub.cancelProgressEncoded(encoded))), Effect.asVoid, Effect.ignore);
969
997
  return CloudflareConversationClient.of({
@@ -979,12 +1007,12 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
979
1007
  });
980
1008
  const encoded = yield* encodeSubmitRequest(request).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`submit request encode failed: ${error.message}`) })));
981
1009
  const response = yield* call(options.conversationId, "submit", (stub) => stub.submitEncoded(encoded));
982
- return (yield* expect(options.conversationId, "submit", "SubmitSucceeded", SUBMIT_FAILURE_TAGS)(response)).receipt;
1010
+ return (yield* expect(options.conversationId, "submit", SubmitSucceeded, ClientSubmitHostFailure)(response)).receipt;
983
1011
  }),
984
1012
  awaitSettlement: (receipt) => Effect.gen(function* () {
985
1013
  const encoded = yield* encodeReceipt(receipt).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`receipt encode failed: ${error.message}`) })));
986
1014
  const response = yield* call(receipt.conversationId, "awaitSettlement", (stub) => stub.awaitSettlementEncoded(encoded));
987
- return (yield* expect(receipt.conversationId, "awaitSettlement", "SettlementReached", AWAIT_FAILURE_TAGS)(response)).settlement;
1015
+ return (yield* expect(receipt.conversationId, "awaitSettlement", SettlementReached, ClientAwaitHostFailure)(response)).settlement;
988
1016
  }),
989
1017
  awaitProgress: (conversationId, afterSequence) => Effect.gen(function* () {
990
1018
  const waiterId = yield* crypto.randomUUIDv4.pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`awaitProgress cancellation identity generation failed: ${error.message}`) })));
@@ -993,7 +1021,7 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
993
1021
  waiterId
994
1022
  });
995
1023
  const encoded = yield* encodeAwaitProgressRequest(request).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`awaitProgress request encode failed: ${error.message}`) })));
996
- const attempt = (retry) => call(conversationId, "awaitProgress", (stub) => stub.awaitProgressEncoded(encoded)).pipe(Effect.flatMap(expect(conversationId, "awaitProgress", "ProgressObserved", PROGRESS_FAILURE_TAGS)), Effect.asVoid, Effect.catchTag("ConversationClientError", (error) => error.retryable === true && error.overloaded !== true && retry < 5 ? Effect.sleep(Duration.millis(10 * 2 ** retry)).pipe(Effect.andThen(attempt(retry + 1))) : Effect.fail(error)));
1024
+ const attempt = (retry) => call(conversationId, "awaitProgress", (stub) => stub.awaitProgressEncoded(encoded)).pipe(Effect.flatMap(expect(conversationId, "awaitProgress", ProgressObserved, ClientObserveHostFailure)), Effect.asVoid, Effect.catchTag("ConversationClientError", (error) => error.retryable === true && error.overloaded !== true && retry < 5 ? Effect.sleep(Duration.millis(10 * 2 ** retry)).pipe(Effect.andThen(attempt(retry + 1))) : Effect.fail(error)));
997
1025
  yield* attempt(0).pipe(Effect.onInterrupt(() => cancelProgress(conversationId, waiterId)));
998
1026
  }),
999
1027
  readPage,
@@ -1014,33 +1042,40 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
1014
1042
  abort: (conversationId, command) => Effect.gen(function* () {
1015
1043
  const encoded = yield* encodeAbortCommand(command).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`abort command encode failed: ${error.message}`) })));
1016
1044
  const response = yield* call(conversationId, "abort", (stub) => stub.abortEncoded(encoded));
1017
- return (yield* expect(conversationId, "abort", "AbortRecorded", ABORT_FAILURE_TAGS)(response)).intent;
1045
+ return (yield* expect(conversationId, "abort", AbortRecorded, ClientAbortHostFailure)(response)).intent;
1018
1046
  }),
1019
1047
  resolveApproval: (conversationId, command) => Effect.gen(function* () {
1020
1048
  const encoded = yield* encodeApprovalDecisionCommand(command).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`approval command encode failed: ${error.message}`) })));
1021
1049
  const response = yield* call(conversationId, "resolveApproval", (stub) => stub.resolveApprovalEncoded(encoded));
1022
- return (yield* expect(conversationId, "resolveApproval", "ApprovalRecorded", APPROVAL_FAILURE_TAGS)(response)).intent;
1050
+ return (yield* expect(conversationId, "resolveApproval", ApprovalRecorded, ClientApprovalHostFailure)(response)).intent;
1023
1051
  }),
1024
1052
  resolveUnknown: (conversationId, command) => Effect.gen(function* () {
1025
1053
  const encoded = yield* encodeUnknownResolutionCommand(command).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`resolution command encode failed: ${error.message}`) })));
1026
1054
  const response = yield* call(conversationId, "resolveUnknown", (stub) => stub.resolveUnknownEncoded(encoded));
1027
- return (yield* expect(conversationId, "resolveUnknown", "UnknownResolutionRecorded", UNKNOWN_FAILURE_TAGS)(response)).intent;
1055
+ return (yield* expect(conversationId, "resolveUnknown", UnknownResolutionRecorded, ClientUnknownHostFailure)(response)).intent;
1028
1056
  })
1029
1057
  });
1030
1058
  }));
1031
1059
  };
1032
1060
  //#endregion
1033
1061
  //#region src/conversation-object.ts
1034
- /** Port envelope tags whose owner-side execution durably mutates this Object's lane. */
1035
- const MUTATING_PORT_TAGS = /* @__PURE__ */ new Set([
1036
- "LedgerAdmit",
1037
- "LedgerMarkReady",
1038
- "LedgerRequestAbort",
1039
- "LedgerRecordChildSettled",
1040
- "StoreMaterialize",
1041
- "StoreAppend"
1042
- ]);
1043
- const isMutatingPortRequest = (encoded) => typeof encoded === "object" && encoded !== null && "_tag" in encoded && typeof encoded._tag === "string" && MUTATING_PORT_TAGS.has(encoded._tag);
1062
+ /** Classify only a decoded port request so new protocol members cannot bypass pre-arming. */
1063
+ const isMutatingPortRequest = (request) => {
1064
+ switch (request._tag) {
1065
+ case "LedgerAdmit":
1066
+ case "LedgerMarkReady":
1067
+ case "LedgerRequestAbort":
1068
+ case "LedgerRecordChildSettled":
1069
+ case "StoreMaterialize":
1070
+ case "StoreAppend": return true;
1071
+ case "LedgerLookup":
1072
+ case "LedgerResolveAdmission":
1073
+ case "StoreReadPage":
1074
+ case "StoreInspectTail":
1075
+ case "StoreExport": return false;
1076
+ }
1077
+ return false;
1078
+ };
1044
1079
  /** The literal encoded `PortFailed(PortProtocolError)` fallback (same shape as WP2's). */
1045
1080
  const encodedPortProtocolFailure = (message) => ({
1046
1081
  _tag: "PortFailed",
@@ -1253,10 +1288,18 @@ const portCallEndpoint = (encoded) => Effect.gen(function* () {
1253
1288
  const ports = yield* ConversationObjectPorts;
1254
1289
  const maintenance = yield* ConversationMaintenance;
1255
1290
  const alarm = yield* DurableAlarmService;
1256
- const mutating = isMutatingPortRequest(encoded);
1257
- const handled = yield* (mutating ? maintenance.withMutation(ports.handle(encoded)) : ports.handle(encoded)).pipe(Effect.exit);
1291
+ const decoded = yield* decodePortRequest(encoded).pipe(Effect.map((request) => ({
1292
+ _tag: "success",
1293
+ request
1294
+ })), Effect.catch((error) => Effect.succeed({
1295
+ _tag: "failure",
1296
+ message: error.message
1297
+ })));
1298
+ if (decoded._tag === "failure") return encodedPortProtocolFailure(`The port request could not be decoded: ${decoded.message}`);
1299
+ const mutating = isMutatingPortRequest(decoded.request);
1300
+ const handled = yield* (mutating ? maintenance.withMutation(ports.handle(decoded.request)) : ports.handle(decoded.request)).pipe(Effect.exit);
1258
1301
  if (handled._tag === "Failure") return encodedPortProtocolFailure("The owner Object could not arm its maintenance alarm before the mutation.");
1259
- const response = handled.value;
1302
+ const response = yield* encodePortResponse(handled.value).pipe(Effect.catch((error) => Effect.succeed(encodedPortProtocolFailure(`The port response could not be encoded: ${error.message}`))));
1260
1303
  if (mutating) yield* alarm.scheduleNow.pipe(Effect.catch((error) => Effect.logWarning("ConversationObject.portCall: immediate re-arm failed", error)));
1261
1304
  return response;
1262
1305
  });
@@ -1343,36 +1386,32 @@ const makeConversationObjectClass = (options, observability) => {
1343
1386
  * The Cloudflare Dynamic Worker `CodeExecutor` adapter (C4 of ADR-0017;
1344
1387
  * DEPLOY-011). Each pass loads one fresh Worker through the Worker Loader
1345
1388
  * with `globalOutbound: null`, so generated code has no ambient network,
1346
- * bindings, or secrets; its only authority is the pass-scoped host stub that
1347
- * routes back to `CodeModeHostEntrypoint` and, from there, into the pass's
1348
- * `CodeExecutionHost` service. Platform CPU limits stop synchronous runaway
1349
- * programs; the executor-owned wall-clock deadline interrupts asynchronously
1350
- * suspended passes. Deployment class `E` only: the adapter records no
1351
- * persistent state and a later pass may run in a completely different
1352
- * isolate.
1389
+ * bindings, or secrets; its only authority is the pass-scoped RPC target that
1390
+ * routes back into the owning event's `CodeExecutionHost` service. Platform
1391
+ * CPU limits stop synchronous runaway programs; the executor-owned wall-clock
1392
+ * deadline interrupts asynchronously suspended passes. Deployment class `E`
1393
+ * only: the adapter records no persistent state and a later pass may run in a
1394
+ * completely different isolate.
1353
1395
  */
1354
1396
  const dynamicWorkerImplementation = SandboxImplementation.make({
1355
1397
  isolation: "isolated",
1356
1398
  identity: "cloudflare-dynamic-worker"
1357
1399
  });
1358
1400
  /**
1359
- * Live passes by identity. Entries are Scope-managed: registered when a pass
1360
- * opens and removed by its finalizer, so a stale harness (or a forged
1361
- * `passId`) cannot reach any host authority.
1401
+ * One object-capability endpoint for one execution pass. Workers RPC invokes
1402
+ * the target in the request context where it was created, so the native
1403
+ * Promise returned by `dispatch` and the Effect fiber that settles it share
1404
+ * one I/O owner. Passing the target as `run()`'s argument also scopes the
1405
+ * remote stub to that RPC call; no request state lives at module scope.
1362
1406
  */
1363
- const passRegistry = /* @__PURE__ */ new Map();
1364
- /**
1365
- * The host-side RPC target for dynamic workers. The application exposes it
1366
- * from its Worker entry (`export { CodeModeHostEntrypoint }`) and hands the
1367
- * adapter a same-instance stub — `ctx.exports.CodeModeHostEntrypoint()` in
1368
- * production (a self service binding may reach a different instance and must
1369
- * not be used there); tests bind it through Miniflare's `kCurrentWorker`.
1370
- */
1371
- var CodeModeHostEntrypoint = class extends WorkerEntrypoint {
1372
- async call(passId, hostCall) {
1373
- const pass = passRegistry.get(String(passId));
1374
- if (pass === void 0) throw new Error("Unknown Code Mode pass");
1375
- return pass.dispatch(hostCall);
1407
+ var CodeModePassHostTarget = class extends RpcTarget {
1408
+ #dispatch;
1409
+ constructor(dispatch) {
1410
+ super();
1411
+ this.#dispatch = dispatch;
1412
+ }
1413
+ call(hostCall) {
1414
+ return this.#dispatch(hostCall);
1376
1415
  }
1377
1416
  };
1378
1417
  /**
@@ -1407,9 +1446,8 @@ const safeJson = (value) => {
1407
1446
  };
1408
1447
 
1409
1448
  export default class CodeModeHarness extends WorkerEntrypoint {
1410
- async run() {
1411
- const config = JSON.parse(this.env.CODE_MODE_PASS);
1412
- const host = this.env.CODE_MODE_HOST;
1449
+ async run(host) {
1450
+ const config = this.env.CODE_MODE_PASS;
1413
1451
  const limits = config.limits;
1414
1452
  const logs = [];
1415
1453
  let logBytes = 0;
@@ -1447,7 +1485,7 @@ export default class CodeModeHarness extends WorkerEntrypoint {
1447
1485
  };
1448
1486
  throw new Error("code-mode host-call argument limit exceeded");
1449
1487
  }
1450
- const outcome = await host.call(config.passId, {
1488
+ const outcome = await host.call({
1451
1489
  namespace,
1452
1490
  method,
1453
1491
  argument: JSON.parse(argText),
@@ -1527,24 +1565,16 @@ export default class CodeModeHarness extends WorkerEntrypoint {
1527
1565
  }
1528
1566
  `;
1529
1567
  const BoundedLogs = Schema.Array(Schema.String.check(Schema.isMaxLength(16 * 1024))).check(Schema.isMaxLength(4096));
1530
- const HarnessCompleted = Schema.Struct({
1531
- _tag: Schema.Literal("completed"),
1568
+ const HarnessCompleted = Schema.TaggedStruct("completed", {
1532
1569
  value: Schema.Json,
1533
1570
  logs: BoundedLogs,
1534
1571
  hostCalls: Schema.Natural,
1535
1572
  logBytes: Schema.Natural,
1536
1573
  resultBytes: Schema.Natural
1537
1574
  });
1538
- const HarnessSourceInvalid = Schema.Struct({
1539
- _tag: Schema.Literal("source-invalid"),
1540
- message: Schema.String
1541
- });
1542
- const HarnessNotAFunction = Schema.Struct({
1543
- _tag: Schema.Literal("source-not-a-function"),
1544
- actual: Schema.String
1545
- });
1546
- const HarnessProgramFailed = Schema.Struct({
1547
- _tag: Schema.Literal("program-failed"),
1575
+ const HarnessSourceInvalid = Schema.TaggedStruct("source-invalid", { message: Schema.String });
1576
+ const HarnessNotAFunction = Schema.TaggedStruct("source-not-a-function", { actual: Schema.String });
1577
+ const HarnessProgramFailed = Schema.TaggedStruct("program-failed", {
1548
1578
  reason: Schema.Literals([
1549
1579
  "threw",
1550
1580
  "rejected",
@@ -1554,29 +1584,20 @@ const HarnessProgramFailed = Schema.Struct({
1554
1584
  message: Schema.String,
1555
1585
  logs: BoundedLogs
1556
1586
  });
1557
- const HarnessLogLimit = Schema.Struct({
1558
- _tag: Schema.Literal("log-limit"),
1587
+ const HarnessLogLimit = Schema.TaggedStruct("log-limit", {
1559
1588
  observed: Schema.Natural,
1560
1589
  logs: BoundedLogs
1561
1590
  });
1562
- const HarnessArgumentLimit = Schema.Struct({
1563
- _tag: Schema.Literal("argument-limit"),
1591
+ const HarnessArgumentLimit = Schema.TaggedStruct("argument-limit", {
1564
1592
  observed: Schema.Natural,
1565
1593
  logs: BoundedLogs
1566
1594
  });
1567
- const HarnessResultLimit = Schema.Struct({
1568
- _tag: Schema.Literal("result-limit"),
1595
+ const HarnessResultLimit = Schema.TaggedStruct("result-limit", {
1569
1596
  observed: Schema.Natural,
1570
1597
  logs: BoundedLogs
1571
1598
  });
1572
- const HarnessHostCallLimit = Schema.Struct({
1573
- _tag: Schema.Literal("host-call-limit"),
1574
- logs: BoundedLogs
1575
- });
1576
- const HarnessProtocol = Schema.Struct({
1577
- _tag: Schema.Literal("protocol"),
1578
- message: Schema.String
1579
- });
1599
+ const HarnessHostCallLimit = Schema.TaggedStruct("host-call-limit", { logs: BoundedLogs });
1600
+ const HarnessProtocol = Schema.TaggedStruct("protocol", { message: Schema.String });
1580
1601
  const HarnessOutcome = Schema.Union([
1581
1602
  HarnessCompleted,
1582
1603
  HarnessSourceInvalid,
@@ -1588,6 +1609,21 @@ const HarnessOutcome = Schema.Union([
1588
1609
  HarnessHostCallLimit,
1589
1610
  HarnessProtocol
1590
1611
  ]);
1612
+ const HarnessPassConfig = Schema.Struct({
1613
+ namespaces: Schema.Array(Schema.Struct({
1614
+ name: Schema.NonEmptyString,
1615
+ methods: Schema.Array(Schema.NonEmptyString).check(Schema.isMaxLength(64))
1616
+ })).check(Schema.isMaxLength(32)),
1617
+ limits: Schema.Struct({
1618
+ maxLogBytes: Schema.Natural,
1619
+ maxResultBytes: Schema.Natural,
1620
+ maxHostCalls: Schema.Natural,
1621
+ maxHostCallArgumentBytes: Schema.Natural
1622
+ })
1623
+ });
1624
+ const encodeHarnessPassConfig = Schema.encodeSync(HarnessPassConfig);
1625
+ const encodeJsonPayload = Schema.encodeSync(Schema.fromJsonString(Schema.Json));
1626
+ const decodeJsonPayload = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Json));
1591
1627
  const decodeHarnessOutcome = (value) => {
1592
1628
  try {
1593
1629
  return Schema.decodeUnknownOption(HarnessOutcome)(value);
@@ -1609,11 +1645,20 @@ const decodeHostCallResult = (value) => {
1609
1645
  return Option.none();
1610
1646
  }
1611
1647
  };
1648
+ /** Dispose a Cloudflare RPC handle when the runtime supplies its untyped disposal hook. @internal */
1649
+ const disposeRpcHandle = (handle) => Effect.try({
1650
+ try: () => {
1651
+ if (typeof handle !== "object" && typeof handle !== "function" || handle === null) return;
1652
+ if (!(Symbol.dispose in handle)) return;
1653
+ const dispose = Reflect.get(handle, Symbol.dispose);
1654
+ if (typeof dispose === "function") Reflect.apply(dispose, handle, []);
1655
+ },
1656
+ catch: (cause) => safeCauseDiagnostic(cause, "The Cloudflare RPC disposal hook failed without a diagnostic")
1657
+ }).pipe(Effect.catch((diagnostic) => Effect.logWarning(`Cloudflare RPC handle disposal failed: ${diagnostic}`).pipe(Effect.ignoreCause)));
1612
1658
  const encodeHostResultPayload = (outcome) => {
1613
1659
  try {
1614
1660
  const payload = outcome._tag === "CodeHostCallSuccess" ? outcome.value : outcome.error;
1615
- const encodedPayload = JSON.stringify(payload);
1616
- if (encodedPayload === void 0) return void 0;
1661
+ const encodedPayload = encodeJsonPayload(payload);
1617
1662
  return {
1618
1663
  encodedPayload,
1619
1664
  resultBytes: utf8ByteLength(encodedPayload)
@@ -1632,8 +1677,7 @@ const utf8ByteLength = (value) => {
1632
1677
  };
1633
1678
  /** Reserved global names the harness owns inside the dynamic worker. */
1634
1679
  const reservedHarnessGlobals = /* @__PURE__ */ new Set(["console"]);
1635
- const passCounterState = { next: 0 };
1636
- const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(function* (request) {
1680
+ const makeExecute = (options, clock) => Effect.fn("DynamicWorkerCodeExecutor.execute")(function* (request) {
1637
1681
  if (request.network._tag !== "NetworkDisabled") return yield* CodeExecutorUnsupportedError.make({
1638
1682
  implementation: dynamicWorkerImplementation,
1639
1683
  feature: "network",
@@ -1651,11 +1695,12 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1651
1695
  message: `Namespace ${namespace.name} collides with a harness binding`
1652
1696
  });
1653
1697
  const host = yield* CodeExecutionHost;
1654
- passCounterState.next += 1;
1655
- const passId = `code-mode-pass-${passCounterState.next}-${crypto.randomUUID()}`;
1656
- const startedAt = performance.now();
1657
- const passDeadline = startedAt + Duration.toMillis(request.limits.maxWallTime);
1658
- const remainingPassWallTime = () => Duration.millis(Math.max(0, passDeadline - performance.now()));
1698
+ const startedAt = clock.monotonicTimeNanosUnsafe();
1699
+ const passDeadline = startedAt + Duration.toNanosUnsafe(request.limits.maxWallTime);
1700
+ const remainingPassWallTime = () => {
1701
+ const now = clock.monotonicTimeNanosUnsafe();
1702
+ return Duration.nanos(passDeadline > now ? passDeadline - now : 0n);
1703
+ };
1659
1704
  let issuedHostCalls = 0;
1660
1705
  let passOpen = true;
1661
1706
  const queuedHostCalls = [];
@@ -1689,13 +1734,21 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1689
1734
  failPass(error);
1690
1735
  return yield* error;
1691
1736
  }
1692
- const normalizedPayload = JSON.parse(encoded.encodedPayload);
1737
+ const normalizedPayload = decodeJsonPayload(encoded.encodedPayload);
1738
+ if (Option.isNone(normalizedPayload)) {
1739
+ const error = CodeExecutionProtocolError.make({
1740
+ implementation: dynamicWorkerImplementation,
1741
+ message: "The execution host returned a result that could not cross the JSON boundary"
1742
+ });
1743
+ failPass(error);
1744
+ return yield* error;
1745
+ }
1693
1746
  queued.resolve(decoded.value._tag === "CodeHostCallSuccess" ? {
1694
1747
  _tag: "CodeHostCallSuccess",
1695
- value: normalizedPayload
1748
+ value: normalizedPayload.value
1696
1749
  } : {
1697
1750
  _tag: "CodeHostCallFailure",
1698
- error: normalizedPayload
1751
+ error: normalizedPayload.value
1699
1752
  });
1700
1753
  });
1701
1754
  const server = yield* Effect.gen(function* () {
@@ -1756,12 +1809,9 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1756
1809
  };
1757
1810
  const closeAdmission = Effect.sync(() => {
1758
1811
  passOpen = false;
1759
- passRegistry.delete(passId);
1760
1812
  rejectQueuedHostCalls(/* @__PURE__ */ new Error("Code Mode pass is closing"));
1761
1813
  });
1762
- yield* Effect.acquireRelease(Effect.sync(() => {
1763
- passRegistry.set(passId, { dispatch });
1764
- }), () => closeAdmission.pipe(Effect.andThen(Fiber.interrupt(server))));
1814
+ yield* Effect.addFinalizer(() => closeAdmission.pipe(Effect.andThen(Fiber.interrupt(server))));
1765
1815
  const workerCode = {
1766
1816
  compatibilityDate: options.compatibilityDate ?? "2025-05-01",
1767
1817
  mainModule: "harness.js",
@@ -1769,22 +1819,18 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1769
1819
  "harness.js": HARNESS_MODULE,
1770
1820
  "program.js": `export default (\n${request.source}\n);`
1771
1821
  },
1772
- env: {
1773
- CODE_MODE_HOST: options.hostStub,
1774
- CODE_MODE_PASS: JSON.stringify({
1775
- passId,
1776
- namespaces: request.namespaces.map((namespace) => ({
1777
- name: namespace.name,
1778
- methods: namespace.methods
1779
- })),
1780
- limits: {
1781
- maxLogBytes: request.limits.maxLogBytes,
1782
- maxResultBytes: request.limits.maxResultBytes,
1783
- maxHostCalls: request.limits.maxHostCalls,
1784
- maxHostCallArgumentBytes: request.limits.maxHostCallArgumentBytes
1785
- }
1786
- })
1787
- },
1822
+ env: { CODE_MODE_PASS: encodeHarnessPassConfig({
1823
+ namespaces: request.namespaces.map((namespace) => ({
1824
+ name: namespace.name,
1825
+ methods: namespace.methods
1826
+ })),
1827
+ limits: {
1828
+ maxLogBytes: request.limits.maxLogBytes,
1829
+ maxResultBytes: request.limits.maxResultBytes,
1830
+ maxHostCalls: request.limits.maxHostCalls,
1831
+ maxHostCallArgumentBytes: request.limits.maxHostCallArgumentBytes
1832
+ }
1833
+ }) },
1788
1834
  globalOutbound: null,
1789
1835
  ...request.limits.cpuMillis === void 0 ? {} : { limits: {
1790
1836
  cpuMs: request.limits.cpuMillis,
@@ -1794,7 +1840,7 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1794
1840
  const worker = yield* Effect.acquireRelease(Effect.try({
1795
1841
  try: () => options.loader.load(workerCode),
1796
1842
  catch: (cause) => {
1797
- const text = cause instanceof Error ? cause.message : String(cause);
1843
+ const text = safeCauseMessage(cause, "The Worker Loader failed without a diagnostic");
1798
1844
  if (/syntaxerror|failed to (compile|parse)/i.test(text)) return CodeSourceError.make({
1799
1845
  implementation: dynamicWorkerImplementation,
1800
1846
  reason: "invalid",
@@ -1806,13 +1852,13 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1806
1852
  cause
1807
1853
  });
1808
1854
  }
1809
- }), (stub) => Effect.sync(() => {
1810
- stub[Symbol.dispose]?.();
1811
- }));
1855
+ }), disposeRpcHandle);
1856
+ const entrypoint = yield* Effect.acquireRelease(Effect.try({
1857
+ try: () => worker.getEntrypoint(),
1858
+ catch: (cause) => classifyWorkerFailure(cause, request.limits.maxWallTime)
1859
+ }), disposeRpcHandle);
1812
1860
  const rpc = Effect.tryPromise({
1813
- try: async () => {
1814
- return await worker.getEntrypoint().run();
1815
- },
1861
+ try: () => entrypoint.run(new CodeModePassHostTarget(dispatch)),
1816
1862
  catch: (cause) => classifyWorkerFailure(cause, request.limits.maxWallTime)
1817
1863
  });
1818
1864
  const exit = yield* Effect.raceFirst(rpc.pipe(Effect.timeoutOrElse({
@@ -1829,7 +1875,7 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1829
1875
  if (passFailure !== void 0) return yield* passFailure;
1830
1876
  if (Exit.isFailure(exit)) return yield* Effect.failCause(exit.cause);
1831
1877
  const raw = exit.value;
1832
- const finishedAt = performance.now();
1878
+ const finishedAt = clock.monotonicTimeNanosUnsafe();
1833
1879
  const outcome = decodeHarnessOutcome(raw);
1834
1880
  if (Option.isNone(outcome)) return yield* CodeExecutionProtocolError.make({
1835
1881
  implementation: dynamicWorkerImplementation,
@@ -1841,7 +1887,7 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1841
1887
  value: outcome.value.value,
1842
1888
  logs: outcome.value.logs,
1843
1889
  resourceUse: CodeExecutionResourceUse.make({
1844
- wallTime: Duration.millis(Math.max(0, finishedAt - startedAt)),
1890
+ wallTime: Duration.nanos(finishedAt > startedAt ? finishedAt - startedAt : 0n),
1845
1891
  hostCalls: outcome.value.hostCalls,
1846
1892
  logBytes: outcome.value.logBytes,
1847
1893
  resultBytes: outcome.value.resultBytes
@@ -1902,13 +1948,7 @@ const makeExecute = (options) => Effect.fn("DynamicWorkerCodeExecutor.execute")(
1902
1948
  * than a fabricated program result.
1903
1949
  */
1904
1950
  const classifyWorkerFailure = (cause, maxWallTime) => {
1905
- const text = (() => {
1906
- try {
1907
- return cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause);
1908
- } catch {
1909
- return "[unserializable worker failure]";
1910
- }
1911
- })();
1951
+ const text = safeCauseDiagnostic(cause, "[unserializable worker failure]");
1912
1952
  if (/syntaxerror|failed to (compile|parse)/i.test(text)) return CodeSourceError.make({
1913
1953
  implementation: dynamicWorkerImplementation,
1914
1954
  reason: "invalid",
@@ -1931,8 +1971,11 @@ const classifyWorkerFailure = (cause, maxWallTime) => {
1931
1971
  });
1932
1972
  };
1933
1973
  /** Layer building the Dynamic Worker `CodeExecutor` from resolved bindings. */
1934
- const dynamicWorkerCodeExecutorLayer = (options) => Layer.succeed(CodeExecutor)(CodeExecutor.of({ execute: makeExecute(options) }));
1974
+ const dynamicWorkerCodeExecutorLayer = (options) => Layer.effect(CodeExecutor, Effect.gen(function* () {
1975
+ const clock = yield* Clock.Clock;
1976
+ return CodeExecutor.of({ execute: makeExecute(options, clock) });
1977
+ }));
1935
1978
  //#endregion
1936
- export { AbortRecorded, AdminExplainRequest, AdminFailed, AdminFailure, AdminResponse, AdminVerifyRequest, AdmissionLimitExceeded, ApprovalRecorded, AwaitProgressRequest, CLOUDFLARE_DATABASE_CAP_BYTES, CLOUDFLARE_RUNTIME_DEFAULTS, CancelProgressRequest, CloudflareAdmissionLimitsValue, CloudflareBindingError, CloudflareConversationClient, CloudflareDurableRuntime, CloudflareDurableRuntimeConfig, CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError, CodeModeHostEntrypoint, ConversationClientError, ConversationMaintenance, ConversationMaintenanceFailpoint, ConversationObjectIdentity, ConversationObjectNamespace, ConversationObjectPorts, DEFAULT_MAX_DATABASE_BYTES, DurableAlarmError, DurableAlarmService, DurableObjectContext, ExplainedRecovery, HostFailed, HostFailure, HostProtocolError, HostResponse, MaintenancePassReport, ObligationsScanned, ObservePageRequest, ObservedPage, ProgressCancelled, ProgressObserved, ProgressWaitRegistry, RetryExecuted, SettlementReached, SubmitRequest, SubmitSucceeded, UnknownResolutionRecorded, VerifiedIntegrity, boundHostDiagnostic, cloudflareWakeSchedulerLayer, conversationNamespaceFromEnv, conversationNamespaceLayer, conversationPortTransportLayer, decodeAbortCommand, decodeAdminExplainRequest, decodeAdminResponse, decodeAdminVerifyRequest, decodeApprovalDecisionCommand, decodeAwaitProgressRequest, decodeCancelProgressRequest, decodeHostResponse, decodeObligationThresholds, decodeObservePageRequest, decodeReceipt, decodeRetryCommand, decodeSubmitRequest, decodeUnknownResolutionCommand, dynamicWorkerCodeExecutorLayer, dynamicWorkerImplementation, encodeAbortCommand, encodeAdminResponse, encodeApprovalDecisionCommand, encodeAwaitProgressRequest, encodeCancelProgressRequest, encodeHostResponse, encodeObservePageRequest, encodeReceipt, encodeSubmitRequest, encodeUnknownResolutionCommand, makeConversationObjectClass };
1979
+ export { AbortRecorded, AdminExplainRequest, AdminFailed, AdminFailure, AdminResponse, AdminVerifyRequest, AdmissionLimitExceeded, ApprovalRecorded, AwaitProgressRequest, CLOUDFLARE_DATABASE_CAP_BYTES, CLOUDFLARE_RUNTIME_DEFAULTS, CancelProgressRequest, CloudflareAdmissionLimitsValue, CloudflareBindingError, CloudflareConversationClient, CloudflareDurableRuntime, CloudflareDurableRuntimeConfig, CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError, ConversationClientError, ConversationMaintenance, ConversationMaintenanceFailpoint, ConversationObjectIdentity, ConversationObjectNamespace, ConversationObjectPorts, DEFAULT_MAX_DATABASE_BYTES, DurableAlarmError, DurableAlarmService, DurableObjectContext, ExplainedRecovery, HostFailed, HostFailure, HostProtocolError, HostResponse, MaintenancePassReport, ObligationsScanned, ObservePageRequest, ObservedPage, ProgressCancelled, ProgressObserved, ProgressWaitRegistry, RetryExecuted, SettlementReached, SubmitRequest, SubmitSucceeded, UnknownResolutionRecorded, VerifiedIntegrity, boundHostDiagnostic, cloudflareWakeSchedulerLayer, conversationNamespaceFromEnv, conversationNamespaceLayer, conversationPortTransportLayer, decodeAbortCommand, decodeAdminExplainRequest, decodeAdminResponse, decodeAdminVerifyRequest, decodeApprovalDecisionCommand, decodeAwaitProgressRequest, decodeCancelProgressRequest, decodeHostResponse, decodeObligationThresholds, decodeObservePageRequest, decodeReceipt, decodeRetryCommand, decodeSubmitRequest, decodeUnknownResolutionCommand, disposeRpcHandle, dynamicWorkerCodeExecutorLayer, dynamicWorkerImplementation, encodeAbortCommand, encodeAdminResponse, encodeApprovalDecisionCommand, encodeAwaitProgressRequest, encodeCancelProgressRequest, encodeHostResponse, encodeObservePageRequest, encodeReceipt, encodeSubmitRequest, encodeUnknownResolutionCommand, makeConversationObjectClass };
1937
1980
 
1938
1981
  //# sourceMappingURL=index.mjs.map