@effect-agent/platform-cloudflare 0.1.0-beta.37 → 0.1.0-beta.39
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/bindings-C00ZfjsX.d.mts +100 -0
- package/dist/index.d.mts +191 -206
- package/dist/index.mjs +157 -163
- package/dist/index.mjs.map +1 -1
- package/dist/interactive-browser.d.mts +23 -3
- package/dist/interactive-browser.mjs +110 -35
- package/dist/interactive-browser.mjs.map +1 -1
- package/dist/{scheduling-B-OFqoS9.mjs → prepared-admission-D5hQ-ofV.mjs} +121 -432
- package/dist/prepared-admission-D5hQ-ofV.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/scheduling.d.mts +47 -2
- package/dist/scheduling.mjs +339 -1
- package/dist/scheduling.mjs.map +1 -0
- package/dist/subscriptions.d.mts +52 -0
- package/dist/subscriptions.mjs +346 -0
- package/dist/subscriptions.mjs.map +1 -0
- package/package.json +18 -11
- package/src/alarm.ts +264 -265
- package/src/bindings.ts +30 -30
- package/src/browser-session-lifecycle.ts +142 -0
- package/src/client.ts +90 -98
- package/src/config.ts +7 -7
- package/src/index.ts +9 -11
- package/src/interactive-browser.ts +81 -70
- package/src/layers.ts +178 -257
- package/src/prepared-admission.ts +90 -0
- package/src/scheduling.ts +19 -55
- package/src/subscriptions.ts +661 -0
- package/src/{conversation-object.ts → thread-object.ts} +167 -136
- package/src/transport.ts +15 -15
- package/src/wake-scheduler.ts +17 -22
- package/dist/scheduling-B-OFqoS9.mjs.map +0 -1
- package/dist/scheduling-BJs_kHTx.d.mts +0 -142
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { browserRestCrawlImplementation, browserRestCrawlLayer } from "./browser-rest-crawl.mjs";
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { $ as CloudflarePlatformConfigError, A as decodeUnknownResolutionCommand, B as DurableAlarmError, C as decodeApprovalDecisionCommand, D as decodeObservePageRequest, E as decodeHostResponse, F as encodeHostResponse, G as safeCauseDiagnostic, H as MaintenancePassReport, I as encodeObservePageRequest, J as CLOUDFLARE_DATABASE_CAP_BYTES, K as safeCauseMessage, L as encodeReceipt, M as encodeApprovalDecisionCommand, N as encodeAwaitProgressRequest, O as decodeReceipt, P as encodeCancelProgressRequest, Q as CloudflareDurableRuntimeConfigValue, R as encodeSubmitRequest, S as decodeAbortCommand, T as decodeCancelProgressRequest, U as ThreadMaintenance, V as DurableAlarmService, W as ThreadMaintenanceFailpoint, X as CloudflareAdmissionLimitsValue, Y as CLOUDFLARE_RUNTIME_DEFAULTS, Z as CloudflareDurableRuntimeConfig, _ as SubmitRequest, a as AwaitProgressRequest, at as threadNamespaceFromEnv, b as UnknownResolutionRecorded, c as HostFailed, d as HostResponse, et as DEFAULT_MAX_DATABASE_BYTES, f as ObservePageRequest, g as SettlementReached, h as ProgressObserved, i as ApprovalRecorded, it as ThreadObjectNamespace, j as encodeAbortCommand, k as decodeSubmitRequest, l as HostFailure, m as ProgressCancelled, n as cloudflareScheduledInputAdmissionLayer, nt as DurableObjectContext, o as CancelProgressRequest, ot as threadNamespaceLayer, p as ObservedPage, q as AdmissionLimitExceeded, r as AbortRecorded, rt as ThreadObjectIdentity, s as CloudflareThreadClient, t as cloudflarePreparedInputAdmissionLayer, tt as CloudflareBindingError, u as HostProtocolError, v as SubmitSucceeded, w as decodeAwaitProgressRequest, x as boundHostDiagnostic, y as ThreadClientError, z as encodeUnknownResolutionCommand } from "./prepared-admission-D5hQ-ofV.mjs";
|
|
3
|
+
import { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass } from "./scheduling.mjs";
|
|
4
|
+
import { CloudflareSubscriptionConfigError, CloudflareSubscriptionsClient, SubscriptionAlarmProtocolError, SubscriptionPartitionIdentity, SubscriptionPartitionNamespace, SubscriptionPartitionProtocolError, makeSubscriptionPartitionObjectClass, sourcePartitionName, validateCloudflareSubscriptionLimits } from "./subscriptions.mjs";
|
|
6
5
|
import { Clock, Context, Deferred, Duration, Effect, Exit, Fiber, Layer, Option, PubSub, Queue, Ref, Schema, Stream } from "effect";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { CurrentToolFailureObserver, RunContextPreparationPassthrough, toolFailureObserverLayer } from "@effect-agent/engine";
|
|
6
|
+
import { ThreadPortTransport, decodePortRequest, encodePortResponse, executePortRequest, portTransportFailure, routedSubmissionLedgerLayer, routedThreadStoreLayer, storageConfigLayer, storageFailpointLayer, submissionLedgerLayer, threadStoreLayer } from "@effect-agent/storage-cloudflare";
|
|
7
|
+
import { AppendConflict, DigestError, DurableAgentRuntime, DurableRuntimeConfig, DurableRuntimeFailpoint, DurableRuntimeFailpointError, FenceRejected, IntegrityReport, LedgerError, ObligationReport, ObligationThresholds, OperationAuthorizationRequest, OperationAuthorizer, OperationDenied, OwnershipLost, PersistedJson, ProducerId, RecoveryExplanation, RecoveryReport, RetryCommand, RetryRefused, RunJournalError, SettlementConflict, SubmissionLedger, SubmissionLookupByKey, ThreadNotMaterialized, ThreadRead, ThreadStore, ThreadStoreError, ToolReconciler, WakeScheduler, compileRegistrations, makeWakeSubscriptionHub, operationAuthorizerLayer } from "@effect-agent/thread";
|
|
8
|
+
import { SubmissionId, ThreadId } from "@effect-agent/core";
|
|
9
|
+
import { CurrentToolFailureObserver, RunContextPreparationPassthrough, RunToolAuthorization, toolFailureObserverLayer } from "@effect-agent/engine";
|
|
11
10
|
import { BrowserCrypto } from "@effect/platform-browser";
|
|
12
11
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
13
12
|
import { DurableObject, DurableObjectState, WorkerEnvironment } from "effect-cf";
|
|
@@ -23,7 +22,7 @@ import { RpcTarget } from "cloudflare:workers";
|
|
|
23
22
|
const WAKE_BUFFER_CAPACITY = 1024;
|
|
24
23
|
/** A remote wake stub call failed; always swallowed and logged (hints are droppable). */
|
|
25
24
|
var RemoteWakeDropped = class extends Schema.TaggedError()("RemoteWakeDropped", {
|
|
26
|
-
|
|
25
|
+
threadId: Schema.String,
|
|
27
26
|
message: Schema.String,
|
|
28
27
|
cause: Schema.optionalKey(Schema.Defect())
|
|
29
28
|
}) {};
|
|
@@ -41,22 +40,22 @@ var RemoteWakeDropped = class extends Schema.TaggedError()("RemoteWakeDropped",
|
|
|
41
40
|
*/
|
|
42
41
|
const cloudflareWakeSchedulerLayer = Layer.effect(WakeScheduler)(Effect.gen(function* () {
|
|
43
42
|
const alarm = yield* DurableAlarmService;
|
|
44
|
-
const identity = yield*
|
|
45
|
-
const { namespace } = yield*
|
|
43
|
+
const identity = yield* ThreadObjectIdentity;
|
|
44
|
+
const { namespace } = yield* ThreadObjectNamespace;
|
|
46
45
|
const hints = yield* PubSub.sliding(WAKE_BUFFER_CAPACITY);
|
|
47
46
|
const progress = yield* makeWakeSubscriptionHub;
|
|
48
47
|
yield* Effect.addFinalizer(() => PubSub.shutdown(hints));
|
|
49
|
-
const notifyLocal = (
|
|
50
|
-
const notifyRemote = (
|
|
51
|
-
try: () => namespace.get(namespace.idFromName(
|
|
48
|
+
const notifyLocal = (threadId) => progress.notify(threadId).pipe(Effect.andThen(PubSub.publish(hints, threadId)), Effect.andThen(alarm.scheduleNow), Effect.catch((error) => Effect.logWarning("CloudflareWakeScheduler: local alarm wake failed", error)), Effect.asVoid);
|
|
49
|
+
const notifyRemote = (threadId) => Effect.tryPromise({
|
|
50
|
+
try: () => namespace.get(namespace.idFromName(threadId)).wake(),
|
|
52
51
|
catch: (cause) => RemoteWakeDropped.make({
|
|
53
|
-
|
|
52
|
+
threadId,
|
|
54
53
|
message: safeCauseMessage(cause, "The remote wake failed without a diagnostic"),
|
|
55
54
|
cause
|
|
56
55
|
})
|
|
57
|
-
}).pipe(Effect.catch((error) => Effect.logWarning(`CloudflareWakeScheduler: remote wake of ${
|
|
56
|
+
}).pipe(Effect.catch((error) => Effect.logWarning(`CloudflareWakeScheduler: remote wake of ${threadId} dropped`, error)), Effect.asVoid);
|
|
58
57
|
return WakeScheduler.of({
|
|
59
|
-
notify: (
|
|
58
|
+
notify: (threadId) => threadId === identity.threadId ? notifyLocal(threadId) : notifyRemote(threadId),
|
|
60
59
|
subscribe: progress.subscribe,
|
|
61
60
|
wakes: Stream.fromPubSub(hints)
|
|
62
61
|
});
|
|
@@ -129,9 +128,9 @@ var ProgressWaitRegistry = class ProgressWaitRegistry extends Context.Service()(
|
|
|
129
128
|
//#endregion
|
|
130
129
|
//#region src/transport.ts
|
|
131
130
|
/**
|
|
132
|
-
* `
|
|
133
|
-
* `portCall(envelope)` on the stub of the Object that owns the addressed
|
|
134
|
-
* (`namespace.idFromName(
|
|
131
|
+
* `ThreadPortTransport` over native Durable Object JS RPC (decision D-P6-3): one
|
|
132
|
+
* `portCall(envelope)` on the stub of the Object that owns the addressed Thread
|
|
133
|
+
* (`namespace.idFromName(threadId)` — the identity rule, plan §1.2). The envelopes are
|
|
135
134
|
* already Schema-encoded JSON, so the RPC boundary carries only structured-cloneable values;
|
|
136
135
|
* the protocol module stays transport-agnostic and fetch-with-JSON remains the documented
|
|
137
136
|
* fallback carrier.
|
|
@@ -141,12 +140,12 @@ var ProgressWaitRegistry = class ProgressWaitRegistry extends Context.Service()(
|
|
|
141
140
|
* when present) and NEVER as a fabricated answer: on `resolveAdmission` the routing layer
|
|
142
141
|
* turns exactly this error into `AdmissionIndeterminate` (SUB-031).
|
|
143
142
|
*/
|
|
144
|
-
const
|
|
145
|
-
const { namespace } = yield*
|
|
146
|
-
return
|
|
147
|
-
try: () => namespace.get(namespace.idFromName(
|
|
148
|
-
catch: (cause) => portTransportFailure(
|
|
149
|
-
}).pipe(Effect.withSpan("CloudflarePortTransport.call", { attributes: {
|
|
143
|
+
const threadPortTransportLayer = Layer.effect(ThreadPortTransport)(Effect.gen(function* () {
|
|
144
|
+
const { namespace } = yield* ThreadObjectNamespace;
|
|
145
|
+
return ThreadPortTransport.of({ call: (threadId, request) => Effect.tryPromise({
|
|
146
|
+
try: () => namespace.get(namespace.idFromName(threadId)).portCall(request),
|
|
147
|
+
catch: (cause) => portTransportFailure(threadId, cause)
|
|
148
|
+
}).pipe(Effect.withSpan("CloudflarePortTransport.call", { attributes: { threadId } })) });
|
|
150
149
|
}));
|
|
151
150
|
//#endregion
|
|
152
151
|
//#region src/layers.ts
|
|
@@ -156,9 +155,9 @@ const conversationPortTransportLayer = Layer.effect(ConversationPortTransport)(E
|
|
|
156
155
|
* request cannot bounce between Objects — and returns the typed response for the endpoint to
|
|
157
156
|
* encode.
|
|
158
157
|
*/
|
|
159
|
-
var
|
|
158
|
+
var ThreadObjectPorts = class extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectPorts") {};
|
|
160
159
|
const decodeConfigValue = Schema.decodeUnknownEffect(CloudflareDurableRuntimeConfigValue);
|
|
161
|
-
const
|
|
160
|
+
const decodeThreadId = Schema.decodeUnknownEffect(ThreadId);
|
|
162
161
|
const decodeProducerId = Schema.decodeUnknownEffect(ProducerId);
|
|
163
162
|
const configFromOptions = (options) => decodeConfigValue({
|
|
164
163
|
deploymentId: options.deploymentId,
|
|
@@ -183,101 +182,94 @@ const configFromOptions = (options) => decodeConfigValue({
|
|
|
183
182
|
cause: error
|
|
184
183
|
})));
|
|
185
184
|
/**
|
|
186
|
-
* The
|
|
187
|
-
* Objects are addressed exclusively by `idFromName(
|
|
188
|
-
*
|
|
185
|
+
* The Thread this Object owns, from the Object identity rule (plan §1.2): Thread
|
|
186
|
+
* Objects are addressed exclusively by `idFromName(threadId)`, so `ctx.id.name` IS the
|
|
187
|
+
* Thread ID. An unnamed Object (from `newUniqueId`) is a deployment error, not a lane.
|
|
189
188
|
*/
|
|
190
|
-
const
|
|
191
|
-
message: `The Durable Object name is not a valid
|
|
189
|
+
const threadIdFromState = (ctx) => ctx.id.name === void 0 ? Effect.fail(CloudflarePlatformConfigError.make({ message: "This Durable Object was not created via idFromName(threadId); Thread Objects must be addressed by their Thread identity (plan §1.2)." })) : decodeThreadId(ctx.id.name).pipe(Effect.mapError((error) => CloudflarePlatformConfigError.make({
|
|
190
|
+
message: `The Durable Object name is not a valid ThreadId: ${error.message}`,
|
|
192
191
|
cause: error
|
|
193
192
|
})));
|
|
194
|
-
const resolveBindings = (source, context) => source === void 0 ? Effect.succeed([]) : Effect.suspend(() => source(context));
|
|
195
|
-
const resolveRunContext = (source, context) => typeof source === "function" ? source(context) : source;
|
|
196
193
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* `@effect/sql-sqlite-do` for BOTH the Conversation Log and the Submission Ledger (so claims
|
|
201
|
-
* fence the same producer epochs — ADR-0011 D7 transposed), wraps the local port facets with
|
|
202
|
-
* the WP2 cross-Object routing decorators over the Durable Object RPC transport, wires the
|
|
203
|
-
* alarm-backed wake scheduler and the maintenance pass, defaults reconciliation to the
|
|
204
|
-
* fail-closed `ToolReconciler.uncertain`, and provides a ready `DurableAgentRuntime` on top.
|
|
205
|
-
*
|
|
206
|
-
* Storage compatibility is verified during construction: an incompatible database fails the
|
|
207
|
-
* Layer typed (`DoStorageCompatibilityError`) before anything is mutated (DEPLOY-008).
|
|
208
|
-
*
|
|
209
|
-
* Requires only the two binding services (`DurableObjectContext`,
|
|
210
|
-
* `ConversationObjectNamespace`) — platform values enter exclusively through Layers
|
|
211
|
-
* (DEPLOY-010).
|
|
194
|
+
* Validate deployment settings and derive services before building application dependencies.
|
|
195
|
+
* The native class factory builds this Layer inside its constructor gate. Custom Effect hosts
|
|
196
|
+
* can provide it around the complete application Layer with the native context already supplied.
|
|
212
197
|
*/
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}), (bindings) => AgentBindingResolver.fromBindings(bindings)));
|
|
267
|
-
const runContextLayer = options.runContext === void 0 ? RunContextPreparationPassthrough : resolveRunContext(options.runContext, {
|
|
268
|
-
ctx,
|
|
269
|
-
env,
|
|
270
|
-
conversationId,
|
|
271
|
-
producerId
|
|
272
|
-
}).pipe(Layer.provide(BrowserCrypto.layer));
|
|
273
|
-
const base = Layer.mergeAll(identityLayer, cloudflareConfigLayer, DurableAlarmService.layer, maintenanceFailpointLayer, ProgressWaitRegistry.layer);
|
|
274
|
-
const runtimeStack = DurableAgentRuntime.layerWithContext.pipe(Layer.provideMerge(routedPorts), Layer.provideMerge(cloudflareWakeSchedulerLayer), Layer.provideMerge(runtimeConfigLayer), Layer.provideMerge(bindingResolverLayer), Layer.provide(Layer.mergeAll(runtimeFailpointLayer, reconcilerLayer, authorizerLayer, observerLayer, runContextLayer, BrowserCrypto.layer)), Layer.provideMerge(base));
|
|
275
|
-
return Layer.mergeAll(runtimeStack, ConversationMaintenance.layer.pipe(Layer.provide(runtimeStack)), portsEndpointLayer);
|
|
276
|
-
}));
|
|
277
|
-
}
|
|
278
|
-
};
|
|
198
|
+
const layerConfig = (options) => Layer.unwrap(Effect.gen(function* () {
|
|
199
|
+
const { ctx } = yield* DurableObjectContext;
|
|
200
|
+
const config = yield* configFromOptions(options);
|
|
201
|
+
const threadId = yield* threadIdFromState(ctx);
|
|
202
|
+
const producerId = yield* decodeProducerId(`${config.producerPrefix}:${threadId}`).pipe(Effect.mapError((error) => CloudflarePlatformConfigError.make({
|
|
203
|
+
message: `The minted producer identity is invalid: ${error.message}`,
|
|
204
|
+
cause: error
|
|
205
|
+
})));
|
|
206
|
+
return Layer.mergeAll(Layer.succeed(CloudflareDurableRuntimeConfig, config), Layer.succeed(ThreadObjectIdentity, {
|
|
207
|
+
threadId,
|
|
208
|
+
producerId
|
|
209
|
+
}), DurableRuntimeConfig.layer({
|
|
210
|
+
deploymentId: config.deploymentId,
|
|
211
|
+
producerId,
|
|
212
|
+
settlementPollInterval: Duration.millis(config.settlementPollInterval),
|
|
213
|
+
leaseRenewalInterval: Duration.millis(config.leaseRenewalInterval),
|
|
214
|
+
abortPollInterval: Duration.millis(config.abortPollInterval),
|
|
215
|
+
...options.estimateCostMicrousd === void 0 ? {} : { estimateCostMicrousd: options.estimateCostMicrousd }
|
|
216
|
+
}), BrowserCrypto.layer, storageFailpointLayer({
|
|
217
|
+
storage: ctx.storage,
|
|
218
|
+
failpoint: options.storageFailpoint?.(ctx)
|
|
219
|
+
}), options.runtimeFailpoint === void 0 ? DurableRuntimeFailpoint.layer : Layer.succeed(DurableRuntimeFailpoint, { hit: options.runtimeFailpoint(ctx) }), options.maintenanceFailpoint === void 0 ? ThreadMaintenanceFailpoint.layer : Layer.succeed(ThreadMaintenanceFailpoint, { hit: options.maintenanceFailpoint(ctx) }), options.toolReconciler ?? ToolReconciler.uncertain, options.operationAuthorizer === void 0 ? Layer.empty : operationAuthorizerLayer(options.operationAuthorizer), options.toolFailureObserver === void 0 ? Layer.succeed(CurrentToolFailureObserver, void 0) : toolFailureObserverLayer(options.toolFailureObserver), RunContextPreparationPassthrough, RunToolAuthorization.allowAll);
|
|
220
|
+
}));
|
|
221
|
+
/**
|
|
222
|
+
* Register typed Agents and version declarations. Hashing and dependency capture happen in
|
|
223
|
+
* this Layer's Scope, after application Layers have been provided. Every Agent's instruction,
|
|
224
|
+
* Tool, Schema, and model requirements remain visible until satisfied by Layer composition.
|
|
225
|
+
* Use Layer.unwrap for registration values that need effectful application setup.
|
|
226
|
+
*/
|
|
227
|
+
const layer = (registrations) => Layer.unwrap(Effect.map(compileRegistrations(registrations), layerFromBindings));
|
|
228
|
+
/** Internal assembly shared by registration compilation and low-level adapter fixtures. */
|
|
229
|
+
const layerFromBindings = (bindings) => Layer.unwrap(Effect.gen(function* () {
|
|
230
|
+
const { ctx } = yield* DurableObjectContext;
|
|
231
|
+
const config = yield* CloudflareDurableRuntimeConfig;
|
|
232
|
+
const { threadId } = yield* ThreadObjectIdentity;
|
|
233
|
+
const storageOptions = {
|
|
234
|
+
storage: ctx.storage,
|
|
235
|
+
observationPollInterval: config.observationPollInterval,
|
|
236
|
+
ownershipLeaseDuration: config.ownershipLeaseDuration,
|
|
237
|
+
maxStoredValueBytes: config.maxStoredValueBytes,
|
|
238
|
+
verifyOnOpen: config.verifyOnOpen
|
|
239
|
+
};
|
|
240
|
+
const infrastructure = Layer.mergeAll(storageConfigLayer(storageOptions), SqliteClient.layer({ storage: ctx.storage }));
|
|
241
|
+
const localPorts = Layer.mergeAll(threadStoreLayer, submissionLedgerLayer).pipe(Layer.provide(infrastructure));
|
|
242
|
+
const portsEndpointLayer = Layer.effect(ThreadObjectPorts)(Effect.gen(function* () {
|
|
243
|
+
const local = yield* Effect.context();
|
|
244
|
+
return ThreadObjectPorts.of({ handle: (request) => executePortRequest(request).pipe(Effect.provide(local)) });
|
|
245
|
+
})).pipe(Layer.provide(localPorts));
|
|
246
|
+
const routedPorts = Layer.mergeAll(routedSubmissionLedgerLayer({ localThreadId: threadId }), routedThreadStoreLayer({ localThreadId: threadId })).pipe(Layer.provide(localPorts), Layer.provide(threadPortTransportLayer));
|
|
247
|
+
const base = Layer.mergeAll(DurableAlarmService.layer, ProgressWaitRegistry.layer);
|
|
248
|
+
const runtimeStack = DurableAgentRuntime.layerWithServices.pipe(Layer.provideMerge(routedPorts), Layer.provideMerge(cloudflareWakeSchedulerLayer), Layer.provideMerge(base));
|
|
249
|
+
return Layer.mergeAll(runtimeStack, ThreadMaintenance.layer(bindings).pipe(Layer.provide(runtimeStack)), portsEndpointLayer);
|
|
250
|
+
}));
|
|
279
251
|
//#endregion
|
|
280
|
-
//#region src/
|
|
252
|
+
//#region src/thread-object.ts
|
|
253
|
+
var thread_object_exports = /* @__PURE__ */ __exportAll({
|
|
254
|
+
AdminExplainRequest: () => AdminExplainRequest,
|
|
255
|
+
AdminFailed: () => AdminFailed,
|
|
256
|
+
AdminFailure: () => AdminFailure,
|
|
257
|
+
AdminResponse: () => AdminResponse,
|
|
258
|
+
AdminVerifyRequest: () => AdminVerifyRequest,
|
|
259
|
+
ExplainedRecovery: () => ExplainedRecovery,
|
|
260
|
+
ObligationsScanned: () => ObligationsScanned,
|
|
261
|
+
RetryExecuted: () => RetryExecuted,
|
|
262
|
+
VerifiedIntegrity: () => VerifiedIntegrity,
|
|
263
|
+
decodeAdminExplainRequest: () => decodeAdminExplainRequest,
|
|
264
|
+
decodeAdminResponse: () => decodeAdminResponse,
|
|
265
|
+
decodeAdminVerifyRequest: () => decodeAdminVerifyRequest,
|
|
266
|
+
decodeObligationThresholds: () => decodeObligationThresholds,
|
|
267
|
+
decodeRetryCommand: () => decodeRetryCommand,
|
|
268
|
+
encodeAdminResponse: () => encodeAdminResponse,
|
|
269
|
+
layer: () => layer,
|
|
270
|
+
layerConfig: () => layerConfig,
|
|
271
|
+
make: () => make
|
|
272
|
+
});
|
|
281
273
|
/** Classify only a decoded port request so new protocol members cannot bypass pre-arming. */
|
|
282
274
|
const isMutatingPortRequest = (request) => {
|
|
283
275
|
switch (request._tag) {
|
|
@@ -321,13 +313,13 @@ const utf8Bytes = (value) => new TextEncoder().encode(JSON.stringify(value)).len
|
|
|
321
313
|
* exempt: its accepted-work obligation already exists, and returning the original Receipt
|
|
322
314
|
* consumes no new quota. Refusals are typed `AdmissionLimitExceeded` and nothing is written.
|
|
323
315
|
*/
|
|
324
|
-
const gateAdmissionLimits = Effect.fn("
|
|
325
|
-
const identity = yield*
|
|
316
|
+
const gateAdmissionLimits = Effect.fn("ThreadObject.gateAdmissionLimits")(function* (request) {
|
|
317
|
+
const identity = yield* ThreadObjectIdentity;
|
|
326
318
|
const config = yield* CloudflareDurableRuntimeConfig;
|
|
327
319
|
const ledger = yield* SubmissionLedger;
|
|
328
320
|
const { ctx } = yield* DurableObjectContext;
|
|
329
321
|
const existing = yield* ledger.lookup(SubmissionLookupByKey.make({
|
|
330
|
-
|
|
322
|
+
threadId: identity.threadId,
|
|
331
323
|
principal: request.principal,
|
|
332
324
|
idempotencyKey: request.idempotencyKey
|
|
333
325
|
}));
|
|
@@ -362,12 +354,12 @@ const passthroughSubmitAgent = (agentId) => ({ definition: {
|
|
|
362
354
|
input: PersistedJson
|
|
363
355
|
} });
|
|
364
356
|
const submitEndpoint = (encoded) => decodeSubmitRequest(encoded).pipe(Effect.mapError(protocolFailure("The submit request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
365
|
-
const identity = yield*
|
|
366
|
-
const maintenance = yield*
|
|
357
|
+
const identity = yield* ThreadObjectIdentity;
|
|
358
|
+
const maintenance = yield* ThreadMaintenance;
|
|
367
359
|
const runtime = yield* DurableAgentRuntime;
|
|
368
360
|
yield* gateAdmissionLimits(request);
|
|
369
361
|
const receipt = yield* maintenance.withMutation(runtime.submit(passthroughSubmitAgent(request.agentId), request.inputPayload, {
|
|
370
|
-
|
|
362
|
+
threadId: identity.threadId,
|
|
371
363
|
principal: request.principal,
|
|
372
364
|
idempotencyKey: request.idempotencyKey,
|
|
373
365
|
definitions: request.definitions
|
|
@@ -379,12 +371,12 @@ const awaitSettlementEndpoint = (encoded) => decodeReceipt(encoded).pipe(Effect.
|
|
|
379
371
|
return SettlementReached.make({ settlement });
|
|
380
372
|
})), respond, Effect.flatMap(encodeResponse));
|
|
381
373
|
const awaitProgressEndpoint = (encoded) => decodeAwaitProgressRequest(encoded).pipe(Effect.mapError(protocolFailure("The progress request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
382
|
-
const identity = yield*
|
|
374
|
+
const identity = yield* ThreadObjectIdentity;
|
|
383
375
|
const runtime = yield* DurableAgentRuntime;
|
|
384
376
|
const registry = yield* ProgressWaitRegistry;
|
|
385
377
|
yield* Effect.scoped(Effect.gen(function* () {
|
|
386
378
|
const cancelled = yield* registry.subscribe(request.waiterId);
|
|
387
|
-
yield* Effect.raceFirst(runtime.awaitProgress(identity.
|
|
379
|
+
yield* Effect.raceFirst(runtime.awaitProgress(identity.threadId, request.afterSequence), cancelled);
|
|
388
380
|
}));
|
|
389
381
|
return ProgressObserved.make();
|
|
390
382
|
})), respond, Effect.flatMap(encodeResponse));
|
|
@@ -393,33 +385,33 @@ const cancelProgressEndpoint = (encoded) => decodeCancelProgressRequest(encoded)
|
|
|
393
385
|
return ProgressCancelled.make();
|
|
394
386
|
})), respond, Effect.flatMap(encodeResponse));
|
|
395
387
|
const observePageEndpoint = (encoded) => decodeObservePageRequest(encoded).pipe(Effect.mapError(protocolFailure("The observe request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
396
|
-
const identity = yield*
|
|
397
|
-
const store = yield*
|
|
388
|
+
const identity = yield* ThreadObjectIdentity;
|
|
389
|
+
const store = yield* ThreadStore;
|
|
398
390
|
yield* (yield* OperationAuthorizer).authorize(OperationAuthorizationRequest.make({
|
|
399
391
|
operation: "observe",
|
|
400
|
-
|
|
392
|
+
threadId: identity.threadId
|
|
401
393
|
}));
|
|
402
|
-
const records = yield* Stream.runCollect(store.read(
|
|
403
|
-
|
|
394
|
+
const records = yield* Stream.runCollect(store.read(ThreadRead.make({
|
|
395
|
+
threadId: identity.threadId,
|
|
404
396
|
...request.afterSequence === void 0 ? {} : { afterSequence: request.afterSequence },
|
|
405
397
|
limit: request.limit
|
|
406
398
|
})));
|
|
407
399
|
return ObservedPage.make({ records: [...records] });
|
|
408
400
|
})), respond, Effect.flatMap(encodeResponse));
|
|
409
401
|
const abortEndpoint = (encoded) => decodeAbortCommand(encoded).pipe(Effect.mapError(protocolFailure("The abort command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
410
|
-
const maintenance = yield*
|
|
402
|
+
const maintenance = yield* ThreadMaintenance;
|
|
411
403
|
const runtime = yield* DurableAgentRuntime;
|
|
412
404
|
const intent = yield* maintenance.withMutation(runtime.abort(command));
|
|
413
405
|
return AbortRecorded.make({ intent });
|
|
414
406
|
})), respond, Effect.flatMap(encodeResponse));
|
|
415
407
|
const resolveApprovalEndpoint = (encoded) => decodeApprovalDecisionCommand(encoded).pipe(Effect.mapError(protocolFailure("The approval command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
416
|
-
const maintenance = yield*
|
|
408
|
+
const maintenance = yield* ThreadMaintenance;
|
|
417
409
|
const runtime = yield* DurableAgentRuntime;
|
|
418
410
|
const intent = yield* maintenance.withMutation(runtime.resolveApproval(command));
|
|
419
411
|
return ApprovalRecorded.make({ intent });
|
|
420
412
|
})), respond, Effect.flatMap(encodeResponse));
|
|
421
413
|
const resolveUnknownEndpoint = (encoded) => decodeUnknownResolutionCommand(encoded).pipe(Effect.mapError(protocolFailure("The resolution command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
422
|
-
const maintenance = yield*
|
|
414
|
+
const maintenance = yield* ThreadMaintenance;
|
|
423
415
|
const runtime = yield* DurableAgentRuntime;
|
|
424
416
|
const intent = yield* maintenance.withMutation(runtime.resolveUnknown(command));
|
|
425
417
|
return UnknownResolutionRecorded.make({ intent });
|
|
@@ -437,8 +429,8 @@ const AdminFailure = Schema.Union([
|
|
|
437
429
|
DigestError,
|
|
438
430
|
OwnershipLost,
|
|
439
431
|
SettlementConflict,
|
|
440
|
-
|
|
441
|
-
|
|
432
|
+
ThreadStoreError,
|
|
433
|
+
ThreadNotMaterialized,
|
|
442
434
|
AppendConflict,
|
|
443
435
|
FenceRejected,
|
|
444
436
|
DurableRuntimeFailpointError,
|
|
@@ -476,18 +468,18 @@ const encodeAdminResponseTotal = (response) => encodeAdminResponse(response).pip
|
|
|
476
468
|
}
|
|
477
469
|
})));
|
|
478
470
|
const explainEndpoint = (encoded) => decodeAdminExplainRequest(encoded).pipe(Effect.mapError(protocolFailure("The explain request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
479
|
-
const identity = yield*
|
|
471
|
+
const identity = yield* ThreadObjectIdentity;
|
|
480
472
|
const runtime = yield* DurableAgentRuntime;
|
|
481
|
-
const explanations = request.submissionId === void 0 ? yield* runtime.
|
|
473
|
+
const explanations = request.submissionId === void 0 ? yield* runtime.explainThread(identity.threadId) : [yield* runtime.explain(request.submissionId)];
|
|
482
474
|
return ExplainedRecovery.make({ explanations });
|
|
483
475
|
})), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
|
|
484
476
|
const verifyEndpoint = (encoded) => decodeAdminVerifyRequest(encoded).pipe(Effect.mapError(protocolFailure("The verify request could not be decoded")), Effect.flatMap(() => Effect.gen(function* () {
|
|
485
|
-
const identity = yield*
|
|
486
|
-
const report = yield* (yield* DurableAgentRuntime).verify(identity.
|
|
477
|
+
const identity = yield* ThreadObjectIdentity;
|
|
478
|
+
const report = yield* (yield* DurableAgentRuntime).verify(identity.threadId);
|
|
487
479
|
return VerifiedIntegrity.make({ report });
|
|
488
480
|
})), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
|
|
489
481
|
const retryEndpoint = (encoded) => decodeRetryCommand(encoded).pipe(Effect.mapError(protocolFailure("The retry command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
490
|
-
const maintenance = yield*
|
|
482
|
+
const maintenance = yield* ThreadMaintenance;
|
|
491
483
|
const runtime = yield* DurableAgentRuntime;
|
|
492
484
|
const report = yield* maintenance.withMutation(runtime.retry(command));
|
|
493
485
|
return RetryExecuted.make({ report });
|
|
@@ -504,8 +496,8 @@ const obligationsEndpoint = (encoded) => decodeObligationThresholds(encoded).pip
|
|
|
504
496
|
* `PortFailed(PortProtocolError)`.
|
|
505
497
|
*/
|
|
506
498
|
const portCallEndpoint = (encoded) => Effect.gen(function* () {
|
|
507
|
-
const ports = yield*
|
|
508
|
-
const maintenance = yield*
|
|
499
|
+
const ports = yield* ThreadObjectPorts;
|
|
500
|
+
const maintenance = yield* ThreadMaintenance;
|
|
509
501
|
const alarm = yield* DurableAlarmService;
|
|
510
502
|
const decoded = yield* decodePortRequest(encoded).pipe(Effect.map((request) => ({
|
|
511
503
|
_tag: "success",
|
|
@@ -519,18 +511,18 @@ const portCallEndpoint = (encoded) => Effect.gen(function* () {
|
|
|
519
511
|
const handled = yield* (mutating ? maintenance.withMutation(ports.handle(decoded.request)) : ports.handle(decoded.request)).pipe(Effect.exit);
|
|
520
512
|
if (handled._tag === "Failure") return encodedPortProtocolFailure("The owner Object could not arm its maintenance alarm before the mutation.");
|
|
521
513
|
const response = yield* encodePortResponse(handled.value).pipe(Effect.catch((error) => Effect.succeed(encodedPortProtocolFailure(`The port response could not be encoded: ${error.message}`))));
|
|
522
|
-
if (mutating) yield* alarm.scheduleNow.pipe(Effect.catch((error) => Effect.logWarning("
|
|
514
|
+
if (mutating) yield* alarm.scheduleNow.pipe(Effect.catch((error) => Effect.logWarning("ThreadObject.portCall: immediate re-arm failed", error)));
|
|
523
515
|
return response;
|
|
524
516
|
});
|
|
525
517
|
const wakeEndpoint = Effect.gen(function* () {
|
|
526
|
-
const identity = yield*
|
|
527
|
-
yield* (yield* WakeScheduler).notify(identity.
|
|
518
|
+
const identity = yield* ThreadObjectIdentity;
|
|
519
|
+
yield* (yield* WakeScheduler).notify(identity.threadId);
|
|
528
520
|
});
|
|
529
521
|
const alarmEndpoint = Effect.gen(function* () {
|
|
530
|
-
yield* (yield*
|
|
522
|
+
yield* (yield* ThreadMaintenance).pass;
|
|
531
523
|
});
|
|
532
524
|
const gateEndpoint = Effect.gen(function* () {
|
|
533
|
-
yield* (yield*
|
|
525
|
+
yield* (yield* ThreadMaintenance).ensureAlarm;
|
|
534
526
|
});
|
|
535
527
|
/**
|
|
536
528
|
* Adapter from effect-cf's native Durable Object services to Effect Agent's existing platform
|
|
@@ -546,9 +538,9 @@ const effectCfPlatformLayer = (namespaceBinding, rpcTracing = false) => {
|
|
|
546
538
|
env
|
|
547
539
|
});
|
|
548
540
|
}));
|
|
549
|
-
const namespace = Layer.effect(
|
|
550
|
-
const binding = yield*
|
|
551
|
-
return
|
|
541
|
+
const namespace = Layer.effect(ThreadObjectNamespace)(Effect.gen(function* () {
|
|
542
|
+
const binding = yield* threadNamespaceFromEnv(yield* WorkerEnvironment, namespaceBinding);
|
|
543
|
+
return ThreadObjectNamespace.of({
|
|
552
544
|
namespace: binding,
|
|
553
545
|
...rpcTracing === true ? { rpcTracing: namespaceBinding } : {}
|
|
554
546
|
});
|
|
@@ -556,14 +548,16 @@ const effectCfPlatformLayer = (namespaceBinding, rpcTracing = false) => {
|
|
|
556
548
|
return Layer.merge(context, namespace);
|
|
557
549
|
};
|
|
558
550
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
551
|
+
* Export a composed application Layer as a native Durable Object class.
|
|
552
|
+
* Bootstrap services are provided to the whole graph before it acquires, so application Layers
|
|
553
|
+
* can yield effect-cf's WorkerEnvironment and DurableObjectState, derived identity, and Crypto.
|
|
554
|
+
* Application dependencies remain visible until Layer.provide satisfies them. effect-cf owns the
|
|
555
|
+
* cached ManagedRuntime, native RPC methods, event scopes, and telemetry flushing.
|
|
556
|
+
* Initialization is local and bounded inside the constructor gate. Cloudflare eviction does not
|
|
557
|
+
* guarantee finalizers; put resources requiring timely release in scoped operations or eventLayer.
|
|
564
558
|
*/
|
|
565
|
-
const
|
|
566
|
-
const application =
|
|
559
|
+
const make = (applicationLayer, options) => {
|
|
560
|
+
const application = applicationLayer.pipe(Layer.provideMerge(layerConfig(options)), Layer.provideMerge(effectCfPlatformLayer(options.namespaceBinding, options.rpcTracing)));
|
|
567
561
|
const runtime = Layer.effectContext(Effect.gen(function* () {
|
|
568
562
|
const state = yield* DurableObjectState.DurableObjectState;
|
|
569
563
|
const scope = yield* Effect.scope;
|
|
@@ -589,19 +583,19 @@ const makeConversationObjectClass = (options, observability) => {
|
|
|
589
583
|
portCall: (encoded) => portCallEndpoint(encoded),
|
|
590
584
|
wake: () => wakeEndpoint
|
|
591
585
|
};
|
|
592
|
-
const
|
|
586
|
+
const EffectCfThreadObject = DurableObject.make(runtime, {
|
|
593
587
|
...options.rpcTracing === true ? { rpcTracing: { service: options.namespaceBinding } } : {},
|
|
594
|
-
...
|
|
588
|
+
...options.eventLayer === void 0 ? {} : { eventLayer: options.eventLayer },
|
|
595
589
|
initialize: Effect.void,
|
|
596
590
|
rpc,
|
|
597
591
|
alarm: () => alarmEndpoint
|
|
598
592
|
});
|
|
599
|
-
class
|
|
593
|
+
class ThreadObject extends EffectCfThreadObject {
|
|
600
594
|
alarm(alarmInfo) {
|
|
601
595
|
return super.alarm?.(alarmInfo);
|
|
602
596
|
}
|
|
603
597
|
}
|
|
604
|
-
return
|
|
598
|
+
return ThreadObject;
|
|
605
599
|
};
|
|
606
600
|
//#endregion
|
|
607
601
|
//#region src/code-mode-executor.ts
|
|
@@ -1199,6 +1193,6 @@ const dynamicWorkerCodeExecutorLayer = (options) => Layer.effect(CodeExecutor, E
|
|
|
1199
1193
|
return CodeExecutor.of({ execute: makeExecute(options, clock) });
|
|
1200
1194
|
}));
|
|
1201
1195
|
//#endregion
|
|
1202
|
-
export { AbortRecorded,
|
|
1196
|
+
export { AbortRecorded, AdmissionLimitExceeded, ApprovalRecorded, AwaitProgressRequest, CLOUDFLARE_DATABASE_CAP_BYTES, CLOUDFLARE_RUNTIME_DEFAULTS, CancelProgressRequest, CloudflareAdmissionLimitsValue, CloudflareBindingError, CloudflareDurableRuntimeConfig, CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError, CloudflareSchedulingClient, CloudflareSubscriptionConfigError, CloudflareSubscriptionsClient, CloudflareThreadClient, DEFAULT_MAX_DATABASE_BYTES, DurableAlarmError, DurableAlarmService, DurableObjectContext, HostFailed, HostFailure, HostProtocolError, HostResponse, MaintenancePassReport, ObservePageRequest, ObservedPage, ProgressCancelled, ProgressObserved, ProgressWaitRegistry, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerProtocolError, SettlementReached, SubmitRequest, SubmitSucceeded, SubscriptionAlarmProtocolError, SubscriptionPartitionIdentity, SubscriptionPartitionNamespace, SubscriptionPartitionProtocolError, ThreadClientError, ThreadMaintenance, ThreadMaintenanceFailpoint, thread_object_exports as ThreadObject, ThreadObjectIdentity, ThreadObjectNamespace, ThreadObjectPorts, UnknownResolutionRecorded, boundHostDiagnostic, cloudflarePreparedInputAdmissionLayer, cloudflareScheduledInputAdmissionLayer, cloudflareWakeSchedulerLayer, decodeAbortCommand, decodeApprovalDecisionCommand, decodeAwaitProgressRequest, decodeCancelProgressRequest, decodeHostResponse, decodeObservePageRequest, decodeReceipt, decodeSubmitRequest, decodeUnknownResolutionCommand, disposeRpcHandle, dynamicWorkerCodeExecutorLayer, dynamicWorkerImplementation, encodeAbortCommand, encodeApprovalDecisionCommand, encodeAwaitProgressRequest, encodeCancelProgressRequest, encodeHostResponse, encodeObservePageRequest, encodeReceipt, encodeSubmitRequest, encodeUnknownResolutionCommand, makeScheduleOwnerObjectClass, makeSubscriptionPartitionObjectClass, sourcePartitionName, threadNamespaceFromEnv, threadNamespaceLayer, threadPortTransportLayer, validateCloudflareSubscriptionLimits };
|
|
1203
1197
|
|
|
1204
1198
|
//# sourceMappingURL=index.mjs.map
|