@effect-agent/platform-cloudflare 0.0.1-beta.6 → 0.1.0-beta.8
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.d.mts +24 -57
- package/dist/index.mjs +63 -368
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -19
- package/src/config.ts +0 -3
- package/src/conversation-object.ts +139 -218
- package/src/index.ts +0 -1
- package/src/layers.ts +5 -14
- package/src/telemetry-internal.ts +0 -432
- package/src/telemetry.ts +0 -37
package/package.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-agent/platform-cloudflare",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0-beta.8",
|
|
4
|
+
"exports": {
|
|
5
|
+
".": {
|
|
6
|
+
"types": "./dist/index.d.mts",
|
|
7
|
+
"default": "./dist/index.mjs"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@effect-agent/core": "0.1.0-beta.8",
|
|
12
|
+
"@effect-agent/sandbox": "0.1.0-beta.8",
|
|
13
|
+
"@effect-agent/session": "0.1.0-beta.8",
|
|
14
|
+
"@effect-agent/storage-cloudflare": "0.1.0-beta.8",
|
|
15
|
+
"@effect/platform-browser": "4.0.0-beta.107",
|
|
16
|
+
"@effect/sql-sqlite-do": "4.0.0-beta.107",
|
|
17
|
+
"effect": "4.0.0-beta.107",
|
|
18
|
+
"effect-cf": "0.25.3"
|
|
19
|
+
},
|
|
4
20
|
"description": "Class DC layer assembly for Effect Agent: SQLite-backed Conversation Durable Objects with alarm-driven recovery.",
|
|
5
21
|
"license": "MIT",
|
|
6
22
|
"repository": {
|
|
@@ -13,12 +29,6 @@
|
|
|
13
29
|
"src"
|
|
14
30
|
],
|
|
15
31
|
"type": "module",
|
|
16
|
-
"exports": {
|
|
17
|
-
".": {
|
|
18
|
-
"types": "./dist/index.d.mts",
|
|
19
|
-
"default": "./dist/index.mjs"
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
32
|
"publishConfig": {
|
|
23
33
|
"access": "public"
|
|
24
34
|
},
|
|
@@ -27,21 +37,12 @@
|
|
|
27
37
|
"check": "tsc --noEmit -p tsconfig.json",
|
|
28
38
|
"test": "vitest run"
|
|
29
39
|
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"@effect-agent/core": "0.0.1-beta.6",
|
|
32
|
-
"@effect-agent/sandbox": "0.0.1-beta.5",
|
|
33
|
-
"@effect-agent/session": "0.0.1-beta.6",
|
|
34
|
-
"@effect-agent/storage-cloudflare": "0.0.1-beta.6",
|
|
35
|
-
"@effect/platform-browser": "4.0.0-beta.107",
|
|
36
|
-
"@effect/sql-sqlite-do": "4.0.0-beta.107",
|
|
37
|
-
"effect": "4.0.0-beta.107"
|
|
38
|
-
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@cloudflare/vitest-pool-workers": "0.21.3",
|
|
41
42
|
"@cloudflare/workers-types": "5.20260813.1",
|
|
42
|
-
"@effect-agent/capabilities": "0.0
|
|
43
|
-
"@effect-agent/engine": "0.0
|
|
44
|
-
"@effect-agent/testing": "0.0
|
|
43
|
+
"@effect-agent/capabilities": "0.1.0-beta.6",
|
|
44
|
+
"@effect-agent/engine": "0.1.0-beta.6",
|
|
45
|
+
"@effect-agent/testing": "0.1.0-beta.6",
|
|
45
46
|
"@effect/vitest": "4.0.0-beta.107",
|
|
46
47
|
"esbuild": "0.28.1",
|
|
47
48
|
"miniflare": "4.20260730.0",
|
package/src/config.ts
CHANGED
|
@@ -103,8 +103,6 @@ export class CloudflareDurableRuntimeConfigValue extends Schema.Class<Cloudflare
|
|
|
103
103
|
abortPollInterval: PositiveMillis,
|
|
104
104
|
/** Canonical observation poll cadence of the Durable Object store. */
|
|
105
105
|
observationPollInterval: NonNegativeMillis,
|
|
106
|
-
/** Cooperative background-export budget; native Object delivery never awaits the flush. */
|
|
107
|
-
telemetryFlushTimeout: PositiveMillis,
|
|
108
106
|
/** Per-value byte bound; must stay under the platform's 2 MB SQLite value limit. */
|
|
109
107
|
maxStoredValueBytes: Schema.Int.check(
|
|
110
108
|
Schema.isGreaterThan(0),
|
|
@@ -131,7 +129,6 @@ export const CLOUDFLARE_RUNTIME_DEFAULTS = {
|
|
|
131
129
|
leaseRenewalInterval: 10_000,
|
|
132
130
|
abortPollInterval: 500,
|
|
133
131
|
observationPollInterval: 25,
|
|
134
|
-
telemetryFlushTimeout: 2_000,
|
|
135
132
|
maxStoredValueBytes: DEFAULT_MAX_STORED_VALUE_BYTES,
|
|
136
133
|
verifyOnOpen: false,
|
|
137
134
|
maxQueueDepthPerLane: 256,
|
|
@@ -29,16 +29,26 @@ import {
|
|
|
29
29
|
SubmissionLookupByKey,
|
|
30
30
|
type DurableSubmitAgent,
|
|
31
31
|
} from "@effect-agent/session";
|
|
32
|
-
import { DurableObject } from "cloudflare:workers";
|
|
33
|
-
import { Effect, Layer,
|
|
32
|
+
import type { DurableObject as CloudflareDurableObject } from "cloudflare:workers";
|
|
33
|
+
import { Effect, Layer, Option, Schema, Stream } from "effect";
|
|
34
|
+
import {
|
|
35
|
+
DurableObject as EffectCfDurableObject,
|
|
36
|
+
DurableObjectState as EffectCfDurableObjectState,
|
|
37
|
+
WorkerEnvironment,
|
|
38
|
+
} from "effect-cf";
|
|
34
39
|
|
|
35
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
ConversationMaintenance,
|
|
42
|
+
DurableAlarmError,
|
|
43
|
+
DurableAlarmService,
|
|
44
|
+
type MaintenancePassFailure,
|
|
45
|
+
} from "./alarm.ts";
|
|
36
46
|
import {
|
|
37
47
|
ConversationObjectIdentity,
|
|
38
48
|
DurableObjectContext,
|
|
39
|
-
|
|
49
|
+
ConversationObjectNamespace,
|
|
50
|
+
conversationNamespaceFromEnv,
|
|
40
51
|
type CloudflareBindingError,
|
|
41
|
-
type ConversationObjectNamespace,
|
|
42
52
|
} from "./bindings.ts";
|
|
43
53
|
import {
|
|
44
54
|
AbortRecorded,
|
|
@@ -68,18 +78,10 @@ import {
|
|
|
68
78
|
type CloudflareDurableRuntimeOptions,
|
|
69
79
|
type CloudflareDurableRuntimeServices,
|
|
70
80
|
} from "./layers.ts";
|
|
71
|
-
import {
|
|
72
|
-
flushCloudflareRuntimeTelemetry,
|
|
73
|
-
logCloudflareWaitUntilRegistrationFailure,
|
|
74
|
-
makeCloudflareTelemetryFlushCoordinator,
|
|
75
|
-
registerCloudflareTelemetryAfterNativeSettlement,
|
|
76
|
-
withCloudflareNativeSpanFailure,
|
|
77
|
-
type CloudflareTelemetryFlushCoordinator,
|
|
78
|
-
} from "./telemetry-internal.ts";
|
|
79
|
-
import { CloudflareRuntimeTelemetry } from "./telemetry.ts";
|
|
80
81
|
|
|
81
82
|
/**
|
|
82
|
-
* `makeConversationObjectClass(options,
|
|
83
|
+
* `makeConversationObjectClass(options, observability?)` — the Conversation Durable Object
|
|
84
|
+
* (plan §1.4,
|
|
83
85
|
* D-P6-1): a factory returning a class that applications export from their Worker entry.
|
|
84
86
|
* One SQLite-backed Object per Conversation is the serialized owner (durability §6); the
|
|
85
87
|
* Object never runs `runResolvedWorker`'s infinite loop — each ingress event or alarm runs
|
|
@@ -105,15 +107,12 @@ export interface ConversationObjectOptions extends CloudflareDurableRuntimeOptio
|
|
|
105
107
|
readonly namespaceBinding: string;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
type
|
|
110
|
+
type EndpointServices = CloudflareDurableRuntimeServices | DurableObjectContext;
|
|
111
|
+
type RuntimeServices = EndpointServices | ConversationObjectNamespace;
|
|
112
|
+
type ConversationObjectInitializationError =
|
|
109
113
|
| CloudflareDurableRuntimeInitializationError
|
|
110
114
|
| CloudflareBindingError
|
|
111
|
-
|
|
|
112
|
-
|
|
113
|
-
type EndpointServices =
|
|
114
|
-
| CloudflareDurableRuntimeServices
|
|
115
|
-
| DurableObjectContext
|
|
116
|
-
| CloudflareRuntimeTelemetry;
|
|
115
|
+
| MaintenancePassFailure;
|
|
117
116
|
|
|
118
117
|
/** Port envelope tags whose owner-side execution durably mutates this Object's lane. */
|
|
119
118
|
const MUTATING_PORT_TAGS: ReadonlySet<string> = new Set([
|
|
@@ -609,71 +608,56 @@ const wakeEndpoint: Effect.Effect<void, never, EndpointServices> = Effect.gen(fu
|
|
|
609
608
|
);
|
|
610
609
|
});
|
|
611
610
|
|
|
612
|
-
const alarmEndpoint: Effect.Effect<void,
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
// Forcing ConversationMaintenance forces the whole Layer stack: migration + exact-version
|
|
621
|
-
// check + configuration decode (DEPLOY-008 fails typed here, before any mutation), then
|
|
622
|
-
// the defensive local ensure-alarm half of the invariant. LOCAL-ONLY by construction.
|
|
623
|
-
const maintenance = yield* ConversationMaintenance;
|
|
624
|
-
yield* maintenance.ensureAlarm;
|
|
625
|
-
});
|
|
611
|
+
const alarmEndpoint: Effect.Effect<void, MaintenancePassFailure, EndpointServices> = Effect.gen(
|
|
612
|
+
function* () {
|
|
613
|
+
const maintenance = yield* ConversationMaintenance;
|
|
614
|
+
// Typed pass failures propagate: the rejected promise makes workerd retry the alarm
|
|
615
|
+
// (at-least-once delivery), and the pass's own pre-arm keeps the slot committed meanwhile.
|
|
616
|
+
yield* maintenance.pass;
|
|
617
|
+
},
|
|
618
|
+
);
|
|
626
619
|
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
"retry",
|
|
637
|
-
"obligations",
|
|
638
|
-
"port_call",
|
|
639
|
-
"wake",
|
|
640
|
-
"alarm",
|
|
641
|
-
] as const;
|
|
642
|
-
|
|
643
|
-
type NativeEntrypoint = (typeof NATIVE_ENTRYPOINTS)[number];
|
|
620
|
+
const gateEndpoint: Effect.Effect<void, MaintenancePassFailure, EndpointServices> = Effect.gen(
|
|
621
|
+
function* () {
|
|
622
|
+
// Forcing ConversationMaintenance forces the whole Layer stack: migration + exact-version
|
|
623
|
+
// check + configuration decode (DEPLOY-008 fails typed here, before any mutation), then
|
|
624
|
+
// the defensive local ensure-alarm half of the invariant. LOCAL-ONLY by construction.
|
|
625
|
+
const maintenance = yield* ConversationMaintenance;
|
|
626
|
+
yield* maintenance.ensureAlarm;
|
|
627
|
+
},
|
|
628
|
+
);
|
|
644
629
|
|
|
645
630
|
/**
|
|
646
|
-
*
|
|
647
|
-
*
|
|
631
|
+
* Adapter from effect-cf's native Durable Object services to Effect Agent's existing platform
|
|
632
|
+
* ports. effect-cf owns the cached ManagedRuntime and supplies these values once per Object
|
|
633
|
+
* incarnation; the durable runtime continues to depend only on the narrow services below.
|
|
648
634
|
*/
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
)
|
|
668
|
-
)
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
flushCloudflareRuntimeTelemetry(config.telemetryFlushTimeout),
|
|
673
|
-
);
|
|
635
|
+
const effectCfPlatformLayer = (
|
|
636
|
+
namespaceBinding: string,
|
|
637
|
+
): Layer.Layer<
|
|
638
|
+
DurableObjectContext | ConversationObjectNamespace,
|
|
639
|
+
CloudflareBindingError,
|
|
640
|
+
EffectCfDurableObjectState.DurableObjectState | WorkerEnvironment
|
|
641
|
+
> => {
|
|
642
|
+
const context = Layer.effect(DurableObjectContext)(
|
|
643
|
+
Effect.gen(function* () {
|
|
644
|
+
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
645
|
+
const env = yield* WorkerEnvironment;
|
|
646
|
+
return DurableObjectContext.of({ ctx: state.raw, env });
|
|
647
|
+
}),
|
|
648
|
+
);
|
|
649
|
+
const namespace = Layer.effect(ConversationObjectNamespace)(
|
|
650
|
+
Effect.gen(function* () {
|
|
651
|
+
const env = yield* WorkerEnvironment;
|
|
652
|
+
const binding = yield* conversationNamespaceFromEnv(env, namespaceBinding);
|
|
653
|
+
return ConversationObjectNamespace.of({ namespace: binding });
|
|
654
|
+
}),
|
|
655
|
+
);
|
|
656
|
+
return Layer.merge(context, namespace);
|
|
657
|
+
};
|
|
674
658
|
|
|
675
659
|
/** The public endpoint surface of one Conversation Object instance. */
|
|
676
|
-
export interface ConversationObjectInstance extends
|
|
660
|
+
export interface ConversationObjectInstance extends CloudflareDurableObject {
|
|
677
661
|
submitEncoded(encoded: unknown): Promise<unknown>;
|
|
678
662
|
awaitSettlementEncoded(encoded: unknown): Promise<unknown>;
|
|
679
663
|
observePage(encoded: unknown): Promise<unknown>;
|
|
@@ -686,7 +670,7 @@ export interface ConversationObjectInstance extends DurableObject {
|
|
|
686
670
|
obligationsEncoded(encoded: unknown): Promise<unknown>;
|
|
687
671
|
portCall(encoded: unknown): Promise<unknown>;
|
|
688
672
|
wake(): Promise<void>;
|
|
689
|
-
alarm(): Promise<void
|
|
673
|
+
alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void;
|
|
690
674
|
}
|
|
691
675
|
|
|
692
676
|
/** The constructor shape workerd instantiates for each Conversation Object. */
|
|
@@ -696,150 +680,87 @@ export interface ConversationObjectClass {
|
|
|
696
680
|
|
|
697
681
|
/**
|
|
698
682
|
* Build the application's Conversation Object class (export it from the Worker entry).
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
* The explicit return type is what makes declaration emit possible: the class body carries a
|
|
704
|
-
* private runtime field, and TS4094 rejects inferring an exported anonymous class type around it.
|
|
683
|
+
* effect-cf owns the cached ManagedRuntime, native RPC methods, event scopes, and post-handler
|
|
684
|
+
* OTLP flush scheduling for RPC and alarm events. The optional outer Layer is built per native
|
|
685
|
+
* event, so a host can install Tracer/Logger/Metric services and `OtlpExporter.Flusher` without
|
|
686
|
+
* Effect Agent owning exporter lifecycle machinery.
|
|
705
687
|
*/
|
|
706
|
-
export const makeConversationObjectClass = <
|
|
707
|
-
TelemetryError = never,
|
|
708
|
-
AdditionalTelemetryOutputs = never,
|
|
709
|
-
>(
|
|
688
|
+
export const makeConversationObjectClass = <EventLayerError = never, EventServices = never>(
|
|
710
689
|
options: ConversationObjectOptions,
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
690
|
+
observability?: Layer.Layer<
|
|
691
|
+
EventServices,
|
|
692
|
+
EventLayerError,
|
|
693
|
+
| DurableObjectContext
|
|
694
|
+
| ConversationObjectNamespace
|
|
695
|
+
| EffectCfDurableObjectState.DurableObjectState
|
|
696
|
+
| WorkerEnvironment
|
|
715
697
|
>,
|
|
716
698
|
): ConversationObjectClass => {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
constructor(ctx: DurableObjectState, env: Cloudflare.Env) {
|
|
726
|
-
super(ctx, env);
|
|
727
|
-
this.#ctx = ctx;
|
|
728
|
-
const platform = Layer.mergeAll(
|
|
729
|
-
DurableObjectContext.layer(ctx, env),
|
|
730
|
-
conversationNamespaceLayer(env, options.namespaceBinding),
|
|
731
|
-
);
|
|
732
|
-
// Host observability is composed at the Worker edge, not hidden in runtime options. Its
|
|
733
|
-
// typed acquisition failure remains in the ManagedRuntime error, while the Object context
|
|
734
|
-
// and namespace are available to Layers that derive exporter configuration from `env`.
|
|
735
|
-
const hostTelemetry = (telemetry ?? CloudflareRuntimeTelemetry.layerNoop).pipe(
|
|
736
|
-
Layer.provideMerge(platform),
|
|
737
|
-
);
|
|
738
|
-
this.#runtime = ManagedRuntime.make(
|
|
739
|
-
CloudflareDurableRuntime.layer(options).pipe(
|
|
740
|
-
// Supplying the host Layer outermost makes its Logger/Tracer/Metric runtime
|
|
741
|
-
// configuration observe application Layer acquisition and every native endpoint.
|
|
742
|
-
Layer.provideMerge(hostTelemetry),
|
|
743
|
-
),
|
|
744
|
-
);
|
|
745
|
-
this.#telemetryFlush = makeCloudflareTelemetryFlushCoordinator(
|
|
746
|
-
() => this.#runtime.runPromise(flushNativeEntrypointTelemetry),
|
|
747
|
-
{
|
|
748
|
-
onReservationDropped: () => {
|
|
749
|
-
void this.#runtime.runSyncExit(
|
|
750
|
-
Effect.logWarning(
|
|
751
|
-
"Cloudflare telemetry delivery coalesced at the batch reservation limit",
|
|
752
|
-
).pipe(
|
|
753
|
-
Effect.annotateLogs({
|
|
754
|
-
"effect_agent.cloudflare.telemetry.failure_kind": "reservation_limit",
|
|
755
|
-
}),
|
|
756
|
-
),
|
|
757
|
-
);
|
|
758
|
-
},
|
|
759
|
-
},
|
|
760
|
-
);
|
|
761
|
-
// The constructor gate: local-only checks; never the recovery pass (deadlock argument,
|
|
762
|
-
// plan §1.4). A failure here fails every delivery with the typed construction error.
|
|
763
|
-
ctx.blockConcurrencyWhile(() => this.#runtime.runPromise(gateEndpoint));
|
|
764
|
-
}
|
|
699
|
+
const application: Layer.Layer<
|
|
700
|
+
RuntimeServices,
|
|
701
|
+
CloudflareDurableRuntimeInitializationError | CloudflareBindingError,
|
|
702
|
+
EffectCfDurableObjectState.DurableObjectState | WorkerEnvironment
|
|
703
|
+
> = CloudflareDurableRuntime.layer(options).pipe(
|
|
704
|
+
Layer.provideMerge(effectCfPlatformLayer(options.namespaceBinding)),
|
|
705
|
+
);
|
|
765
706
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
// Native entrypoints run only after blockConcurrencyWhile has built the cached runtime.
|
|
784
|
-
// Effect Logger invocation is synchronous; runSyncExit captures a broken logger without
|
|
785
|
-
// starting an unscoped fiber or changing the delivery Promise. The exact platform value
|
|
786
|
-
// stays confined to this registration callback; the automatic Logger diagnostic is
|
|
787
|
-
// deliberately content-free.
|
|
788
|
-
void this.#runtime.runSyncExit(logCloudflareWaitUntilRegistrationFailure(cause));
|
|
789
|
-
},
|
|
707
|
+
// The storage/config Layer must acquire inside Cloudflare's constructor gate. effect-cf owns
|
|
708
|
+
// the ManagedRuntime, while this effectContext ensures its first Layer build enters the gate
|
|
709
|
+
// before migration, compatibility checks, or alarm inspection touch Object storage.
|
|
710
|
+
const runtime: Layer.Layer<
|
|
711
|
+
RuntimeServices,
|
|
712
|
+
ConversationObjectInitializationError,
|
|
713
|
+
EffectCfDurableObjectState.DurableObjectState | WorkerEnvironment
|
|
714
|
+
> = Layer.effectContext(
|
|
715
|
+
Effect.gen(function* () {
|
|
716
|
+
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
717
|
+
const scope = yield* Effect.scope;
|
|
718
|
+
return yield* state.blockConcurrencyWhile(
|
|
719
|
+
Effect.gen(function* () {
|
|
720
|
+
const services = yield* Layer.buildWithScope(application, scope);
|
|
721
|
+
yield* gateEndpoint.pipe(Effect.provide(services));
|
|
722
|
+
return services;
|
|
723
|
+
}),
|
|
790
724
|
);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
async submitEncoded(encoded: unknown): Promise<unknown> {
|
|
794
|
-
return this.#runNative("submit", submitEndpoint(encoded));
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
async awaitSettlementEncoded(encoded: unknown): Promise<unknown> {
|
|
798
|
-
return this.#runNative("await_settlement", awaitSettlementEndpoint(encoded));
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
async observePage(encoded: unknown): Promise<unknown> {
|
|
802
|
-
return this.#runNative("observe", observePageEndpoint(encoded));
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
async abortEncoded(encoded: unknown): Promise<unknown> {
|
|
806
|
-
return this.#runNative("abort", abortEndpoint(encoded));
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
async resolveApprovalEncoded(encoded: unknown): Promise<unknown> {
|
|
810
|
-
return this.#runNative("resolve_approval", resolveApprovalEndpoint(encoded));
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
async resolveUnknownEncoded(encoded: unknown): Promise<unknown> {
|
|
814
|
-
return this.#runNative("resolve_unknown", resolveUnknownEndpoint(encoded));
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
async explainEncoded(encoded: unknown): Promise<unknown> {
|
|
818
|
-
return this.#runNative("explain", explainEndpoint(encoded));
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
async verifyEncoded(encoded: unknown): Promise<unknown> {
|
|
822
|
-
return this.#runNative("verify", verifyEndpoint(encoded));
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
async retryEncoded(encoded: unknown): Promise<unknown> {
|
|
826
|
-
return this.#runNative("retry", retryEndpoint(encoded));
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
async obligationsEncoded(encoded: unknown): Promise<unknown> {
|
|
830
|
-
return this.#runNative("obligations", obligationsEndpoint(encoded));
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
async portCall(encoded: unknown): Promise<unknown> {
|
|
834
|
-
return this.#runNative("port_call", portCallEndpoint(encoded));
|
|
835
|
-
}
|
|
725
|
+
}),
|
|
726
|
+
);
|
|
836
727
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
728
|
+
const rpc = {
|
|
729
|
+
submitEncoded: (encoded: unknown) => submitEndpoint(encoded),
|
|
730
|
+
awaitSettlementEncoded: (encoded: unknown) => awaitSettlementEndpoint(encoded),
|
|
731
|
+
observePage: (encoded: unknown) => observePageEndpoint(encoded),
|
|
732
|
+
abortEncoded: (encoded: unknown) => abortEndpoint(encoded),
|
|
733
|
+
resolveApprovalEncoded: (encoded: unknown) => resolveApprovalEndpoint(encoded),
|
|
734
|
+
resolveUnknownEncoded: (encoded: unknown) => resolveUnknownEndpoint(encoded),
|
|
735
|
+
explainEncoded: (encoded: unknown) => explainEndpoint(encoded),
|
|
736
|
+
verifyEncoded: (encoded: unknown) => verifyEndpoint(encoded),
|
|
737
|
+
retryEncoded: (encoded: unknown) => retryEndpoint(encoded),
|
|
738
|
+
obligationsEncoded: (encoded: unknown) => obligationsEndpoint(encoded),
|
|
739
|
+
portCall: (encoded: unknown) => portCallEndpoint(encoded),
|
|
740
|
+
wake: () => wakeEndpoint,
|
|
741
|
+
} satisfies EffectCfDurableObject.DurableObjectRpc<RuntimeServices | EventServices>;
|
|
742
|
+
|
|
743
|
+
const EffectCfConversationObject = EffectCfDurableObject.make<
|
|
744
|
+
RuntimeServices,
|
|
745
|
+
ConversationObjectInitializationError,
|
|
746
|
+
EventServices,
|
|
747
|
+
EventLayerError,
|
|
748
|
+
typeof rpc
|
|
749
|
+
>(runtime, {
|
|
750
|
+
...(observability === undefined ? {} : { eventLayer: observability }),
|
|
751
|
+
// Force the gated runtime Layer when Cloudflare loads this Object incarnation. Recovery stays
|
|
752
|
+
// in each bounded pass so cross-Object initialization cannot deadlock.
|
|
753
|
+
initialize: Effect.void,
|
|
754
|
+
rpc,
|
|
755
|
+
alarm: () => alarmEndpoint,
|
|
756
|
+
});
|
|
840
757
|
|
|
841
|
-
|
|
842
|
-
|
|
758
|
+
// effect-cf's class type keeps `alarm` optional even when the handler option is present. This
|
|
759
|
+
// concrete override reflects this factory's stronger contract while delegating execution to
|
|
760
|
+
// the effect-cf runtime unchanged.
|
|
761
|
+
class ConversationObject extends EffectCfConversationObject {
|
|
762
|
+
override alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void {
|
|
763
|
+
return super.alarm?.(alarmInfo);
|
|
843
764
|
}
|
|
844
765
|
}
|
|
845
766
|
|
package/src/index.ts
CHANGED
|
@@ -17,7 +17,6 @@ export * from "./config.ts";
|
|
|
17
17
|
export * from "./alarm.ts";
|
|
18
18
|
export * from "./wake-scheduler.ts";
|
|
19
19
|
export * from "./transport.ts";
|
|
20
|
-
export * from "./telemetry.ts";
|
|
21
20
|
export * from "./layers.ts";
|
|
22
21
|
export * from "./conversation-object.ts";
|
|
23
22
|
export * from "./client.ts";
|
package/src/layers.ts
CHANGED
|
@@ -31,8 +31,8 @@ import { Context, Duration, Effect, Layer, Schema } from "effect";
|
|
|
31
31
|
import { ConversationMaintenance, DurableAlarmService } from "./alarm.ts";
|
|
32
32
|
import {
|
|
33
33
|
ConversationObjectIdentity,
|
|
34
|
+
ConversationObjectNamespace,
|
|
34
35
|
DurableObjectContext,
|
|
35
|
-
type ConversationObjectNamespace,
|
|
36
36
|
} from "./bindings.ts";
|
|
37
37
|
import {
|
|
38
38
|
CLOUDFLARE_RUNTIME_DEFAULTS,
|
|
@@ -69,11 +69,6 @@ export interface CloudflareDurableRuntimeOptions {
|
|
|
69
69
|
readonly abortPollInterval?: number | undefined;
|
|
70
70
|
/** Milliseconds; default 25. */
|
|
71
71
|
readonly observationPollInterval?: number | undefined;
|
|
72
|
-
/**
|
|
73
|
-
* Milliseconds; default 2000. Cooperative budget for the background exporter flush registered
|
|
74
|
-
* after each native RPC, wake, or alarm span. Delivery never awaits the flush.
|
|
75
|
-
*/
|
|
76
|
-
readonly telemetryFlushTimeout?: number | undefined;
|
|
77
72
|
/** Bytes; default just under the 2 MB platform value limit. */
|
|
78
73
|
readonly maxStoredValueBytes?: number | undefined;
|
|
79
74
|
/** Default false. */
|
|
@@ -185,8 +180,6 @@ const configFromOptions = (
|
|
|
185
180
|
abortPollInterval: options.abortPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.abortPollInterval,
|
|
186
181
|
observationPollInterval:
|
|
187
182
|
options.observationPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.observationPollInterval,
|
|
188
|
-
telemetryFlushTimeout:
|
|
189
|
-
options.telemetryFlushTimeout ?? CLOUDFLARE_RUNTIME_DEFAULTS.telemetryFlushTimeout,
|
|
190
183
|
maxStoredValueBytes:
|
|
191
184
|
options.maxStoredValueBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxStoredValueBytes,
|
|
192
185
|
verifyOnOpen: options.verifyOnOpen ?? CLOUDFLARE_RUNTIME_DEFAULTS.verifyOnOpen,
|
|
@@ -261,9 +254,9 @@ const resolveBindings = (
|
|
|
261
254
|
* Storage compatibility is verified during construction: an incompatible database fails the
|
|
262
255
|
* Layer typed (`DoStorageCompatibilityError`) before anything is mutated (DEPLOY-008).
|
|
263
256
|
*
|
|
264
|
-
* Requires the two binding services (`DurableObjectContext`,
|
|
265
|
-
*
|
|
266
|
-
*
|
|
257
|
+
* Requires only the two binding services (`DurableObjectContext`,
|
|
258
|
+
* `ConversationObjectNamespace`) — platform values enter exclusively through Layers
|
|
259
|
+
* (DEPLOY-010).
|
|
267
260
|
*/
|
|
268
261
|
export class CloudflareDurableRuntime {
|
|
269
262
|
static layer(
|
|
@@ -372,13 +365,11 @@ export class CloudflareDurableRuntime {
|
|
|
372
365
|
Layer.provideMerge(base),
|
|
373
366
|
);
|
|
374
367
|
|
|
375
|
-
|
|
368
|
+
return Layer.mergeAll(
|
|
376
369
|
runtimeStack,
|
|
377
370
|
ConversationMaintenance.layer.pipe(Layer.provide(runtimeStack)),
|
|
378
371
|
portsEndpointLayer,
|
|
379
372
|
);
|
|
380
|
-
|
|
381
|
-
return application;
|
|
382
373
|
}),
|
|
383
374
|
);
|
|
384
375
|
}
|