effect-cf 0.40.2 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/D1.d.mts +1 -1
- package/dist/DurableObjectNamespace.mjs +17 -8
- package/dist/DurableObjectSqlite.mjs +12 -3
- package/dist/HyperdrivePg.d.mts +1 -1
- package/dist/RpcTargets.d.mts +31 -0
- package/dist/RpcTargets.mjs +73 -0
- package/dist/Worker.mjs +5 -4
- package/dist/Workflow.mjs +2 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/internal/Runtime.mjs +3 -2
- package/package.json +1 -1
- package/src/DurableObjectNamespace.ts +13 -4
- package/src/DurableObjectSqlite.ts +19 -4
- package/src/RpcTargets.ts +100 -0
- package/src/Worker.ts +27 -22
- package/src/Workflow.ts +6 -1
- package/src/index.ts +1 -0
- package/src/internal/Runtime.ts +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# effect-cf
|
|
2
2
|
|
|
3
|
+
## 0.41.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#159](https://github.com/danieljvdm/effect-cf/pull/159) [`8cbc534`](https://github.com/danieljvdm/effect-cf/commit/8cbc5344ffa2aa031b6d98a2845ca3b945cf7d5f) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Reuse Durable Object RPC targets within each invocation so callbacks cannot grow a new subrequest chain on every call. Incoming requests and durable retries retain separate target lifetimes. Expose RpcTargets for native RPC adapters sharing the same invocation boundary.
|
|
8
|
+
|
|
9
|
+
## 0.40.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#157](https://github.com/danieljvdm/effect-cf/pull/157) [`279eecd`](https://github.com/danieljvdm/effect-cf/commit/279eecd1a5ea9112e727497e0aac666142e7a7f8) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Prevent Durable Object SQLite transactions from stalling when a blocked owner timer precedes an Effect scheduler yield. Keep transaction isolation, rollback, and the caller's scheduler after the transaction completes.
|
|
14
|
+
|
|
3
15
|
## 0.40.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/D1.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import { WorkerEnvironment } from "./Environment.mjs";
|
|
|
2
2
|
import { BindingNotFoundError, BindingService, BindingValidationError } from "./Binding.mjs";
|
|
3
3
|
import * as Layer$1 from "effect/Layer";
|
|
4
4
|
import { D1Client } from "@effect/sql-d1";
|
|
5
|
-
import { Config } from "effect";
|
|
6
5
|
import { SqlClient } from "effect/unstable/sql";
|
|
6
|
+
import { Config } from "effect";
|
|
7
7
|
declare namespace D1_d_exports {
|
|
8
8
|
export { D1Definition, D1Service, D1SqlLayerOptions, Service, TypeId, make };
|
|
9
9
|
}
|
|
@@ -2,6 +2,7 @@ import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
|
2
2
|
import { layer as layer$1 } from "./Binding.mjs";
|
|
3
3
|
import { causeMessage } from "./internal/ErrorMessage.mjs";
|
|
4
4
|
import { decodeSuccess, encodeArgs } from "./RpcDefinition.mjs";
|
|
5
|
+
import { get, invalidate } from "./RpcTargets.mjs";
|
|
5
6
|
import { withRpcClientSpan, withRpcTraceContext } from "./RpcTracing.mjs";
|
|
6
7
|
import { invokeRpcMethod } from "./internal/RpcInvocation.mjs";
|
|
7
8
|
import { resolve, scoped } from "./Rpc.mjs";
|
|
@@ -41,8 +42,16 @@ const makeClient = (definition) => {
|
|
|
41
42
|
const newUniqueId = (options) => Effect.sync(() => namespace.newUniqueId(options));
|
|
42
43
|
const idFromName = (name) => Effect.sync(() => namespace.idFromName(name));
|
|
43
44
|
const idFromString = (id) => Effect.sync(() => namespace.idFromString(id));
|
|
44
|
-
const get = (id, options) =>
|
|
45
|
-
|
|
45
|
+
const get$1 = (id, options) => get(namespace, JSON.stringify([
|
|
46
|
+
"id",
|
|
47
|
+
id.toString(),
|
|
48
|
+
options
|
|
49
|
+
]), () => namespace.get(id, options)).pipe(Effect.orDie);
|
|
50
|
+
const getByName = (name, options) => get(namespace, JSON.stringify([
|
|
51
|
+
"name",
|
|
52
|
+
name,
|
|
53
|
+
options
|
|
54
|
+
]), () => namespace.getByName(name, options)).pipe(Effect.orDie);
|
|
46
55
|
const jurisdiction = (value) => Effect.sync(() => namespace.jurisdiction(value));
|
|
47
56
|
const fetch = (stub, input, init) => Effect.tryPromise({
|
|
48
57
|
try: (signal) => {
|
|
@@ -56,7 +65,7 @@ const makeClient = (definition) => {
|
|
|
56
65
|
binding: definition.binding,
|
|
57
66
|
cause
|
|
58
67
|
})
|
|
59
|
-
});
|
|
68
|
+
}).pipe(Effect.tapCause(() => invalidate(stub)));
|
|
60
69
|
const rpc = Effect.fnUntraced(function* (stub, method, ...args) {
|
|
61
70
|
const methodName = String(method);
|
|
62
71
|
const encodedArgs = definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
|
|
@@ -69,7 +78,7 @@ const makeClient = (definition) => {
|
|
|
69
78
|
binding: definition.binding,
|
|
70
79
|
method: methodName,
|
|
71
80
|
cause
|
|
72
|
-
}));
|
|
81
|
+
})).pipe(Effect.tapCause(() => invalidate(stub)));
|
|
73
82
|
});
|
|
74
83
|
const decodeSuccess$1 = Effect.fnUntraced(function* (methodName, value) {
|
|
75
84
|
if (definition.definition === void 0) return value;
|
|
@@ -81,7 +90,7 @@ const makeClient = (definition) => {
|
|
|
81
90
|
});
|
|
82
91
|
const call = Effect.fnUntraced(function* (stub, method, ...args) {
|
|
83
92
|
const methodName = String(method);
|
|
84
|
-
const value = yield* resolve(yield* rpc(stub, method, ...args)).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
|
|
93
|
+
const value = yield* resolve(yield* rpc(stub, method, ...args)).pipe(Effect.tapCause(() => invalidate(stub)), Effect.mapError((cause) => new DurableObjectRpcError({
|
|
85
94
|
binding: definition.binding,
|
|
86
95
|
method: methodName,
|
|
87
96
|
cause
|
|
@@ -91,7 +100,7 @@ const makeClient = (definition) => {
|
|
|
91
100
|
const scopedCall = Effect.fnUntraced(function* (stub, method, ...args) {
|
|
92
101
|
const methodName = String(method);
|
|
93
102
|
const result = yield* rpc(stub, method, ...args);
|
|
94
|
-
const value = yield* scoped(result).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
|
|
103
|
+
const value = yield* scoped(result).pipe(Effect.tapCause(() => invalidate(stub)), Effect.mapError((cause) => new DurableObjectRpcError({
|
|
95
104
|
binding: definition.binding,
|
|
96
105
|
method: methodName,
|
|
97
106
|
cause
|
|
@@ -101,14 +110,14 @@ const makeClient = (definition) => {
|
|
|
101
110
|
const directMethods = makeDirectMethods(definition.definition, {
|
|
102
111
|
call,
|
|
103
112
|
fetch,
|
|
104
|
-
get,
|
|
113
|
+
get: get$1,
|
|
105
114
|
getByName
|
|
106
115
|
});
|
|
107
116
|
return Object.assign(directMethods, {
|
|
108
117
|
newUniqueId,
|
|
109
118
|
idFromName,
|
|
110
119
|
idFromString,
|
|
111
|
-
get,
|
|
120
|
+
get: get$1,
|
|
112
121
|
getByName,
|
|
113
122
|
jurisdiction,
|
|
114
123
|
fetch,
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
2
2
|
import { DurableObjectState } from "./DurableObjectState.mjs";
|
|
3
|
+
import * as Context from "effect/Context";
|
|
3
4
|
import * as Effect from "effect/Effect";
|
|
4
5
|
import * as Layer from "effect/Layer";
|
|
5
6
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
7
|
+
import * as Scheduler from "effect/Scheduler";
|
|
8
|
+
import * as Reactivity from "effect/unstable/reactivity/Reactivity";
|
|
9
|
+
import { SqlClient } from "effect/unstable/sql";
|
|
6
10
|
//#region src/DurableObjectSqlite.ts
|
|
7
11
|
var DurableObjectSqlite_exports = /* @__PURE__ */ __exportAll({ layer: () => layer });
|
|
8
|
-
const layer = (options) => Layer.
|
|
12
|
+
const layer = (options) => Layer.effectContext(Effect.gen(function* () {
|
|
9
13
|
const state = yield* DurableObjectState;
|
|
10
|
-
|
|
14
|
+
const client = yield* SqliteClient.make({
|
|
11
15
|
...options,
|
|
12
16
|
storage: state.raw.storage
|
|
13
17
|
});
|
|
14
|
-
|
|
18
|
+
const original = client.withTransaction;
|
|
19
|
+
const scheduler = new Scheduler.MixedScheduler("sync");
|
|
20
|
+
const withTransaction = (body) => original(body).pipe(Effect.provideService(Scheduler.Scheduler, scheduler));
|
|
21
|
+
Object.assign(client, { withTransaction });
|
|
22
|
+
return Context.make(SqliteClient.SqliteClient, client).pipe(Context.add(SqlClient.SqlClient, client));
|
|
23
|
+
})).pipe(Layer.provide(Reactivity.layer));
|
|
15
24
|
//#endregion
|
|
16
25
|
export { DurableObjectSqlite_exports, layer };
|
package/dist/HyperdrivePg.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import { WorkerEnvironment } from "./Environment.mjs";
|
|
|
2
2
|
import { BindingNotFoundError, BindingValidationError } from "./Binding.mjs";
|
|
3
3
|
import { LayerOptions, TagClass } from "./Hyperdrive.mjs";
|
|
4
4
|
import * as Layer from "effect/Layer";
|
|
5
|
-
import { PgClient } from "@effect/sql-pg";
|
|
6
5
|
import { SqlClient, SqlError } from "effect/unstable/sql";
|
|
6
|
+
import { PgClient } from "@effect/sql-pg";
|
|
7
7
|
//#region src/HyperdrivePg.d.ts
|
|
8
8
|
type PgLayerOptions = Omit<Parameters<typeof PgClient.makeClient>[0], "url" | "host" | "port" | "path" | "ssl" | "database" | "username" | "password" | "stream">;
|
|
9
9
|
declare const layer: <Self, Id extends string>(tag: TagClass<Self, Id>, binding: LayerOptions, options?: PgLayerOptions) => Layer.Layer<PgClient.PgClient | SqlClient.SqlClient, BindingNotFoundError | BindingValidationError | SqlError.SqlError, WorkerEnvironment>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Scope from "effect/Scope";
|
|
3
|
+
declare namespace RpcTargets_d_exports {
|
|
4
|
+
export { RpcTargetError, get, invalidate, withScope };
|
|
5
|
+
}
|
|
6
|
+
declare const RpcTargetError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
7
|
+
readonly _tag: "RpcTargetError";
|
|
8
|
+
} & Readonly<A>;
|
|
9
|
+
/** A native RPC target could not be constructed. */
|
|
10
|
+
declare class RpcTargetError extends RpcTargetError_base<{
|
|
11
|
+
readonly cause: unknown;
|
|
12
|
+
}> {}
|
|
13
|
+
/**
|
|
14
|
+
* Reuse a native RPC target within the current invocation. Native Durable Object
|
|
15
|
+
* stubs capture the calling request's channel when created. Recreating a stub
|
|
16
|
+
* after a callback can extend that callback's call chain until Cloudflare's
|
|
17
|
+
* subrequest depth limit is reached, even when an alarm owns the work.
|
|
18
|
+
*
|
|
19
|
+
* The owner and address must identify one target and its construction options.
|
|
20
|
+
* Outside an effect-cf invocation (or withScope), each lookup constructs a target.
|
|
21
|
+
*/
|
|
22
|
+
declare const get: <A extends object, Owner extends object>(owner: Owner, address: string, create: () => A) => Effect.Effect<A, RpcTargetError, never>;
|
|
23
|
+
/** Discard a failed native target so a subsequent call can acquire a fresh channel. */
|
|
24
|
+
declare const invalidate: <Target extends object>(target: Target) => Effect.Effect<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Own RPC targets in the current Scope, including a transferred response stream,
|
|
27
|
+
* never across incoming requests or durable retries. effect-cf entrypoints install this boundary automatically.
|
|
28
|
+
*/
|
|
29
|
+
declare const withScope: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R | Scope.Scope>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { RpcTargetError, RpcTargets_d_exports, get, invalidate, withScope };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import * as Context from "effect/Context";
|
|
3
|
+
import * as Data from "effect/Data";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Option from "effect/Option";
|
|
6
|
+
//#region src/RpcTargets.ts
|
|
7
|
+
var RpcTargets_exports = /* @__PURE__ */ __exportAll({
|
|
8
|
+
RpcTargetError: () => RpcTargetError,
|
|
9
|
+
get: () => get,
|
|
10
|
+
invalidate: () => invalidate,
|
|
11
|
+
withScope: () => withScope
|
|
12
|
+
});
|
|
13
|
+
/** A native RPC target could not be constructed. */
|
|
14
|
+
var RpcTargetError = class extends Data.TaggedError("RpcTargetError") {};
|
|
15
|
+
var CurrentTargets = class extends Context.Service()("effect-cf/RpcTargets") {};
|
|
16
|
+
/**
|
|
17
|
+
* Reuse a native RPC target within the current invocation. Native Durable Object
|
|
18
|
+
* stubs capture the calling request's channel when created. Recreating a stub
|
|
19
|
+
* after a callback can extend that callback's call chain until Cloudflare's
|
|
20
|
+
* subrequest depth limit is reached, even when an alarm owns the work.
|
|
21
|
+
*
|
|
22
|
+
* The owner and address must identify one target and its construction options.
|
|
23
|
+
* Outside an effect-cf invocation (or withScope), each lookup constructs a target.
|
|
24
|
+
*/
|
|
25
|
+
const get = (owner, address, create) => Effect.flatMap(Effect.serviceOption(CurrentTargets), (targets) => Effect.try({
|
|
26
|
+
try: () => Option.isSome(targets) ? targets.value.get(owner, address, create) : create(),
|
|
27
|
+
catch: (cause) => new RpcTargetError({ cause })
|
|
28
|
+
}));
|
|
29
|
+
/** Discard a failed native target so a subsequent call can acquire a fresh channel. */
|
|
30
|
+
const invalidate = (target) => Effect.map(Effect.serviceOption(CurrentTargets), (targets) => {
|
|
31
|
+
if (Option.isSome(targets)) targets.value.invalidate(target);
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Own RPC targets in the current Scope, including a transferred response stream,
|
|
35
|
+
* never across incoming requests or durable retries. effect-cf entrypoints install this boundary automatically.
|
|
36
|
+
*/
|
|
37
|
+
const withScope = (effect) => Effect.gen(function* () {
|
|
38
|
+
let active = true;
|
|
39
|
+
let owners = /* @__PURE__ */ new WeakMap();
|
|
40
|
+
let addresses = /* @__PURE__ */ new WeakMap();
|
|
41
|
+
const targets = {
|
|
42
|
+
get: (owner, address, create) => {
|
|
43
|
+
if (!active) return create();
|
|
44
|
+
let entries = owners.get(owner);
|
|
45
|
+
if (entries === void 0) {
|
|
46
|
+
entries = /* @__PURE__ */ new Map();
|
|
47
|
+
owners.set(owner, entries);
|
|
48
|
+
}
|
|
49
|
+
const existing = entries.get(address);
|
|
50
|
+
if (existing !== void 0) return existing;
|
|
51
|
+
const target = create();
|
|
52
|
+
entries.set(address, target);
|
|
53
|
+
addresses.set(target, {
|
|
54
|
+
entries,
|
|
55
|
+
address
|
|
56
|
+
});
|
|
57
|
+
return target;
|
|
58
|
+
},
|
|
59
|
+
invalidate: (target) => {
|
|
60
|
+
const entry = addresses.get(target);
|
|
61
|
+
if (entry?.entries.get(entry.address) === target) entry.entries.delete(entry.address);
|
|
62
|
+
addresses.delete(target);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
66
|
+
active = false;
|
|
67
|
+
owners = /* @__PURE__ */ new WeakMap();
|
|
68
|
+
addresses = /* @__PURE__ */ new WeakMap();
|
|
69
|
+
}));
|
|
70
|
+
return yield* effect.pipe(Effect.provideService(CurrentTargets, targets));
|
|
71
|
+
});
|
|
72
|
+
//#endregion
|
|
73
|
+
export { RpcTargetError, RpcTargets_exports, get, invalidate, withScope };
|
package/dist/Worker.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
|
2
2
|
import { fromExecutionContext } from "./internal/WorkerContext.mjs";
|
|
3
3
|
import { fromMessage, fromMessageBatch } from "./Queue.mjs";
|
|
4
4
|
import { reservedMethodNames as reservedMethodNames$1 } from "./RpcDefinition.mjs";
|
|
5
|
+
import { withScope } from "./RpcTargets.mjs";
|
|
5
6
|
import { assumeEntrypointClass, defineEntrypointRpcMethods } from "./internal/Entrypoint.mjs";
|
|
6
7
|
import { makeEntrypointRuntime, runEventPromise } from "./internal/Runtime.mjs";
|
|
7
8
|
import { scheduleTelemetryFlush as scheduleTelemetryFlush$1 } from "./internal/Telemetry.mjs";
|
|
@@ -61,15 +62,15 @@ const renderFetchSuccess = (effect, eventLayer) => Effect.suspend(() => {
|
|
|
61
62
|
context
|
|
62
63
|
});
|
|
63
64
|
});
|
|
64
|
-
const telemetryMiddleware = HttpMiddleware.make((self) => Effect.gen(function* () {
|
|
65
|
+
const telemetryMiddleware = HttpMiddleware.make((self) => withScope(Effect.gen(function* () {
|
|
65
66
|
yield* Effect.addFinalizer(() => scheduleTelemetryFlush);
|
|
66
67
|
return yield* self;
|
|
67
|
-
}));
|
|
68
|
-
const handled = eventLayer === void 0 ? HttpEffect.toHandled(httpApp, handleResponse, telemetryMiddleware) : Effect.flatMap(References.TracerEnabled, (tracerEnabled) => HttpEffect.toHandled(httpApp, handleResponse, HttpMiddleware.make((self) => Effect.provideService(Effect.gen(function* () {
|
|
68
|
+
})));
|
|
69
|
+
const handled = eventLayer === void 0 ? HttpEffect.toHandled(httpApp, handleResponse, telemetryMiddleware) : Effect.flatMap(References.TracerEnabled, (tracerEnabled) => HttpEffect.toHandled(httpApp, handleResponse, HttpMiddleware.make((self) => withScope(Effect.provideService(Effect.gen(function* () {
|
|
69
70
|
const context = yield* Layer.build(Layer.fresh(eventLayer));
|
|
70
71
|
yield* Effect.addFinalizer(() => Effect.provideContext(scheduleTelemetryFlush, context));
|
|
71
72
|
return yield* HttpMiddleware.tracer(self).pipe(Effect.onExit(() => Effect.yieldNow), Effect.provideContext(context));
|
|
72
|
-
}), References.TracerEnabled, tracerEnabled))).pipe(Effect.withTracerEnabled(false)));
|
|
73
|
+
}), References.TracerEnabled, tracerEnabled)))).pipe(Effect.withTracerEnabled(false)));
|
|
73
74
|
const captured = () => nativeResponse ?? webResponse ?? new Response(null, { status: 500 });
|
|
74
75
|
return Effect.matchCause(handled, {
|
|
75
76
|
onFailure: captured,
|
package/dist/Workflow.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
2
2
|
import { causeMessage } from "./internal/ErrorMessage.mjs";
|
|
3
3
|
import { fromExecutionContext } from "./internal/WorkerContext.mjs";
|
|
4
|
+
import { withScope } from "./RpcTargets.mjs";
|
|
4
5
|
import { assumeEntrypointClass } from "./internal/Entrypoint.mjs";
|
|
5
6
|
import { makeEntrypointRuntime, runEventPromise } from "./internal/Runtime.mjs";
|
|
6
7
|
import { ExecutionContext, WorkerContext } from "./Worker.mjs";
|
|
@@ -74,7 +75,7 @@ const fromWorkflowStep = (step) => ({
|
|
|
74
75
|
return yield* Effect.tryPromise({
|
|
75
76
|
try: () => {
|
|
76
77
|
const run = (stepContext) => {
|
|
77
|
-
const stepEffect = Effect.scoped(Effect.provideService(effect, WorkflowStepContext$1, stepContext));
|
|
78
|
+
const stepEffect = Effect.scoped(withScope(Effect.provideService(effect, WorkflowStepContext$1, stepContext)));
|
|
78
79
|
return runPromise(exposeCloudflareNonRetryableError(Effect.provideContext(stepEffect, context)));
|
|
79
80
|
};
|
|
80
81
|
const rawStep = step;
|
package/dist/index.d.mts
CHANGED
|
@@ -34,8 +34,9 @@ import { Email_d_exports } from "./Email.mjs";
|
|
|
34
34
|
import { Images_d_exports } from "./Images.mjs";
|
|
35
35
|
import { Kv_d_exports } from "./Kv.mjs";
|
|
36
36
|
import { R2_d_exports } from "./R2.mjs";
|
|
37
|
+
import { RpcTargets_d_exports } from "./RpcTargets.mjs";
|
|
37
38
|
import { Vectorize_d_exports } from "./Vectorize.mjs";
|
|
38
39
|
import { WebTransport_d_exports } from "./WebTransport.mjs";
|
|
39
40
|
import { WorkflowDefinition_d_exports } from "./WorkflowDefinition.mjs";
|
|
40
41
|
import { Workflow_d_exports } from "./Workflow.mjs";
|
|
41
|
-
export { AiGateway_d_exports as AiGateway, AnalyticsEngine_d_exports as AnalyticsEngine, Artifacts_d_exports as Artifacts, Binding_d_exports as Binding, BrowserRendering_d_exports as BrowserRendering, Cache_d_exports as Cache, CloudflareOtlp_d_exports as CloudflareOtlp, CloudflareTracer_d_exports as CloudflareTracer, ContainerNamespace_d_exports as ContainerNamespace, D1_d_exports as D1, DurableObject_d_exports as DurableObject, DurableObjectAlarm_d_exports as DurableObjectAlarm, DurableObjectDefinition_d_exports as DurableObjectDefinition, DurableObjectNamespace_d_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_d_exports as DurableObjectRpcWebSocket, DurableObjectSqlite_d_exports as DurableObjectSqlite, DurableObjectState_d_exports as DurableObjectState, DurableObjectStorage_d_exports as DurableObjectStorage, DurableObjectWebSocket_d_exports as DurableObjectWebSocket, Email_d_exports as Email, Environment_d_exports as Environment, Hyperdrive_d_exports as Hyperdrive, Images_d_exports as Images, Kv_d_exports as Kv, Queue_d_exports as Queue, QueueBinding_d_exports as QueueBinding, QueueDefinition_d_exports as QueueDefinition, R2_d_exports as R2, Rpc_d_exports as Rpc, RpcDefinition_d_exports as RpcDefinition, RpcTracing_d_exports as RpcTracing, ServiceBinding_d_exports as ServiceBinding, Vectorize_d_exports as Vectorize, WebTransport_d_exports as WebTransport, Worker_d_exports as Worker, WorkerConfig, WorkerDefinition_d_exports as WorkerDefinition, type WorkerEnv, WorkerEnvironment, WorkersAi_d_exports as WorkersAi, Workflow_d_exports as Workflow, WorkflowBinding_d_exports as WorkflowBinding, WorkflowDefinition_d_exports as WorkflowDefinition };
|
|
42
|
+
export { AiGateway_d_exports as AiGateway, AnalyticsEngine_d_exports as AnalyticsEngine, Artifacts_d_exports as Artifacts, Binding_d_exports as Binding, BrowserRendering_d_exports as BrowserRendering, Cache_d_exports as Cache, CloudflareOtlp_d_exports as CloudflareOtlp, CloudflareTracer_d_exports as CloudflareTracer, ContainerNamespace_d_exports as ContainerNamespace, D1_d_exports as D1, DurableObject_d_exports as DurableObject, DurableObjectAlarm_d_exports as DurableObjectAlarm, DurableObjectDefinition_d_exports as DurableObjectDefinition, DurableObjectNamespace_d_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_d_exports as DurableObjectRpcWebSocket, DurableObjectSqlite_d_exports as DurableObjectSqlite, DurableObjectState_d_exports as DurableObjectState, DurableObjectStorage_d_exports as DurableObjectStorage, DurableObjectWebSocket_d_exports as DurableObjectWebSocket, Email_d_exports as Email, Environment_d_exports as Environment, Hyperdrive_d_exports as Hyperdrive, Images_d_exports as Images, Kv_d_exports as Kv, Queue_d_exports as Queue, QueueBinding_d_exports as QueueBinding, QueueDefinition_d_exports as QueueDefinition, R2_d_exports as R2, Rpc_d_exports as Rpc, RpcDefinition_d_exports as RpcDefinition, RpcTargets_d_exports as RpcTargets, RpcTracing_d_exports as RpcTracing, ServiceBinding_d_exports as ServiceBinding, Vectorize_d_exports as Vectorize, WebTransport_d_exports as WebTransport, Worker_d_exports as Worker, WorkerConfig, WorkerDefinition_d_exports as WorkerDefinition, type WorkerEnv, WorkerEnvironment, WorkersAi_d_exports as WorkersAi, Workflow_d_exports as Workflow, WorkflowBinding_d_exports as WorkflowBinding, WorkflowDefinition_d_exports as WorkflowDefinition };
|
package/dist/index.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import { QueueBinding_exports } from "./QueueBinding.mjs";
|
|
|
17
17
|
import { QueueDefinition_exports } from "./QueueDefinition.mjs";
|
|
18
18
|
import { Queue_exports } from "./Queue.mjs";
|
|
19
19
|
import { RpcDefinition_exports } from "./RpcDefinition.mjs";
|
|
20
|
+
import { RpcTargets_exports } from "./RpcTargets.mjs";
|
|
20
21
|
import { RpcTracing_exports } from "./RpcTracing.mjs";
|
|
21
22
|
import { Rpc_exports } from "./Rpc.mjs";
|
|
22
23
|
import { ServiceBinding_exports } from "./ServiceBinding.mjs";
|
|
@@ -38,4 +39,4 @@ import { WebTransport_exports } from "./WebTransport.mjs";
|
|
|
38
39
|
import { WorkflowBinding_exports } from "./WorkflowBinding.mjs";
|
|
39
40
|
import { WorkflowDefinition_exports } from "./WorkflowDefinition.mjs";
|
|
40
41
|
import { Workflow_exports } from "./Workflow.mjs";
|
|
41
|
-
export { AiGateway_exports as AiGateway, AnalyticsEngine_exports as AnalyticsEngine, Artifacts_exports as Artifacts, Binding_exports as Binding, BrowserRendering_exports as BrowserRendering, Cache_exports as Cache, CloudflareOtlp_exports as CloudflareOtlp, CloudflareTracer_exports as CloudflareTracer, ContainerNamespace_exports as ContainerNamespace, D1_exports as D1, DurableObject_exports as DurableObject, DurableObjectAlarm_exports as DurableObjectAlarm, DurableObjectDefinition_exports as DurableObjectDefinition, DurableObjectNamespace_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_exports as DurableObjectRpcWebSocket, DurableObjectSqlite_exports as DurableObjectSqlite, DurableObjectState_exports as DurableObjectState, DurableObjectStorage_exports as DurableObjectStorage, DurableObjectWebSocket_exports as DurableObjectWebSocket, Email_exports as Email, Environment_exports as Environment, Hyperdrive_exports as Hyperdrive, Images_exports as Images, Kv_exports as Kv, Queue_exports as Queue, QueueBinding_exports as QueueBinding, QueueDefinition_exports as QueueDefinition, R2_exports as R2, Rpc_exports as Rpc, RpcDefinition_exports as RpcDefinition, RpcTracing_exports as RpcTracing, ServiceBinding_exports as ServiceBinding, Vectorize_exports as Vectorize, WebTransport_exports as WebTransport, Worker_exports as Worker, WorkerConfig, WorkerDefinition_exports as WorkerDefinition, WorkerEnvironment, WorkersAi_exports as WorkersAi, Workflow_exports as Workflow, WorkflowBinding_exports as WorkflowBinding, WorkflowDefinition_exports as WorkflowDefinition };
|
|
42
|
+
export { AiGateway_exports as AiGateway, AnalyticsEngine_exports as AnalyticsEngine, Artifacts_exports as Artifacts, Binding_exports as Binding, BrowserRendering_exports as BrowserRendering, Cache_exports as Cache, CloudflareOtlp_exports as CloudflareOtlp, CloudflareTracer_exports as CloudflareTracer, ContainerNamespace_exports as ContainerNamespace, D1_exports as D1, DurableObject_exports as DurableObject, DurableObjectAlarm_exports as DurableObjectAlarm, DurableObjectDefinition_exports as DurableObjectDefinition, DurableObjectNamespace_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_exports as DurableObjectRpcWebSocket, DurableObjectSqlite_exports as DurableObjectSqlite, DurableObjectState_exports as DurableObjectState, DurableObjectStorage_exports as DurableObjectStorage, DurableObjectWebSocket_exports as DurableObjectWebSocket, Email_exports as Email, Environment_exports as Environment, Hyperdrive_exports as Hyperdrive, Images_exports as Images, Kv_exports as Kv, Queue_exports as Queue, QueueBinding_exports as QueueBinding, QueueDefinition_exports as QueueDefinition, R2_exports as R2, Rpc_exports as Rpc, RpcDefinition_exports as RpcDefinition, RpcTargets_exports as RpcTargets, RpcTracing_exports as RpcTracing, ServiceBinding_exports as ServiceBinding, Vectorize_exports as Vectorize, WebTransport_exports as WebTransport, Worker_exports as Worker, WorkerConfig, WorkerDefinition_exports as WorkerDefinition, WorkerEnvironment, WorkersAi_exports as WorkersAi, Workflow_exports as Workflow, WorkflowBinding_exports as WorkflowBinding, WorkflowDefinition_exports as WorkflowDefinition };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WorkerConfig, WorkerEnvironment } from "../Environment.mjs";
|
|
2
|
+
import { withScope } from "../RpcTargets.mjs";
|
|
2
3
|
import { provideEntrypointServices } from "./Entrypoint.mjs";
|
|
3
4
|
import * as Effect from "effect/Effect";
|
|
4
5
|
import * as Layer from "effect/Layer";
|
|
@@ -21,10 +22,10 @@ const makeEntrypointRuntime = (layer, env, services) => {
|
|
|
21
22
|
function runEventPromise(...args) {
|
|
22
23
|
const [runtime, effect, eventLayer, parent] = args;
|
|
23
24
|
if (eventLayer === void 0) {
|
|
24
|
-
const event = Effect.scoped(effect);
|
|
25
|
+
const event = Effect.scoped(withScope(effect));
|
|
25
26
|
return runtime.runPromise(parent === void 0 ? event : Effect.withParentSpan(event, parent));
|
|
26
27
|
}
|
|
27
|
-
const event = Effect.scoped(effect.pipe(Effect.provide(eventLayer, { local: true })));
|
|
28
|
+
const event = Effect.scoped(withScope(effect.pipe(Effect.provide(eventLayer, { local: true }))));
|
|
28
29
|
return runtime.runPromise(parent === void 0 ? event : Effect.withParentSpan(event, parent));
|
|
29
30
|
}
|
|
30
31
|
//#endregion
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ import * as RpcDefinition from "./RpcDefinition";
|
|
|
11
11
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
12
12
|
import * as RpcInvocation from "./internal/RpcInvocation";
|
|
13
13
|
import * as RpcTracing from "./RpcTracing";
|
|
14
|
+
import * as RpcTargets from "./RpcTargets";
|
|
14
15
|
|
|
15
16
|
const expectedDurableObjectNamespace =
|
|
16
17
|
"Durable Object namespace binding with getByName(), get(), idFromName(), idFromString(), newUniqueId(), and jurisdiction()";
|
|
@@ -348,12 +349,18 @@ export const makeClient = <
|
|
|
348
349
|
const get = (
|
|
349
350
|
id: globalThis.DurableObjectId,
|
|
350
351
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
351
|
-
) =>
|
|
352
|
+
) =>
|
|
353
|
+
RpcTargets.get(namespace, JSON.stringify(["id", id.toString(), options]), () =>
|
|
354
|
+
namespace.get(id, options),
|
|
355
|
+
).pipe(Effect.orDie);
|
|
352
356
|
|
|
353
357
|
const getByName = (
|
|
354
358
|
name: string,
|
|
355
359
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
356
|
-
) =>
|
|
360
|
+
) =>
|
|
361
|
+
RpcTargets.get(namespace, JSON.stringify(["name", name, options]), () =>
|
|
362
|
+
namespace.getByName(name, options),
|
|
363
|
+
).pipe(Effect.orDie);
|
|
357
364
|
|
|
358
365
|
const jurisdiction = (value: globalThis.DurableObjectJurisdiction) =>
|
|
359
366
|
Effect.sync(() => namespace.jurisdiction(value));
|
|
@@ -377,7 +384,7 @@ export const makeClient = <
|
|
|
377
384
|
});
|
|
378
385
|
},
|
|
379
386
|
catch: (cause) => new DurableObjectFetchError({ binding: definition.binding, cause }),
|
|
380
|
-
});
|
|
387
|
+
}).pipe(Effect.tapCause(() => RpcTargets.invalidate(stub)));
|
|
381
388
|
|
|
382
389
|
const rpc = Effect.fnUntraced(function* <Method extends StubMethodKey<Api>>(
|
|
383
390
|
stub: StubClient,
|
|
@@ -419,7 +426,7 @@ export const makeClient = <
|
|
|
419
426
|
method: methodName,
|
|
420
427
|
cause,
|
|
421
428
|
}),
|
|
422
|
-
);
|
|
429
|
+
).pipe(Effect.tapCause(() => RpcTargets.invalidate(stub)));
|
|
423
430
|
});
|
|
424
431
|
|
|
425
432
|
const decodeSuccess = Effect.fnUntraced(function* <Method extends StubMethodKey<Api>>(
|
|
@@ -459,6 +466,7 @@ export const makeClient = <
|
|
|
459
466
|
): Effect.fn.Return<StubMethodSuccess<Api, Method>, DurableObjectRpcError> {
|
|
460
467
|
const methodName = String(method);
|
|
461
468
|
const value = yield* CloudflareRpc.resolve(yield* rpc(stub, method, ...args)).pipe(
|
|
469
|
+
Effect.tapCause(() => RpcTargets.invalidate(stub)),
|
|
462
470
|
Effect.mapError(
|
|
463
471
|
(cause) =>
|
|
464
472
|
new DurableObjectRpcError({
|
|
@@ -484,6 +492,7 @@ export const makeClient = <
|
|
|
484
492
|
const methodName = String(method);
|
|
485
493
|
const result = yield* rpc(stub, method, ...args);
|
|
486
494
|
const value = yield* CloudflareRpc.scoped(result).pipe(
|
|
495
|
+
Effect.tapCause(() => RpcTargets.invalidate(stub)),
|
|
487
496
|
Effect.mapError(
|
|
488
497
|
(cause) =>
|
|
489
498
|
new DurableObjectRpcError({
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
2
|
+
import * as Context from "effect/Context";
|
|
2
3
|
import * as Effect from "effect/Effect";
|
|
3
4
|
import * as Layer from "effect/Layer";
|
|
4
|
-
import
|
|
5
|
+
import * as Scheduler from "effect/Scheduler";
|
|
6
|
+
import * as Reactivity from "effect/unstable/reactivity/Reactivity";
|
|
7
|
+
import { SqlClient } from "effect/unstable/sql";
|
|
5
8
|
|
|
6
9
|
import { DurableObjectState } from "./DurableObjectState";
|
|
7
10
|
|
|
@@ -10,10 +13,22 @@ export type SqliteLayerOptions = Omit<SqliteClient.SqliteClientConfig, "db" | "s
|
|
|
10
13
|
export const layer = (
|
|
11
14
|
options?: SqliteLayerOptions,
|
|
12
15
|
): Layer.Layer<SqliteClient.SqliteClient | SqlClient.SqlClient, never, DurableObjectState> =>
|
|
13
|
-
Layer.
|
|
16
|
+
Layer.effectContext(
|
|
14
17
|
Effect.gen(function* () {
|
|
15
18
|
const state = yield* DurableObjectState;
|
|
19
|
+
const client = yield* SqliteClient.make({ ...options, storage: state.raw.storage });
|
|
20
|
+
const original = client.withTransaction;
|
|
21
|
+
const scheduler = new Scheduler.MixedScheduler("sync");
|
|
22
|
+
const withTransaction: SqliteClient.SqliteClient["withTransaction"] = (body) =>
|
|
23
|
+
original(body).pipe(Effect.provideService(Scheduler.Scheduler, scheduler));
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
// Native timers retain their input gate. A blocked parent timer can prevent
|
|
26
|
+
// a transaction's later timer from running, so yield through microtasks until
|
|
27
|
+
// the native transaction settles. Keep the original client and SQL permit.
|
|
28
|
+
Object.assign(client, { withTransaction });
|
|
29
|
+
|
|
30
|
+
return Context.make(SqliteClient.SqliteClient, client).pipe(
|
|
31
|
+
Context.add(SqlClient.SqlClient, client),
|
|
32
|
+
);
|
|
18
33
|
}),
|
|
19
|
-
);
|
|
34
|
+
).pipe(Layer.provide(Reactivity.layer));
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as Context from "effect/Context";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Data from "effect/Data";
|
|
4
|
+
import type * as Scope from "effect/Scope";
|
|
5
|
+
import * as Option from "effect/Option";
|
|
6
|
+
|
|
7
|
+
/** A native RPC target could not be constructed. */
|
|
8
|
+
export class RpcTargetError extends Data.TaggedError("RpcTargetError")<{
|
|
9
|
+
readonly cause: unknown;
|
|
10
|
+
}> {}
|
|
11
|
+
|
|
12
|
+
interface Targets {
|
|
13
|
+
get<A extends object, Owner extends object>(owner: Owner, address: string, create: () => A): A;
|
|
14
|
+
invalidate<Target extends object>(target: Target): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class CurrentTargets extends Context.Service<CurrentTargets, Targets>()("effect-cf/RpcTargets") {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Reuse a native RPC target within the current invocation. Native Durable Object
|
|
21
|
+
* stubs capture the calling request's channel when created. Recreating a stub
|
|
22
|
+
* after a callback can extend that callback's call chain until Cloudflare's
|
|
23
|
+
* subrequest depth limit is reached, even when an alarm owns the work.
|
|
24
|
+
*
|
|
25
|
+
* The owner and address must identify one target and its construction options.
|
|
26
|
+
* Outside an effect-cf invocation (or withScope), each lookup constructs a target.
|
|
27
|
+
*/
|
|
28
|
+
export const get = <A extends object, Owner extends object>(
|
|
29
|
+
owner: Owner,
|
|
30
|
+
address: string,
|
|
31
|
+
create: () => A,
|
|
32
|
+
) =>
|
|
33
|
+
Effect.flatMap(Effect.serviceOption(CurrentTargets), (targets) =>
|
|
34
|
+
Effect.try({
|
|
35
|
+
try: () => (Option.isSome(targets) ? targets.value.get(owner, address, create) : create()),
|
|
36
|
+
catch: (cause) => new RpcTargetError({ cause }),
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/** Discard a failed native target so a subsequent call can acquire a fresh channel. */
|
|
41
|
+
export const invalidate = <Target extends object>(target: Target): Effect.Effect<void> =>
|
|
42
|
+
Effect.map(Effect.serviceOption(CurrentTargets), (targets) => {
|
|
43
|
+
if (Option.isSome(targets)) targets.value.invalidate(target);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Own RPC targets in the current Scope, including a transferred response stream,
|
|
48
|
+
* never across incoming requests or durable retries. effect-cf entrypoints install this boundary automatically.
|
|
49
|
+
*/
|
|
50
|
+
export const withScope = <A, E, R>(
|
|
51
|
+
effect: Effect.Effect<A, E, R>,
|
|
52
|
+
): Effect.Effect<A, E, R | Scope.Scope> =>
|
|
53
|
+
Effect.gen(function* () {
|
|
54
|
+
let active = true;
|
|
55
|
+
let owners = new WeakMap<object, Map<string, object>>();
|
|
56
|
+
let addresses = new WeakMap<object, { entries: Map<string, object>; address: string }>();
|
|
57
|
+
const targets: Targets = {
|
|
58
|
+
get: <T extends object, Owner extends object>(
|
|
59
|
+
owner: Owner,
|
|
60
|
+
address: string,
|
|
61
|
+
create: () => T,
|
|
62
|
+
): T => {
|
|
63
|
+
if (!active) return create();
|
|
64
|
+
let entries = owners.get(owner);
|
|
65
|
+
|
|
66
|
+
if (entries === undefined) {
|
|
67
|
+
entries = new Map();
|
|
68
|
+
owners.set(owner, entries);
|
|
69
|
+
}
|
|
70
|
+
const existing = entries.get(address);
|
|
71
|
+
|
|
72
|
+
if (existing !== undefined) {
|
|
73
|
+
// SAFETY: the caller's owner/address identifies the same native target type.
|
|
74
|
+
return existing as T;
|
|
75
|
+
}
|
|
76
|
+
const target = create();
|
|
77
|
+
|
|
78
|
+
entries.set(address, target);
|
|
79
|
+
addresses.set(target, { entries, address });
|
|
80
|
+
|
|
81
|
+
return target;
|
|
82
|
+
},
|
|
83
|
+
invalidate: (target) => {
|
|
84
|
+
const entry = addresses.get(target);
|
|
85
|
+
|
|
86
|
+
if (entry?.entries.get(entry.address) === target) entry.entries.delete(entry.address);
|
|
87
|
+
addresses.delete(target);
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
yield* Effect.addFinalizer(() =>
|
|
92
|
+
Effect.sync(() => {
|
|
93
|
+
active = false;
|
|
94
|
+
owners = new WeakMap();
|
|
95
|
+
addresses = new WeakMap();
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return yield* effect.pipe(Effect.provideService(CurrentTargets, targets));
|
|
100
|
+
});
|
package/src/Worker.ts
CHANGED
|
@@ -13,6 +13,7 @@ import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
|
|
|
13
13
|
import { WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
14
14
|
import { fromMessage, fromMessageBatch, type QueueHandler } from "./Queue";
|
|
15
15
|
import * as RpcDefinition from "./RpcDefinition";
|
|
16
|
+
import * as RpcTargets from "./RpcTargets";
|
|
16
17
|
import type { ReceiverOptions, RpcInvocationInfo } from "./RpcTracing";
|
|
17
18
|
import * as Entrypoint from "./internal/Entrypoint";
|
|
18
19
|
import * as Runtime from "./internal/Runtime";
|
|
@@ -273,11 +274,13 @@ const renderFetchSuccess = <E, R, REvent, EventLayerError, EventLayerRequirement
|
|
|
273
274
|
});
|
|
274
275
|
});
|
|
275
276
|
const telemetryMiddleware = HttpMiddleware.make((self) =>
|
|
276
|
-
|
|
277
|
-
|
|
277
|
+
RpcTargets.withScope(
|
|
278
|
+
Effect.gen(function* () {
|
|
279
|
+
yield* Effect.addFinalizer(() => scheduleTelemetryFlush);
|
|
278
280
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
+
return yield* self;
|
|
282
|
+
}),
|
|
283
|
+
),
|
|
281
284
|
);
|
|
282
285
|
const handled =
|
|
283
286
|
eventLayer === undefined
|
|
@@ -287,24 +290,26 @@ const renderFetchSuccess = <E, R, REvent, EventLayerError, EventLayerRequirement
|
|
|
287
290
|
httpApp,
|
|
288
291
|
handleResponse,
|
|
289
292
|
HttpMiddleware.make((self) =>
|
|
290
|
-
|
|
291
|
-
Effect.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
Effect.
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
293
|
+
RpcTargets.withScope(
|
|
294
|
+
Effect.provideService(
|
|
295
|
+
Effect.gen(function* () {
|
|
296
|
+
const context = yield* Layer.build(Layer.fresh(eventLayer));
|
|
297
|
+
|
|
298
|
+
yield* Effect.addFinalizer(() =>
|
|
299
|
+
Effect.provideContext(scheduleTelemetryFlush, context),
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
return yield* HttpMiddleware.tracer(self).pipe(
|
|
303
|
+
// The tracer schedules span completion. Let it publish on
|
|
304
|
+
// every exit with event references still installed, before
|
|
305
|
+
// the exporter scope finalizes.
|
|
306
|
+
Effect.onExit(() => Effect.yieldNow),
|
|
307
|
+
Effect.provideContext(context),
|
|
308
|
+
);
|
|
309
|
+
}),
|
|
310
|
+
References.TracerEnabled,
|
|
311
|
+
tracerEnabled,
|
|
312
|
+
),
|
|
308
313
|
),
|
|
309
314
|
),
|
|
310
315
|
).pipe(Effect.withTracerEnabled(false)),
|
package/src/Workflow.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as RpcTargets from "./RpcTargets";
|
|
1
2
|
import {
|
|
2
3
|
WorkflowEntrypoint as CloudflareWorkflowEntrypoint,
|
|
3
4
|
type WorkflowEvent as CloudflareWorkflowEvent,
|
|
@@ -151,7 +152,11 @@ const fromWorkflowStep = (step: CloudflareWorkflowStep): WorkflowStepService =>
|
|
|
151
152
|
A,
|
|
152
153
|
E,
|
|
153
154
|
Exclude<R, WorkflowStepContext>
|
|
154
|
-
> = Effect.scoped(
|
|
155
|
+
> = Effect.scoped(
|
|
156
|
+
RpcTargets.withScope(
|
|
157
|
+
Effect.provideService(effect, WorkflowStepContext, stepContext),
|
|
158
|
+
),
|
|
159
|
+
);
|
|
155
160
|
|
|
156
161
|
return runPromise(
|
|
157
162
|
exposeCloudflareNonRetryableError(Effect.provideContext(stepEffect, context)),
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,7 @@ export * as R2 from "./R2";
|
|
|
29
29
|
export * as Rpc from "./Rpc";
|
|
30
30
|
export * as RpcDefinition from "./RpcDefinition";
|
|
31
31
|
export * as RpcTracing from "./RpcTracing";
|
|
32
|
+
export * as RpcTargets from "./RpcTargets";
|
|
32
33
|
export * as ServiceBinding from "./ServiceBinding";
|
|
33
34
|
export * as Vectorize from "./Vectorize";
|
|
34
35
|
export * as WebTransport from "./WebTransport";
|
package/src/internal/Runtime.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as ManagedRuntime from "effect/ManagedRuntime";
|
|
|
5
5
|
import type { Scope, Tracer } from "effect";
|
|
6
6
|
|
|
7
7
|
import { WorkerConfig, WorkerEnvironment, type WorkerEnv } from "../Environment";
|
|
8
|
+
import * as RpcTargets from "../RpcTargets";
|
|
8
9
|
import { provideEntrypointServices } from "./Entrypoint";
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -61,12 +62,14 @@ export function runEventPromise<A, E, R, REvent, EventLayerError, LayerError>(
|
|
|
61
62
|
const [runtime, effect, eventLayer, parent] = args;
|
|
62
63
|
|
|
63
64
|
if (eventLayer === undefined) {
|
|
64
|
-
const event = Effect.scoped(effect);
|
|
65
|
+
const event = Effect.scoped(RpcTargets.withScope(effect));
|
|
65
66
|
|
|
66
67
|
return runtime.runPromise(parent === undefined ? event : Effect.withParentSpan(event, parent));
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
const event = Effect.scoped(
|
|
70
|
+
const event = Effect.scoped(
|
|
71
|
+
RpcTargets.withScope(effect.pipe(Effect.provide(eventLayer, { local: true }))),
|
|
72
|
+
);
|
|
70
73
|
|
|
71
74
|
return runtime.runPromise(parent === undefined ? event : Effect.withParentSpan(event, parent));
|
|
72
75
|
}
|