effect-cf 0.36.0 → 0.38.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 +14 -0
- package/README.md +47 -0
- package/dist/ComputerWorkspace.mjs +1 -1
- package/dist/{DurableObjectState-DCh4PZMN.mjs → DurableObjectState-DLL0YgBd.mjs} +1 -1
- package/dist/Vitest.mjs +1 -1
- package/dist/index.d.mts +50 -15
- package/dist/index.mjs +116 -46
- package/package.json +2 -1
- package/src/CloudflareTracer.ts +92 -0
- package/src/DurableObjectAlarm.ts +80 -30
- package/src/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# effect-cf
|
|
2
2
|
|
|
3
|
+
## 0.38.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#137](https://github.com/danieljvdm/effect-cf/pull/137) [`8e35961`](https://github.com/danieljvdm/effect-cf/commit/8e3596157732b487f8fef5fd983a6c56a32e74ec) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add `CloudflareTracer.layer` to send existing Effect spans to Cloudflare Workers Observability. Provide it per invocation through `Worker.make`'s `eventLayer` and enable tracing in Wrangler to see Effect operations alongside automatic platform spans, with context preserved across concurrent fibers.
|
|
8
|
+
|
|
9
|
+
## 0.37.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#135](https://github.com/danieljvdm/effect-cf/pull/135) [`9dea62e`](https://github.com/danieljvdm/effect-cf/commit/9dea62e74818b7fc9da919e8bdbfcc49991aef36) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add `DurableObjectAlarm.transaction` to commit application storage and logical alarm schedule, replacement, or cancellation together in one native SQLite Durable Object transaction. Application queries can use the existing storage wrapper or a `SqlClient` from `@effect/sql-sqlite-do` backed by the same object. The callback receives transaction-only alarm mutations and preserves the caller's success value, typed errors, and service requirements.
|
|
14
|
+
|
|
15
|
+
Failures before commit roll back application rows, logical alarms, and native alarm reconciliation together. Interruption or a lost reply after commit does not undo committed state. Keep external effects outside the transaction and durably pre-arm a later wake before fallible external work; Cloudflare's native alarm retries remain bounded.
|
|
16
|
+
|
|
3
17
|
## 0.36.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -47,6 +47,53 @@ Declare `SETTINGS` in `wrangler.jsonc` and pass `SettingsLive` to `Worker.make`.
|
|
|
47
47
|
|
|
48
48
|
The [counter example](https://github.com/danieljvdm/effect-cf/tree/main/examples/counter) shows `DurableObject.Tag`, storage, a typed RPC call, and the complete Wrangler configuration.
|
|
49
49
|
|
|
50
|
+
For atomic application writes and alarm changes, see the [alarm transaction example](tests/fixtures/alarm-transaction-consumer.ts) and [API contract](src/DurableObjectAlarm.ts).
|
|
51
|
+
|
|
52
|
+
## Cloudflare Observability traces
|
|
53
|
+
|
|
54
|
+
`CloudflareTracer.layer` sends existing `Effect.withSpan` and named `Effect.fn`
|
|
55
|
+
spans to Cloudflare's trace waterfall, alongside automatic platform spans.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { Effect, Layer } from "effect";
|
|
59
|
+
import { CloudflareTracer, Worker } from "effect-cf";
|
|
60
|
+
|
|
61
|
+
export default Worker.make(Layer.empty, {
|
|
62
|
+
eventLayer: CloudflareTracer.layer,
|
|
63
|
+
fetch: Effect.sync(() => new Response("Hello")).pipe(Effect.withSpan("greet")),
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Enable tracing in `wrangler.jsonc`:
|
|
68
|
+
|
|
69
|
+
```jsonc
|
|
70
|
+
{
|
|
71
|
+
"compatibility_date": "2026-08-25",
|
|
72
|
+
"observability": {
|
|
73
|
+
"traces": { "enabled": true },
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Build the layer per invocation with `eventLayer`. It captures the current
|
|
79
|
+
Cloudflare async context, so do not put it in a runtime layer cached across
|
|
80
|
+
requests. Standalone Effect programs can provide it around each invocation.
|
|
81
|
+
Nested spans, concurrent fibers, and resumed work restore the appropriate span
|
|
82
|
+
context. Cloudflare handles sampling and export; no exporter endpoint or flush
|
|
83
|
+
is needed.
|
|
84
|
+
|
|
85
|
+
String, number, and boolean attributes are forwarded. Other attributes, span
|
|
86
|
+
events, and links remain Effect-local. Completion is recorded as `effect.exit`
|
|
87
|
+
with `success`, `failure`, or `interrupted`; Cloudflare does not expose a setter
|
|
88
|
+
for native outcome status. Effect IDs remain separate from Cloudflare's opaque
|
|
89
|
+
trace/span IDs. Explicit external parents cannot join a Cloudflare trace by ID,
|
|
90
|
+
and `root: true` starts under the invocation's captured context.
|
|
91
|
+
|
|
92
|
+
This layer replaces the active Effect tracer. When combining it with
|
|
93
|
+
`CloudflareOtlp`, select only `logs` and/or `metrics` in the OTLP layer. See
|
|
94
|
+
[Cloudflare's custom span API](https://developers.cloudflare.com/workers/observability/traces/custom-spans/)
|
|
95
|
+
for platform limitations.
|
|
96
|
+
|
|
50
97
|
## Native RPC tracing
|
|
51
98
|
|
|
52
99
|
`call()`, `scopedCall()`, and definition methods create one CLIENT span named `binding/method`, covering argument encoding, the native RPC wait, and success decoding. Raw `rpc()` retains Cloudflare's pipelined result without creating a span. Wrap its complete lifetime with `RpcTracing.withRpcClientSpan` when tracing raw calls.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as DurableObjectState } from "./DurableObjectState-
|
|
1
|
+
import { t as DurableObjectState } from "./DurableObjectState-DLL0YgBd.mjs";
|
|
2
2
|
import { fromClient } from "./ComputerArtifacts.mjs";
|
|
3
3
|
import { t as lookup } from "./ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs";
|
|
4
4
|
import { Context, Effect, Layer, Predicate, Schema, Stream } from "effect";
|
|
@@ -288,4 +288,4 @@ const runExitPreservingTypedFailures = async (run, effect) => {
|
|
|
288
288
|
return exit;
|
|
289
289
|
};
|
|
290
290
|
//#endregion
|
|
291
|
-
export { DurableWebSocketAttachmentError as a, DurableObjectWebSocket_exports as i, DurableObjectState_exports as n, fromWebSocket as o, fromDurableObjectState as r, DurableObjectStorage_exports as s, DurableObjectState as t };
|
|
291
|
+
export { DurableWebSocketAttachmentError as a, StorageOperationError as c, DurableObjectWebSocket_exports as i, DurableObjectState_exports as n, fromWebSocket as o, fromDurableObjectState as r, DurableObjectStorage_exports as s, DurableObjectState as t };
|
package/dist/Vitest.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as WorkerEnvironment, i as WorkerConfig } from "./ErrorMessage-Byx2OgNd.mjs";
|
|
2
2
|
import { r as runNativeCallback } from "./WorkerContext-Yobnfw-K.mjs";
|
|
3
|
-
import { r as fromDurableObjectState, t as DurableObjectState } from "./DurableObjectState-
|
|
3
|
+
import { r as fromDurableObjectState, t as DurableObjectState } from "./DurableObjectState-DLL0YgBd.mjs";
|
|
4
4
|
import { ConfigProvider, Effect, Exit, Layer } from "effect";
|
|
5
5
|
import { env } from "cloudflare:workers";
|
|
6
6
|
import { abortAllDurableObjects as abortAllDurableObjects$1, adminSecretsStore as adminSecretsStore$1, applyD1Migrations as applyD1Migrations$1, createExecutionContext, createMessageBatch, createPagesEventContext, createScheduledController, evictAllDurableObjects as evictAllDurableObjects$1, evictDurableObject as evictDurableObject$1, getQueueResult, introspectWorkflow as introspectWorkflow$1, introspectWorkflowInstance as introspectWorkflowInstance$1, listDurableObjectIds as listDurableObjectIds$1, reset as reset$1, runDurableObjectAlarm as runDurableObjectAlarm$1, runInDurableObject as runInDurableObject$1, waitOnExecutionContext } from "cloudflare:test";
|
package/dist/index.d.mts
CHANGED
|
@@ -8,8 +8,8 @@ import { a as WorkflowInstanceCreateOptions, i as WorkflowInstanceCreateBatchOpt
|
|
|
8
8
|
import { Cause, Config, Context, Data, DateTime, Duration, Effect, Layer, Option, Predicate, Redacted, Schema, Scope } from "effect";
|
|
9
9
|
import { Headers as Headers$1, HttpClient, HttpClientResponse } from "effect/unstable/http";
|
|
10
10
|
import { OtlpExporter, OtlpResource } from "effect/unstable/observability";
|
|
11
|
-
import { D1Client } from "@effect/sql-d1";
|
|
12
11
|
import { DurableObject, WorkflowEntrypoint, WorkflowEvent, WorkflowSleepDuration, WorkflowStep, WorkflowStepConfig, WorkflowStepContext, WorkflowStepEvent, WorkflowTimeoutDuration } from "cloudflare:workers";
|
|
12
|
+
import { D1Client } from "@effect/sql-d1";
|
|
13
13
|
import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
|
|
14
14
|
import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
|
|
15
15
|
import * as RpcServer from "effect/unstable/rpc/RpcServer";
|
|
@@ -17,7 +17,7 @@ import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
|
17
17
|
import { SqlClient } from "effect/unstable/sql";
|
|
18
18
|
import * as Tracer$1 from "effect/Tracer";
|
|
19
19
|
declare namespace WorkersAi_d_exports {
|
|
20
|
-
export { LayerOptions$13 as LayerOptions, Tag$12 as Tag, TagClass$11 as TagClass, WorkersAiAsyncBatchResponse, WorkersAiBinding, WorkersAiClient, WorkersAiDefinition, WorkersAiEmbeddingInput, WorkersAiEmbeddingResponse, WorkersAiModelsSearchObject, WorkersAiModelsSearchParams, WorkersAiOperationError, WorkersAiOptions, WorkersAiService, embeddingResponse, isWorkersAiBinding, layer$
|
|
20
|
+
export { LayerOptions$13 as LayerOptions, Tag$12 as Tag, TagClass$11 as TagClass, WorkersAiAsyncBatchResponse, WorkersAiBinding, WorkersAiClient, WorkersAiDefinition, WorkersAiEmbeddingInput, WorkersAiEmbeddingResponse, WorkersAiModelsSearchObject, WorkersAiModelsSearchParams, WorkersAiOperationError, WorkersAiOptions, WorkersAiService, embeddingResponse, isWorkersAiBinding, layer$14 as layer, make$12 as make, makeClient$10 as makeClient };
|
|
21
21
|
}
|
|
22
22
|
declare const WorkersAiOperationError_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 & {
|
|
23
23
|
readonly _tag: "WorkersAiOperationError";
|
|
@@ -89,11 +89,11 @@ declare const embeddingResponse: (value: {
|
|
|
89
89
|
readonly [embeddingDimensionsKey]?: ReadonlyArray<number>;
|
|
90
90
|
}) => WorkersAiEmbeddingResponse;
|
|
91
91
|
declare const makeClient$10: <ModelList extends AiModelListType = AiModels>(definition: WorkersAiDefinition) => (ai: WorkersAiBinding<ModelList>) => WorkersAiClient<ModelList>;
|
|
92
|
-
declare const layer$
|
|
92
|
+
declare const layer$14: <Self, ModelList extends AiModelListType = AiModels>(tag: Context.Service<Self, WorkersAiClient<ModelList>>, definition: WorkersAiDefinition) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
93
93
|
declare const make$12: <Id extends string>(id: Id) => TagClass$11<WorkersAiService<Id>, Id, AiModels>;
|
|
94
94
|
declare const Tag$12: <Self>() => <Id extends string, ModelList extends AiModelListType = AiModels>(id: Id) => TagClass$11<Self, Id, ModelList>;
|
|
95
95
|
declare namespace AiGateway_d_exports {
|
|
96
|
-
export { AiGatewayBinding, AiGatewayClient, AiGatewayDefinition, AiGatewayFetchOptions, AiGatewayHeaders, AiGatewayLog, AiGatewayOperationError, AiGatewayPatchLog, AiGatewayProvider, AiGatewayRunOptions, AiGatewayService, AiGatewayUniversalRequest, LayerOptions$12 as LayerOptions, Tag$11 as Tag, TagClass$10 as TagClass, isAiGatewayBinding, layer$
|
|
96
|
+
export { AiGatewayBinding, AiGatewayClient, AiGatewayDefinition, AiGatewayFetchOptions, AiGatewayHeaders, AiGatewayLog, AiGatewayOperationError, AiGatewayPatchLog, AiGatewayProvider, AiGatewayRunOptions, AiGatewayService, AiGatewayUniversalRequest, LayerOptions$12 as LayerOptions, Tag$11 as Tag, TagClass$10 as TagClass, isAiGatewayBinding, layer$13 as layer, make$11 as make, makeClient$9 as makeClient, makeClientFromAi, makeHttpClient };
|
|
97
97
|
}
|
|
98
98
|
declare const AiGatewayOperationError_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 & {
|
|
99
99
|
readonly _tag: "AiGatewayOperationError";
|
|
@@ -167,11 +167,11 @@ declare const makeHttpClient: (definition: Omit<AiGatewayDefinition, "binding">
|
|
|
167
167
|
readonly accountId: string;
|
|
168
168
|
readonly binding?: string;
|
|
169
169
|
}, request?: typeof fetch) => AiGatewayClient;
|
|
170
|
-
declare const layer$
|
|
170
|
+
declare const layer$13: <Self>(tag: Context.Service<Self, AiGatewayClient>, definition: AiGatewayDefinition) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
171
171
|
declare const make$11: <Id extends string>(id: Id) => TagClass$10<AiGatewayService<Id>, Id>;
|
|
172
172
|
declare const Tag$11: <Self>() => <Id extends string>(id: Id) => TagClass$10<Self, Id>;
|
|
173
173
|
declare namespace AnalyticsEngine_d_exports {
|
|
174
|
-
export { AnalyticsEngineBinding, AnalyticsEngineClient, AnalyticsEngineDataPoint, AnalyticsEngineDataPointSchema, AnalyticsEngineDefinition, AnalyticsEngineFieldValue, AnalyticsEngineFieldValueSchema, AnalyticsEngineInvalidWritePolicy, AnalyticsEngineOperationError, AnalyticsEngineQueryClient, AnalyticsEngineQueryColumn, AnalyticsEngineQueryDefinition, AnalyticsEngineQueryError, AnalyticsEngineQueryOptions, AnalyticsEngineQueryResult, AnalyticsEngineQueryRow, AnalyticsEngineQueryService, AnalyticsEngineService, AnalyticsEngineWriteError, AnalyticsEngineWriteOptions, AnalyticsEngineWritePolicy, AnalyticsEngineWriteValidationError, AnalyticsEngineWriteViolation, LayerOptions$11 as LayerOptions, QueryConfigOptions, QueryTag, QueryTagClass, Tag$10 as Tag, TagClass$9 as TagClass, isAnalyticsEngineDataset, layer$
|
|
174
|
+
export { AnalyticsEngineBinding, AnalyticsEngineClient, AnalyticsEngineDataPoint, AnalyticsEngineDataPointSchema, AnalyticsEngineDefinition, AnalyticsEngineFieldValue, AnalyticsEngineFieldValueSchema, AnalyticsEngineInvalidWritePolicy, AnalyticsEngineOperationError, AnalyticsEngineQueryClient, AnalyticsEngineQueryColumn, AnalyticsEngineQueryDefinition, AnalyticsEngineQueryError, AnalyticsEngineQueryOptions, AnalyticsEngineQueryResult, AnalyticsEngineQueryRow, AnalyticsEngineQueryService, AnalyticsEngineService, AnalyticsEngineWriteError, AnalyticsEngineWriteOptions, AnalyticsEngineWritePolicy, AnalyticsEngineWriteValidationError, AnalyticsEngineWriteViolation, LayerOptions$11 as LayerOptions, QueryConfigOptions, QueryTag, QueryTagClass, Tag$10 as Tag, TagClass$9 as TagClass, isAnalyticsEngineDataset, layer$12 as layer, layerFetch, layerFetchConfig, make$10 as make, makeClient$8 as makeClient, makeQuery, makeQueryClient, queryConfig, queryLayer, queryLayerConfig, writeLimits };
|
|
175
175
|
}
|
|
176
176
|
declare const writeLimits: {
|
|
177
177
|
readonly maxBlobs: 20;
|
|
@@ -322,13 +322,13 @@ declare const queryLayer: <Self>(tag: Context.Service<Self, AnalyticsEngineQuery
|
|
|
322
322
|
declare const layerFetch: <Self>(tag: Context.Service<Self, AnalyticsEngineQueryClient>, definition: AnalyticsEngineQueryDefinition) => Layer.Layer<Self, never, never>;
|
|
323
323
|
declare const queryLayerConfig: <Self>(tag: Context.Service<Self, AnalyticsEngineQueryClient>, config?: Config.Config<AnalyticsEngineQueryDefinition>) => Layer.Layer<Self, Config.ConfigError, HttpClient.HttpClient>;
|
|
324
324
|
declare const layerFetchConfig: <Self>(tag: Context.Service<Self, AnalyticsEngineQueryClient>, config?: Config.Config<AnalyticsEngineQueryDefinition>) => Layer.Layer<Self, Config.ConfigError, never>;
|
|
325
|
-
declare const layer$
|
|
325
|
+
declare const layer$12: <Self>(tag: Context.Service<Self, AnalyticsEngineClient>, definition: LayerOptions$11) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
326
326
|
declare const make$10: <Id extends string>(id: Id) => TagClass$9<AnalyticsEngineService<Id>, Id>;
|
|
327
327
|
declare const makeQuery: <Id extends string>(id: Id) => QueryTagClass<AnalyticsEngineQueryService<Id>, Id>;
|
|
328
328
|
declare const Tag$10: <Self>() => <Id extends string>(id: Id) => TagClass$9<Self, Id>;
|
|
329
329
|
declare const QueryTag: <Self>() => <Id extends string>(id: Id) => QueryTagClass<Self, Id>;
|
|
330
330
|
declare namespace BrowserRendering_d_exports {
|
|
331
|
-
export { BrowserRenderingBinding, BrowserRenderingBrowserClient, BrowserRenderingBrowserLike, BrowserRenderingClient, BrowserRenderingConnect, BrowserRenderingDefinition, BrowserRenderingExternalResult, BrowserRenderingLaunch, BrowserRenderingMethodOptions, BrowserRenderingOperationError, BrowserRenderingPageClient, BrowserRenderingPageFunction, BrowserRenderingPageLike, BrowserRenderingService, LayerOptions$10 as LayerOptions, Tag$9 as Tag, TagClass$8 as TagClass, isBrowserRenderingBinding, layer$
|
|
331
|
+
export { BrowserRenderingBinding, BrowserRenderingBrowserClient, BrowserRenderingBrowserLike, BrowserRenderingClient, BrowserRenderingConnect, BrowserRenderingDefinition, BrowserRenderingExternalResult, BrowserRenderingLaunch, BrowserRenderingMethodOptions, BrowserRenderingOperationError, BrowserRenderingPageClient, BrowserRenderingPageFunction, BrowserRenderingPageLike, BrowserRenderingService, LayerOptions$10 as LayerOptions, Tag$9 as Tag, TagClass$8 as TagClass, isBrowserRenderingBinding, layer$11 as layer, make$9 as make, makeClient$7 as makeClient };
|
|
332
332
|
}
|
|
333
333
|
declare const BrowserRenderingOperationError_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 & {
|
|
334
334
|
readonly _tag: "BrowserRenderingOperationError";
|
|
@@ -402,11 +402,11 @@ interface TagClass$8<Self, Id extends string> extends Context.ServiceClass<Self,
|
|
|
402
402
|
}
|
|
403
403
|
declare const isBrowserRenderingBinding: <Candidate>(value: Candidate) => value is Candidate & BrowserRenderingBinding;
|
|
404
404
|
declare const makeClient$7: <RawBinding extends BrowserRenderingBinding = BrowserRenderingBinding>(definition: BrowserRenderingDefinition) => (binding: RawBinding) => BrowserRenderingClient<RawBinding>;
|
|
405
|
-
declare const layer$
|
|
405
|
+
declare const layer$11: <Self>(tag: Context.Service<Self, BrowserRenderingClient>, definition: BrowserRenderingDefinition) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
406
406
|
declare const make$9: <Id extends string>(id: Id) => TagClass$8<BrowserRenderingService<Id>, Id>;
|
|
407
407
|
declare const Tag$9: <Self>() => <Id extends string>(id: Id) => TagClass$8<Self, Id>;
|
|
408
408
|
declare namespace Cache_d_exports {
|
|
409
|
-
export { CacheClient, CacheOperation, CacheOperationError, CacheQueryOptions, CacheRequest, CacheStorage, CacheStorageClient, layer$
|
|
409
|
+
export { CacheClient, CacheOperation, CacheOperationError, CacheQueryOptions, CacheRequest, CacheStorage, CacheStorageClient, layer$10 as layer, layerFrom, makeCacheClient, makeClient$6 as makeClient };
|
|
410
410
|
}
|
|
411
411
|
type CacheRequest = CloudflareRequestInfo | URL;
|
|
412
412
|
type CacheQueryOptions = CloudflareCacheQueryOptions;
|
|
@@ -438,9 +438,9 @@ declare class CacheStorage extends CacheStorage_base {}
|
|
|
438
438
|
declare const makeCacheClient: (cache: CloudflareCache, name?: string) => CacheClient;
|
|
439
439
|
declare const makeClient$6: (storage: CloudflareCacheStorage) => CacheStorageClient;
|
|
440
440
|
declare const layerFrom: (storage: CloudflareCacheStorage) => Layer.Layer<CacheStorage>;
|
|
441
|
-
declare const layer$
|
|
441
|
+
declare const layer$10: Layer.Layer<CacheStorage>;
|
|
442
442
|
declare namespace CloudflareOtlp_d_exports {
|
|
443
|
-
export { DurableObjectLayerOptions, LayerOptions$9 as LayerOptions, ResourceOptions, Serialization, Signal, WorkerLayerOptions, layer$
|
|
443
|
+
export { DurableObjectLayerOptions, LayerOptions$9 as LayerOptions, ResourceOptions, Serialization, Signal, WorkerLayerOptions, layer$9 as layer, layerDurableObject, layerJson, layerProtobuf, layerWorker };
|
|
444
444
|
}
|
|
445
445
|
type ResourceAttributes = NonNullable<Parameters<typeof OtlpResource.make>[0]["attributes"]>;
|
|
446
446
|
/** Telemetry signal groups supported by the Cloudflare OTLP layers. */
|
|
@@ -504,7 +504,7 @@ interface DurableObjectLayerOptions extends LayerOptions$9 {
|
|
|
504
504
|
* The layer provides {@link OtlpExporter.Flusher} for draining buffered
|
|
505
505
|
* telemetry before the isolate freezes.
|
|
506
506
|
*/
|
|
507
|
-
declare const layer$
|
|
507
|
+
declare const layer$9: (options?: LayerOptions$9) => Layer.Layer<OtlpExporter.Flusher>;
|
|
508
508
|
/** Base OTLP telemetry layer forced to JSON serialization. */
|
|
509
509
|
declare const layerJson: (options?: Omit<LayerOptions$9, "serialization">) => Layer.Layer<OtlpExporter.Flusher>;
|
|
510
510
|
/** Base OTLP telemetry layer forced to protobuf serialization. */
|
|
@@ -526,6 +526,23 @@ declare const layerWorker: (options?: WorkerLayerOptions) => Layer.Layer<OtlpExp
|
|
|
526
526
|
* backend can tolerate high-cardinality resource attributes.
|
|
527
527
|
*/
|
|
528
528
|
declare const layerDurableObject: (options?: DurableObjectLayerOptions) => Layer.Layer<OtlpExporter.Flusher, never, DurableObjectState>;
|
|
529
|
+
declare namespace CloudflareTracer_d_exports {
|
|
530
|
+
export { layer$8 as layer };
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Sends Effect spans to Cloudflare Workers Observability using the runtime's
|
|
534
|
+
* custom span API. Build this layer inside each invocation, for example with
|
|
535
|
+
* `Worker.make(Services, { eventLayer: CloudflareTracer.layer, fetch })`.
|
|
536
|
+
* It captures the invocation's async context and must not be cached across requests.
|
|
537
|
+
*
|
|
538
|
+
* Enable `observability.traces.enabled` in Wrangler. Cloudflare owns sampling
|
|
539
|
+
* and export; no OTLP exporter or flush is required. Scalar attributes are
|
|
540
|
+
* forwarded; other attributes, events, and links remain Effect-local. Completion
|
|
541
|
+
* is recorded as `effect.exit`, since Cloudflare has no outcome-setting API.
|
|
542
|
+
* Effect trace/span IDs remain independent of Cloudflare's opaque IDs. External
|
|
543
|
+
* parents and `root: true` cannot override the invocation's Cloudflare trace.
|
|
544
|
+
*/
|
|
545
|
+
declare const layer$8: Layer.Layer<never>;
|
|
529
546
|
declare namespace D1_d_exports {
|
|
530
547
|
export { D1Definition, D1Service, D1SqlLayerOptions, Service, TypeId$1 as TypeId, make$8 as make };
|
|
531
548
|
}
|
|
@@ -853,7 +870,7 @@ type DurableObjectClass<Rpc extends DurableObjectRpc<ROut>, ROut> = new (state:
|
|
|
853
870
|
*/
|
|
854
871
|
declare const make$6: <ROut, LayerError, REvent = never, EventLayerError = never, const Rpc extends DurableObjectRpc<ROut | REvent> = Record<never, never>>(layer: Layer.Layer<ROut, LayerError, DurableObjectState | WorkerEnvironment>, options?: DurableObjectOptions<ROut, REvent, EventLayerError, Rpc>) => DurableObjectClass<Rpc, ROut | REvent>;
|
|
855
872
|
declare namespace DurableObjectAlarm_d_exports {
|
|
856
|
-
export { AlarmDefinitionConfig, AlarmDefinitionEntry, AlarmDefinitionPayload, AlarmDefinitions, AlarmFailurePolicy, AlarmPayload, AlarmPayloadSchema, AlarmRef, AlarmRetryPolicy, AlarmScheduler, DefinedAlarmEvent, DefinedAlarmHandlers, DurableObjectAlarm, DurableObjectAlarmError, DurableObjectAlarmEvent, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, ProcessDueAlarmsFailure, ProcessDueAlarmsFailureAction, ProcessDueAlarmsHandler, ProcessDueAlarmsMode, ProcessDueAlarmsOptions, ProcessDueAlarmsResult, ScheduleAlarmInput, StoredAlarmDecodeError, define, processDue };
|
|
873
|
+
export { AlarmDefinitionConfig, AlarmDefinitionEntry, AlarmDefinitionPayload, AlarmDefinitions, AlarmFailurePolicy, AlarmPayload, AlarmPayloadSchema, AlarmRef, AlarmRetryPolicy, AlarmScheduler, AlarmTransaction, DefinedAlarmEvent, DefinedAlarmHandlers, DurableObjectAlarm, DurableObjectAlarmError, DurableObjectAlarmEvent, InvalidAlarmPayloadError, InvalidAlarmRefError, InvalidProcessDueAlarmsOptionsError, InvalidRepeatEveryError, ProcessDueAlarmsFailure, ProcessDueAlarmsFailureAction, ProcessDueAlarmsHandler, ProcessDueAlarmsMode, ProcessDueAlarmsOptions, ProcessDueAlarmsResult, ScheduleAlarmInput, StoredAlarmDecodeError, define, processDue };
|
|
857
874
|
}
|
|
858
875
|
type AlarmPayload = Schema.Json;
|
|
859
876
|
declare const InvalidAlarmRefError_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 & {
|
|
@@ -946,8 +963,26 @@ interface ProcessDueAlarmsOptions<OnFailureR = never, OnFailureE = never> {
|
|
|
946
963
|
readonly retryFailedAfter?: Duration.Input;
|
|
947
964
|
}
|
|
948
965
|
type ProcessDueAlarmsHandler<R = never, E = never> = (event: DurableObjectAlarmEvent) => Effect.Effect<void, E, R>;
|
|
966
|
+
/**
|
|
967
|
+
* Alarm mutations owned by one transaction callback. Run them in the callback's
|
|
968
|
+
* fiber; forked work and use after the callback ends fail with StorageOperationError.
|
|
969
|
+
*/
|
|
970
|
+
type AlarmTransaction = Pick<AlarmScheduler, "scheduleAlarm" | "cancelAlarm">;
|
|
949
971
|
/** Own `storage.setAlarm()` exclusively: a Durable Object has one platform alarm timestamp. */
|
|
950
972
|
type AlarmScheduler = {
|
|
973
|
+
/**
|
|
974
|
+
* Commits local application storage and logical alarms in one native SQLite
|
|
975
|
+
* Durable Object transaction, reconciling the native alarm before commit.
|
|
976
|
+
* Use the supplied mutations, not standalone alarm methods or nested transactions.
|
|
977
|
+
* SqlClient queries must use this same Durable Object's storage.
|
|
978
|
+
*
|
|
979
|
+
* Failure, defects and interruption before commit roll back. A lost reply or
|
|
980
|
+
* interruption after commit does not undo committed state. Keep RPC and other
|
|
981
|
+
* external effects outside; atomically pre-arm a later wake before fallible work.
|
|
982
|
+
* Cloudflare's native retries are bounded; composition does not remove the
|
|
983
|
+
* pre-arm requirement or promise infinite retry liveness.
|
|
984
|
+
*/
|
|
985
|
+
readonly transaction: <A, E, R>(closure: (alarms: AlarmTransaction) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | StorageOperationError, R>;
|
|
951
986
|
readonly cancelAlarm: (input: AlarmRef) => Effect.Effect<void, InvalidAlarmRefError | StorageOperationError>;
|
|
952
987
|
/** Acknowledge after handling. Conditional writes preserve handler replacements; alarms are at-least-once. */
|
|
953
988
|
readonly processDueAlarms: <R = never, E = never, OnFailureR = never, OnFailureE = never>(handle: ProcessDueAlarmsHandler<R, E>, options?: ProcessDueAlarmsOptions<OnFailureR, OnFailureE>) => Effect.Effect<ProcessDueAlarmsResult, E | OnFailureE | DurableObjectAlarmError, R | OnFailureR>;
|
|
@@ -1763,4 +1798,4 @@ declare const implement: typeof implement$1;
|
|
|
1763
1798
|
type Handler<ROut, Self extends Definition$1.Any> = Handler$1<ROut, Self>;
|
|
1764
1799
|
type Options<ROut, Self extends Definition$1.Any> = Options$1<ROut, Self>;
|
|
1765
1800
|
//#endregion
|
|
1766
|
-
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, 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 };
|
|
1801
|
+
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { a as WorkerEnvironment, i as WorkerConfig, n as violationsMessage, r as Environment_exports, t as causeMessage } from "./ErrorMessage-Byx2OgNd.mjs";
|
|
3
|
-
import { n as Service$1, r as layer$
|
|
3
|
+
import { n as Service$1, r as layer$18, t as Binding_exports } from "./Binding-C82jRhdr.mjs";
|
|
4
4
|
import { n as Artifacts_exports } from "./Artifacts-CBxWGeZB.mjs";
|
|
5
5
|
import { t as fromExecutionContext } from "./WorkerContext-Yobnfw-K.mjs";
|
|
6
|
-
import { a as DurableWebSocketAttachmentError, i as DurableObjectWebSocket_exports, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState } from "./DurableObjectState-
|
|
6
|
+
import { a as DurableWebSocketAttachmentError, c as StorageOperationError, i as DurableObjectWebSocket_exports, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState } from "./DurableObjectState-DLL0YgBd.mjs";
|
|
7
7
|
import { A as QueueDefinition_exports, C as decodeSuccess, D as method$1, E as make$15, O as reservedMethodNames$2, S as decodeArgs, T as encodeSuccess, _ as RpcTracing_exports, a as WorkerDefinition_exports, b as RpcDefinition_exports, c as resolve, d as makeEntrypointRuntime, f as runEventPromise, g as recordDecodedArgs, h as invokeRpcMethod, i as Worker_exports, j as QueueBinding_exports, k as Queue_exports, l as scoped, m as defineEntrypointRpcMethods, n as NativeRequest, o as ServiceBinding_exports, p as assumeEntrypointClass, r as WorkerContext, s as Rpc_exports, t as ExecutionContext, u as scheduleTelemetryFlush$1, v as withRpcClientSpan, w as encodeArgs, x as assertNoReservedMethods, y as withRpcTraceContext } from "./Worker-XsGJsCJX.mjs";
|
|
8
8
|
import { Cause, Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, FiberSet, Function as Function$1, Layer, Option, Predicate, Queue, Result, Schema, Tracer } from "effect";
|
|
9
9
|
import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
10
10
|
import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
11
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12
|
+
import { DurableObject, WorkflowEntrypoint, tracing } from "cloudflare:workers";
|
|
11
13
|
import { D1Client } from "@effect/sql-d1";
|
|
12
|
-
import { DurableObject, WorkflowEntrypoint } from "cloudflare:workers";
|
|
13
14
|
import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
|
|
14
15
|
import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
|
|
15
16
|
import * as RpcServer from "effect/unstable/rpc/RpcServer";
|
|
@@ -21,7 +22,7 @@ var WorkersAi_exports = /* @__PURE__ */ __exportAll({
|
|
|
21
22
|
WorkersAiOperationError: () => WorkersAiOperationError,
|
|
22
23
|
embeddingResponse: () => embeddingResponse,
|
|
23
24
|
isWorkersAiBinding: () => isWorkersAiBinding,
|
|
24
|
-
layer: () => layer$
|
|
25
|
+
layer: () => layer$17,
|
|
25
26
|
make: () => make$14,
|
|
26
27
|
makeClient: () => makeClient$13
|
|
27
28
|
});
|
|
@@ -78,11 +79,11 @@ const makeClient$13 = (definition) => (ai) => {
|
|
|
78
79
|
rawUnsafe: Effect.succeed(ai)
|
|
79
80
|
};
|
|
80
81
|
};
|
|
81
|
-
const layer$
|
|
82
|
+
const layer$17 = (tag, definition) => layer$18(tag, definition.binding, (value) => isWorkersAiBinding(value), makeClient$13(definition), { expected: expectedWorkersAiBinding });
|
|
82
83
|
const make$14 = (id) => Tag$13()(id);
|
|
83
84
|
const Tag$13 = () => (id) => {
|
|
84
85
|
const tag = Context.Service()(id);
|
|
85
|
-
const makeLayer = (definition) => layer$
|
|
86
|
+
const makeLayer = (definition) => layer$17(tag, definition);
|
|
86
87
|
return Object.assign(tag, {
|
|
87
88
|
id,
|
|
88
89
|
layer: makeLayer
|
|
@@ -94,7 +95,7 @@ var AiGateway_exports = /* @__PURE__ */ __exportAll({
|
|
|
94
95
|
AiGatewayOperationError: () => AiGatewayOperationError,
|
|
95
96
|
Tag: () => Tag$12,
|
|
96
97
|
isAiGatewayBinding: () => isAiGatewayBinding,
|
|
97
|
-
layer: () => layer$
|
|
98
|
+
layer: () => layer$16,
|
|
98
99
|
make: () => make$13,
|
|
99
100
|
makeClient: () => makeClient$12,
|
|
100
101
|
makeClientFromAi: () => makeClientFromAi,
|
|
@@ -247,11 +248,11 @@ const makeHttpClient = (definition, request = fetch) => {
|
|
|
247
248
|
rawUnsafe: Effect.fail(aiGatewayError(binding, "rawUnsafe", /* @__PURE__ */ new TypeError("HTTP AI Gateway clients have no raw binding")))
|
|
248
249
|
};
|
|
249
250
|
};
|
|
250
|
-
const layer$
|
|
251
|
+
const layer$16 = (tag, definition) => layer$18(tag, definition.binding, isAiGatewayBinding, (ai) => makeClientFromAi(definition, ai), { expected: expectedAiGatewayBinding });
|
|
251
252
|
const make$13 = (id) => Tag$12()(id);
|
|
252
253
|
const Tag$12 = () => (id) => {
|
|
253
254
|
const tag = Context.Service()(id);
|
|
254
|
-
const makeLayer = (definition) => layer$
|
|
255
|
+
const makeLayer = (definition) => layer$16(tag, definition);
|
|
255
256
|
return Object.assign(tag, {
|
|
256
257
|
id,
|
|
257
258
|
layer: makeLayer
|
|
@@ -268,7 +269,7 @@ var AnalyticsEngine_exports = /* @__PURE__ */ __exportAll({
|
|
|
268
269
|
QueryTag: () => QueryTag,
|
|
269
270
|
Tag: () => Tag$11,
|
|
270
271
|
isAnalyticsEngineDataset: () => isAnalyticsEngineDataset,
|
|
271
|
-
layer: () => layer$
|
|
272
|
+
layer: () => layer$15,
|
|
272
273
|
layerFetch: () => layerFetch,
|
|
273
274
|
layerFetchConfig: () => layerFetchConfig,
|
|
274
275
|
make: () => make$12,
|
|
@@ -491,12 +492,12 @@ const queryLayerConfig = (tag, config = queryConfig()) => Layer.effect(tag, Effe
|
|
|
491
492
|
return yield* makeQueryClient(definition);
|
|
492
493
|
}));
|
|
493
494
|
const layerFetchConfig = (tag, config = queryConfig()) => queryLayerConfig(tag, config).pipe(Layer.provide(FetchHttpClient.layer));
|
|
494
|
-
const layer$
|
|
495
|
+
const layer$15 = (tag, definition) => layer$18(tag, definition.binding, isAnalyticsEngineDataset, makeClient$11(definition, definition.write), { expected: expectedAnalyticsEngineDataset });
|
|
495
496
|
const make$12 = (id) => Tag$11()(id);
|
|
496
497
|
const makeQuery = (id) => QueryTag()(id);
|
|
497
498
|
const Tag$11 = () => (id) => {
|
|
498
499
|
const tag = Context.Service()(id);
|
|
499
|
-
const makeLayer = (definition) => layer$
|
|
500
|
+
const makeLayer = (definition) => layer$15(tag, definition);
|
|
500
501
|
return Object.assign(tag, {
|
|
501
502
|
id,
|
|
502
503
|
layer: makeLayer
|
|
@@ -522,7 +523,7 @@ var BrowserRendering_exports = /* @__PURE__ */ __exportAll({
|
|
|
522
523
|
BrowserRenderingOperationError: () => BrowserRenderingOperationError,
|
|
523
524
|
Tag: () => Tag$10,
|
|
524
525
|
isBrowserRenderingBinding: () => isBrowserRenderingBinding,
|
|
525
|
-
layer: () => layer$
|
|
526
|
+
layer: () => layer$14,
|
|
526
527
|
make: () => make$11,
|
|
527
528
|
makeClient: () => makeClient$10
|
|
528
529
|
});
|
|
@@ -579,11 +580,11 @@ const makeClient$10 = (definition) => (binding) => ({
|
|
|
579
580
|
connectWith: (connect, options) => tryBrowserRenderingPromise(definition.binding, "connect", () => connect(binding, options)).pipe(Effect.map((browser) => wrapBrowser(definition.binding, browser)), Effect.withSpan("BrowserRendering.connectWith")),
|
|
580
581
|
rawUnsafe: Effect.succeed(binding)
|
|
581
582
|
});
|
|
582
|
-
const layer$
|
|
583
|
+
const layer$14 = (tag, definition) => layer$18(tag, definition.binding, isBrowserRenderingBinding, makeClient$10(definition), { expected: expectedBrowserRenderingBinding });
|
|
583
584
|
const make$11 = (id) => Tag$10()(id);
|
|
584
585
|
const Tag$10 = () => (id) => {
|
|
585
586
|
const tag = Context.Service()(id);
|
|
586
|
-
const makeLayer = (definition) => layer$
|
|
587
|
+
const makeLayer = (definition) => layer$14(tag, definition);
|
|
587
588
|
return Object.assign(tag, {
|
|
588
589
|
id,
|
|
589
590
|
layer: makeLayer
|
|
@@ -594,7 +595,7 @@ const Tag$10 = () => (id) => {
|
|
|
594
595
|
var Cache_exports = /* @__PURE__ */ __exportAll({
|
|
595
596
|
CacheOperationError: () => CacheOperationError,
|
|
596
597
|
CacheStorage: () => CacheStorage,
|
|
597
|
-
layer: () => layer$
|
|
598
|
+
layer: () => layer$13,
|
|
598
599
|
layerFrom: () => layerFrom,
|
|
599
600
|
makeCacheClient: () => makeCacheClient,
|
|
600
601
|
makeClient: () => makeClient$9
|
|
@@ -631,7 +632,7 @@ const makeClient$9 = (storage) => ({
|
|
|
631
632
|
rawUnsafe: Effect.succeed(storage)
|
|
632
633
|
});
|
|
633
634
|
const layerFrom = (storage) => Layer.succeed(CacheStorage, makeClient$9(storage));
|
|
634
|
-
const layer$
|
|
635
|
+
const layer$13 = Layer.sync(CacheStorage, () => makeClient$9(caches));
|
|
635
636
|
//#endregion
|
|
636
637
|
//#region src/CloudflareOtlp.ts
|
|
637
638
|
/**
|
|
@@ -641,7 +642,7 @@ const layer$12 = Layer.sync(CacheStorage, () => makeClient$9(caches));
|
|
|
641
642
|
* layer finalizers run separately and follow their configured shutdown timeout.
|
|
642
643
|
*/
|
|
643
644
|
var CloudflareOtlp_exports = /* @__PURE__ */ __exportAll({
|
|
644
|
-
layer: () => layer$
|
|
645
|
+
layer: () => layer$12,
|
|
645
646
|
layerDurableObject: () => layerDurableObject,
|
|
646
647
|
layerJson: () => layerJson,
|
|
647
648
|
layerProtobuf: () => layerProtobuf,
|
|
@@ -707,14 +708,14 @@ const makeLayer = (options = {}, runtimeAttributes = {}) => {
|
|
|
707
708
|
* The layer provides {@link OtlpExporter.Flusher} for draining buffered
|
|
708
709
|
* telemetry before the isolate freezes.
|
|
709
710
|
*/
|
|
710
|
-
const layer$
|
|
711
|
+
const layer$12 = (options = {}) => makeLayer(options);
|
|
711
712
|
/** Base OTLP telemetry layer forced to JSON serialization. */
|
|
712
|
-
const layerJson = (options = {}) => layer$
|
|
713
|
+
const layerJson = (options = {}) => layer$12({
|
|
713
714
|
...options,
|
|
714
715
|
serialization: "json"
|
|
715
716
|
});
|
|
716
717
|
/** Base OTLP telemetry layer forced to protobuf serialization. */
|
|
717
|
-
const layerProtobuf = (options = {}) => layer$
|
|
718
|
+
const layerProtobuf = (options = {}) => layer$12({
|
|
718
719
|
...options,
|
|
719
720
|
serialization: "protobuf"
|
|
720
721
|
});
|
|
@@ -743,6 +744,64 @@ const layerDurableObject = (options = {}) => Layer.unwrap(Effect.map(DurableObje
|
|
|
743
744
|
"cloudflare.durable_object.id": options.includeObjectId ? state.id.toString() : void 0
|
|
744
745
|
})));
|
|
745
746
|
//#endregion
|
|
747
|
+
//#region src/CloudflareTracer.ts
|
|
748
|
+
var CloudflareTracer_exports = /* @__PURE__ */ __exportAll({ layer: () => layer$11 });
|
|
749
|
+
var Span = class extends Tracer.NativeSpan {
|
|
750
|
+
runInContext;
|
|
751
|
+
cloudflareSpan;
|
|
752
|
+
constructor(options, runInContext, cloudflareSpan) {
|
|
753
|
+
super({
|
|
754
|
+
...options,
|
|
755
|
+
sampled: options.sampled && (cloudflareSpan?.isTraced ?? false)
|
|
756
|
+
});
|
|
757
|
+
this.runInContext = runInContext;
|
|
758
|
+
this.cloudflareSpan = cloudflareSpan;
|
|
759
|
+
}
|
|
760
|
+
attribute(key, value) {
|
|
761
|
+
super.attribute(key, value);
|
|
762
|
+
if (Predicate.isString(value) || Predicate.isNumber(value) || Predicate.isBoolean(value)) this.cloudflareSpan?.setAttribute(key, value);
|
|
763
|
+
}
|
|
764
|
+
end(endTime, exit) {
|
|
765
|
+
if (this.status._tag === "Ended") return;
|
|
766
|
+
super.end(endTime, exit);
|
|
767
|
+
this.cloudflareSpan?.setAttribute("effect.exit", Exit.isSuccess(exit) ? "success" : Cause.hasInterruptsOnly(exit.cause) ? "interrupted" : "failure");
|
|
768
|
+
this.cloudflareSpan?.end();
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
/**
|
|
772
|
+
* Sends Effect spans to Cloudflare Workers Observability using the runtime's
|
|
773
|
+
* custom span API. Build this layer inside each invocation, for example with
|
|
774
|
+
* `Worker.make(Services, { eventLayer: CloudflareTracer.layer, fetch })`.
|
|
775
|
+
* It captures the invocation's async context and must not be cached across requests.
|
|
776
|
+
*
|
|
777
|
+
* Enable `observability.traces.enabled` in Wrangler. Cloudflare owns sampling
|
|
778
|
+
* and export; no OTLP exporter or flush is required. Scalar attributes are
|
|
779
|
+
* forwarded; other attributes, events, and links remain Effect-local. Completion
|
|
780
|
+
* is recorded as `effect.exit`, since Cloudflare has no outcome-setting API.
|
|
781
|
+
* Effect trace/span IDs remain independent of Cloudflare's opaque IDs. External
|
|
782
|
+
* parents and `root: true` cannot override the invocation's Cloudflare trace.
|
|
783
|
+
*/
|
|
784
|
+
const layer$11 = Layer.effect(Tracer.Tracer, Effect.sync(() => {
|
|
785
|
+
const invocationContext = AsyncLocalStorage.snapshot();
|
|
786
|
+
const contextFor = (span) => {
|
|
787
|
+
while (span?._tag === "Span") {
|
|
788
|
+
if (span instanceof Span) return span.runInContext;
|
|
789
|
+
span = Option.getOrUndefined(span.parent);
|
|
790
|
+
}
|
|
791
|
+
return invocationContext;
|
|
792
|
+
};
|
|
793
|
+
return Tracer.make({
|
|
794
|
+
span(options) {
|
|
795
|
+
const parentContext = options.root ? invocationContext : contextFor(Option.getOrUndefined(options.parent));
|
|
796
|
+
if (!options.sampled) return new Span(options, parentContext);
|
|
797
|
+
return parentContext(() => tracing.startActiveSpan(options.name, (span) => new Span(options, AsyncLocalStorage.snapshot(), span)));
|
|
798
|
+
},
|
|
799
|
+
context(primitive, fiber) {
|
|
800
|
+
return contextFor(fiber.currentSpan)(() => primitive["~effect/Effect/evaluate"](fiber));
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
}));
|
|
804
|
+
//#endregion
|
|
746
805
|
//#region src/ContainerNamespace.ts
|
|
747
806
|
var ContainerNamespace_exports = /* @__PURE__ */ __exportAll({
|
|
748
807
|
ContainerNamespace: () => ContainerNamespace,
|
|
@@ -864,7 +923,7 @@ const makeClient$8 = (definition) => (namespace) => {
|
|
|
864
923
|
rawUnsafe: Effect.succeed(namespace)
|
|
865
924
|
};
|
|
866
925
|
};
|
|
867
|
-
const layer$10 = (tag, definition) => layer$
|
|
926
|
+
const layer$10 = (tag, definition) => layer$18(tag, definition.binding, (value) => isContainerNamespaceResource(value), makeClient$8(definition), { expected: expectedContainerNamespace });
|
|
868
927
|
const make$10 = (id) => Tag$9()(id);
|
|
869
928
|
const Tag$9 = () => (id) => {
|
|
870
929
|
const tag = Context.Service()(`effect-cf/Container/${id}`);
|
|
@@ -1033,7 +1092,7 @@ const makeClient$7 = (definition) => {
|
|
|
1033
1092
|
});
|
|
1034
1093
|
};
|
|
1035
1094
|
};
|
|
1036
|
-
const layer$9 = (tag, definition) => layer$
|
|
1095
|
+
const layer$9 = (tag, definition) => layer$18(tag, definition.binding, (value) => isDurableObjectNamespaceClient(value), makeClient$7(definition), { expected: expectedDurableObjectNamespace });
|
|
1037
1096
|
const makeDirectMethods = (rpcDefinition, helpers) => {
|
|
1038
1097
|
const methods = {};
|
|
1039
1098
|
if (rpcDefinition !== void 0) {
|
|
@@ -1430,25 +1489,35 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
1430
1489
|
});
|
|
1431
1490
|
const cancelAlarm = Effect.fn("DurableObjectAlarm.cancelAlarm")(function* (input) {
|
|
1432
1491
|
const ref = yield* decodeAlarmRef(input);
|
|
1433
|
-
yield* state.storage.
|
|
1434
|
-
yield* ensureTable(state);
|
|
1435
|
-
yield* state.storage.sql.exec(`DELETE FROM effect_cf_scheduled_alarms WHERE storage_id = ?`, getScheduledEventId(ref)).pipe(Effect.asVoid);
|
|
1436
|
-
yield* reconcileAlarm();
|
|
1437
|
-
}));
|
|
1492
|
+
yield* state.storage.sql.exec(`DELETE FROM effect_cf_scheduled_alarms WHERE storage_id = ?`, getScheduledEventId(ref));
|
|
1438
1493
|
});
|
|
1439
1494
|
const scheduleAlarm = Effect.fn("DurableObjectAlarm.scheduleAlarm")(function* (input) {
|
|
1440
1495
|
const ref = yield* decodeAlarmRef(input);
|
|
1441
1496
|
const repeatEveryMillis = yield* toRepeatEveryMillis(input.repeatEvery);
|
|
1442
1497
|
const payload = yield* encodeStoredPayload(input.payload);
|
|
1443
1498
|
const runAt = DateTime.toEpochMillis(input.runAt);
|
|
1444
|
-
yield* state.storage.
|
|
1445
|
-
yield* ensureTable(state);
|
|
1446
|
-
yield* state.storage.sql.exec(`INSERT OR REPLACE INTO effect_cf_scheduled_alarms
|
|
1499
|
+
yield* state.storage.sql.exec(`INSERT OR REPLACE INTO effect_cf_scheduled_alarms
|
|
1447
1500
|
(storage_id, alarm_id, tag, run_at, repeat_every_ms, payload)
|
|
1448
|
-
VALUES (?, ?, ?, ?, ?, ?)`, getScheduledEventId(ref), ref.id, ref.tag, runAt, repeatEveryMillis, payload)
|
|
1449
|
-
yield* reconcileAlarm();
|
|
1450
|
-
}));
|
|
1501
|
+
VALUES (?, ?, ?, ?, ?, ?)`, getScheduledEventId(ref), ref.id, ref.tag, runAt, repeatEveryMillis, payload);
|
|
1451
1502
|
});
|
|
1503
|
+
const transaction = (closure) => state.storage.transaction(() => Effect.withFiber((owner) => {
|
|
1504
|
+
let active = true;
|
|
1505
|
+
const requireActive = (effect) => Effect.withFiber((fiber) => active && fiber === owner ? effect : Effect.fail(new StorageOperationError({
|
|
1506
|
+
operation: "alarm.transaction",
|
|
1507
|
+
cause: /* @__PURE__ */ new Error("Alarm mutations require their active transaction callback")
|
|
1508
|
+
})));
|
|
1509
|
+
return Effect.gen(function* () {
|
|
1510
|
+
yield* ensureTable(state);
|
|
1511
|
+
const result = yield* Effect.suspend(() => closure({
|
|
1512
|
+
cancelAlarm: (input) => requireActive(cancelAlarm(input)),
|
|
1513
|
+
scheduleAlarm: (input) => requireActive(scheduleAlarm(input))
|
|
1514
|
+
})).pipe(Effect.ensuring(Effect.sync(() => {
|
|
1515
|
+
active = false;
|
|
1516
|
+
})));
|
|
1517
|
+
yield* reconcileAlarm();
|
|
1518
|
+
return result;
|
|
1519
|
+
});
|
|
1520
|
+
}));
|
|
1452
1521
|
const processDueAlarms = Effect.fn("DurableObjectAlarm.processDueAlarms")(function* (handle, options) {
|
|
1453
1522
|
yield* ensureTable(state);
|
|
1454
1523
|
const mode = options?.mode ?? "isolated";
|
|
@@ -1507,9 +1576,10 @@ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("eff
|
|
|
1507
1576
|
};
|
|
1508
1577
|
});
|
|
1509
1578
|
return DurableObjectAlarm.of({
|
|
1510
|
-
cancelAlarm,
|
|
1579
|
+
cancelAlarm: (input) => transaction((alarms) => alarms.cancelAlarm(input)),
|
|
1511
1580
|
processDueAlarms,
|
|
1512
|
-
scheduleAlarm
|
|
1581
|
+
scheduleAlarm: (input) => transaction((alarms) => alarms.scheduleAlarm(input)),
|
|
1582
|
+
transaction
|
|
1513
1583
|
});
|
|
1514
1584
|
}).pipe(Effect.withSpan("DurableObjectAlarm.layer")));
|
|
1515
1585
|
};
|
|
@@ -2282,7 +2352,7 @@ const makeClient$6 = (definition, options) => (email) => {
|
|
|
2282
2352
|
rawUnsafe: Effect.succeed(email)
|
|
2283
2353
|
};
|
|
2284
2354
|
};
|
|
2285
|
-
const layer$6 = (tag, definition) => layer$
|
|
2355
|
+
const layer$6 = (tag, definition) => layer$18(tag, definition.binding, isEmailBinding, makeClient$6(definition, definition.send), { expected: expectedSendEmailBinding });
|
|
2286
2356
|
const make$6 = (id) => Tag$7()(id);
|
|
2287
2357
|
const Tag$7 = () => (id) => {
|
|
2288
2358
|
const tag = Context.Service()(id);
|
|
@@ -2308,7 +2378,7 @@ const makeClient$5 = (definition) => (hyperdrive) => ({
|
|
|
2308
2378
|
connectionString: hyperdrive.connectionString,
|
|
2309
2379
|
rawUnsafe: Effect.succeed(hyperdrive)
|
|
2310
2380
|
});
|
|
2311
|
-
const layer$5 = (tag, definition) => layer$
|
|
2381
|
+
const layer$5 = (tag, definition) => layer$18(tag, definition.binding, isHyperdrive, makeClient$5(definition), { expected: expectedHyperdrive });
|
|
2312
2382
|
const make$5 = (id) => Tag$6()(id);
|
|
2313
2383
|
const Tag$6 = () => (id) => {
|
|
2314
2384
|
const tag = Context.Service()(id);
|
|
@@ -2410,7 +2480,7 @@ const makeClient$4 = (definition) => (images) => {
|
|
|
2410
2480
|
rawUnsafe: Effect.succeed(images)
|
|
2411
2481
|
};
|
|
2412
2482
|
};
|
|
2413
|
-
const layer$4 = (tag, definition) => layer$
|
|
2483
|
+
const layer$4 = (tag, definition) => layer$18(tag, definition.binding, isImagesBinding, makeClient$4(definition), { expected: expectedImagesBinding });
|
|
2414
2484
|
const make$4 = (id) => Tag$5()(id);
|
|
2415
2485
|
const Tag$5 = () => (id) => {
|
|
2416
2486
|
const tag = Context.Service()(id);
|
|
@@ -2518,7 +2588,7 @@ const makeClient$3 = (definition) => {
|
|
|
2518
2588
|
rawUnsafe: Effect.succeed(kv)
|
|
2519
2589
|
});
|
|
2520
2590
|
};
|
|
2521
|
-
const layer$3 = (tag, definition) => layer$
|
|
2591
|
+
const layer$3 = (tag, definition) => layer$18(tag, definition.binding, isKvNamespace, makeClient$3(definition), { expected: expectedKvNamespace });
|
|
2522
2592
|
const makeDefinition$1 = (id, definition) => {
|
|
2523
2593
|
const kvDefinition = {
|
|
2524
2594
|
id,
|
|
@@ -2639,7 +2709,7 @@ const makeClient$2 = (definition) => {
|
|
|
2639
2709
|
};
|
|
2640
2710
|
};
|
|
2641
2711
|
};
|
|
2642
|
-
const layer$2 = (tag, definition) => layer$
|
|
2712
|
+
const layer$2 = (tag, definition) => layer$18(tag, definition.binding, isR2Bucket, makeClient$2(definition), { expected: expectedR2Bucket });
|
|
2643
2713
|
const make$3 = (id) => Tag$3()(id);
|
|
2644
2714
|
const Tag$3 = () => (id) => {
|
|
2645
2715
|
const tag = Context.Service()(id);
|
|
@@ -2705,7 +2775,7 @@ const makeClient$1 = (definition) => (index) => {
|
|
|
2705
2775
|
rawUnsafe: Effect.succeed(index)
|
|
2706
2776
|
};
|
|
2707
2777
|
};
|
|
2708
|
-
const layer$1 = (tag, definition) => layer$
|
|
2778
|
+
const layer$1 = (tag, definition) => layer$18(tag, definition.binding, isVectorizeBinding, makeClient$1(definition), { expected: expectedVectorizeBinding });
|
|
2709
2779
|
const make$2 = (id) => Tag$2()(id);
|
|
2710
2780
|
const Tag$2 = () => (id) => {
|
|
2711
2781
|
const tag = Context.Service()(id);
|
|
@@ -2860,7 +2930,7 @@ const makeClient = (definition) => {
|
|
|
2860
2930
|
rawUnsafe: Effect.succeed(workflow)
|
|
2861
2931
|
});
|
|
2862
2932
|
};
|
|
2863
|
-
const layer = (tag, definition) => layer$
|
|
2933
|
+
const layer = (tag, definition) => layer$18(tag, definition.binding, (value) => isWorkflow(value), makeClient(definition), { expected: expectedWorkflow });
|
|
2864
2934
|
//#endregion
|
|
2865
2935
|
//#region src/WorkflowDefinition.ts
|
|
2866
2936
|
var WorkflowDefinition_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -2881,7 +2951,7 @@ const make$1 = (id, definition) => Tag$1()(id, definition);
|
|
|
2881
2951
|
const Tag$1 = () => (id, definition) => {
|
|
2882
2952
|
const workflowDefinition = makeDefinition(id, definition);
|
|
2883
2953
|
const tag = Context.Service()(`effect-cf/Workflow/${id}`);
|
|
2884
|
-
const layer$
|
|
2954
|
+
const layer$19 = (binding) => layer(tag, {
|
|
2885
2955
|
...binding,
|
|
2886
2956
|
payload: definition.payload,
|
|
2887
2957
|
result: definition.result
|
|
@@ -2901,7 +2971,7 @@ const Tag$1 = () => (id, definition) => {
|
|
|
2901
2971
|
payload: workflowDefinition.payload,
|
|
2902
2972
|
result: workflowDefinition.result,
|
|
2903
2973
|
make: workflowDefinition.make,
|
|
2904
|
-
layer: layer$
|
|
2974
|
+
layer: layer$19,
|
|
2905
2975
|
create,
|
|
2906
2976
|
createBatch,
|
|
2907
2977
|
get,
|
|
@@ -3046,4 +3116,4 @@ const waitForEvent = (name, options) => Effect.flatMap(WorkflowStep$1, (workflow
|
|
|
3046
3116
|
const Tag = Tag$1;
|
|
3047
3117
|
const implement = implement$1;
|
|
3048
3118
|
//#endregion
|
|
3049
|
-
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, 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 };
|
|
3119
|
+
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 };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-cf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.0",
|
|
4
4
|
"description": "Effect-native primitives for Cloudflare Workers and bindings.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"@platformatic/vfs": "^0.4.0",
|
|
86
86
|
"effect": "catalog:",
|
|
87
87
|
"esbuild": "^0.28.1",
|
|
88
|
+
"miniflare": "catalog:",
|
|
88
89
|
"vite-plus": "catalog:",
|
|
89
90
|
"vitest": "catalog:"
|
|
90
91
|
},
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { tracing } from "cloudflare:workers";
|
|
3
|
+
import { Cause, Effect, Exit, Layer, Option, Predicate, Tracer } from "effect";
|
|
4
|
+
|
|
5
|
+
type SpanOptions = Parameters<Tracer.Tracer["span"]>[0];
|
|
6
|
+
type RunInContext = ReturnType<typeof AsyncLocalStorage.snapshot>;
|
|
7
|
+
type CloudflareSpan = Parameters<Parameters<typeof tracing.startActiveSpan>[1]>[0];
|
|
8
|
+
|
|
9
|
+
class Span extends Tracer.NativeSpan {
|
|
10
|
+
constructor(
|
|
11
|
+
options: SpanOptions,
|
|
12
|
+
readonly runInContext: RunInContext,
|
|
13
|
+
readonly cloudflareSpan?: CloudflareSpan,
|
|
14
|
+
) {
|
|
15
|
+
super({ ...options, sampled: options.sampled && (cloudflareSpan?.isTraced ?? false) });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Effect's tracer contract accepts arbitrary attributes; only CF-supported scalars cross the boundary.
|
|
19
|
+
// oxlint-disable-next-line anti-slop/no-unknown-parameters
|
|
20
|
+
override attribute(key: string, value: unknown): void {
|
|
21
|
+
super.attribute(key, value);
|
|
22
|
+
|
|
23
|
+
if (Predicate.isString(value) || Predicate.isNumber(value) || Predicate.isBoolean(value)) {
|
|
24
|
+
this.cloudflareSpan?.setAttribute(key, value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override end(endTime: bigint, exit: Exit.Exit<unknown, unknown>): void {
|
|
29
|
+
if (this.status._tag === "Ended") return;
|
|
30
|
+
|
|
31
|
+
super.end(endTime, exit);
|
|
32
|
+
this.cloudflareSpan?.setAttribute(
|
|
33
|
+
"effect.exit",
|
|
34
|
+
Exit.isSuccess(exit)
|
|
35
|
+
? "success"
|
|
36
|
+
: Cause.hasInterruptsOnly(exit.cause)
|
|
37
|
+
? "interrupted"
|
|
38
|
+
: "failure",
|
|
39
|
+
);
|
|
40
|
+
this.cloudflareSpan?.end();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Sends Effect spans to Cloudflare Workers Observability using the runtime's
|
|
46
|
+
* custom span API. Build this layer inside each invocation, for example with
|
|
47
|
+
* `Worker.make(Services, { eventLayer: CloudflareTracer.layer, fetch })`.
|
|
48
|
+
* It captures the invocation's async context and must not be cached across requests.
|
|
49
|
+
*
|
|
50
|
+
* Enable `observability.traces.enabled` in Wrangler. Cloudflare owns sampling
|
|
51
|
+
* and export; no OTLP exporter or flush is required. Scalar attributes are
|
|
52
|
+
* forwarded; other attributes, events, and links remain Effect-local. Completion
|
|
53
|
+
* is recorded as `effect.exit`, since Cloudflare has no outcome-setting API.
|
|
54
|
+
* Effect trace/span IDs remain independent of Cloudflare's opaque IDs. External
|
|
55
|
+
* parents and `root: true` cannot override the invocation's Cloudflare trace.
|
|
56
|
+
*/
|
|
57
|
+
export const layer: Layer.Layer<never> = Layer.effect(
|
|
58
|
+
Tracer.Tracer,
|
|
59
|
+
Effect.sync(() => {
|
|
60
|
+
const invocationContext = AsyncLocalStorage.snapshot();
|
|
61
|
+
const contextFor = (span: Tracer.AnySpan | undefined): RunInContext => {
|
|
62
|
+
while (span?._tag === "Span") {
|
|
63
|
+
if (span instanceof Span) return span.runInContext;
|
|
64
|
+
|
|
65
|
+
// Effect can install a no-op span while tracing is locally disabled.
|
|
66
|
+
span = Option.getOrUndefined(span.parent);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return invocationContext;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return Tracer.make({
|
|
73
|
+
span(options) {
|
|
74
|
+
const parentContext = options.root
|
|
75
|
+
? invocationContext
|
|
76
|
+
: contextFor(Option.getOrUndefined(options.parent));
|
|
77
|
+
|
|
78
|
+
if (!options.sampled) return new Span(options, parentContext);
|
|
79
|
+
|
|
80
|
+
return parentContext(() =>
|
|
81
|
+
tracing.startActiveSpan(
|
|
82
|
+
options.name,
|
|
83
|
+
(span) => new Span(options, AsyncLocalStorage.snapshot(), span),
|
|
84
|
+
),
|
|
85
|
+
);
|
|
86
|
+
},
|
|
87
|
+
context(primitive, fiber) {
|
|
88
|
+
return contextFor(fiber.currentSpan)(() => primitive["~effect/Effect/evaluate"](fiber));
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "effect";
|
|
13
13
|
|
|
14
14
|
import { DurableObjectState } from "./DurableObjectState";
|
|
15
|
-
import type
|
|
15
|
+
import { type SqlStorageValue, StorageOperationError } from "./DurableObjectStorage";
|
|
16
16
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
17
17
|
|
|
18
18
|
const INIT_TABLE_SQL = `
|
|
@@ -177,8 +177,30 @@ export type ProcessDueAlarmsHandler<R = never, E = never> = (
|
|
|
177
177
|
event: DurableObjectAlarmEvent,
|
|
178
178
|
) => Effect.Effect<void, E, R>;
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Alarm mutations owned by one transaction callback. Run them in the callback's
|
|
182
|
+
* fiber; forked work and use after the callback ends fail with StorageOperationError.
|
|
183
|
+
*/
|
|
184
|
+
export type AlarmTransaction = Pick<AlarmScheduler, "scheduleAlarm" | "cancelAlarm">;
|
|
185
|
+
|
|
180
186
|
/** Own `storage.setAlarm()` exclusively: a Durable Object has one platform alarm timestamp. */
|
|
181
187
|
export type AlarmScheduler = {
|
|
188
|
+
/**
|
|
189
|
+
* Commits local application storage and logical alarms in one native SQLite
|
|
190
|
+
* Durable Object transaction, reconciling the native alarm before commit.
|
|
191
|
+
* Use the supplied mutations, not standalone alarm methods or nested transactions.
|
|
192
|
+
* SqlClient queries must use this same Durable Object's storage.
|
|
193
|
+
*
|
|
194
|
+
* Failure, defects and interruption before commit roll back. A lost reply or
|
|
195
|
+
* interruption after commit does not undo committed state. Keep RPC and other
|
|
196
|
+
* external effects outside; atomically pre-arm a later wake before fallible work.
|
|
197
|
+
* Cloudflare's native retries are bounded; composition does not remove the
|
|
198
|
+
* pre-arm requirement or promise infinite retry liveness.
|
|
199
|
+
*/
|
|
200
|
+
readonly transaction: <A, E, R>(
|
|
201
|
+
closure: (alarms: AlarmTransaction) => Effect.Effect<A, E, R>,
|
|
202
|
+
) => Effect.Effect<A, E | StorageOperationError, R>;
|
|
203
|
+
|
|
182
204
|
readonly cancelAlarm: (
|
|
183
205
|
input: AlarmRef,
|
|
184
206
|
) => Effect.Effect<void, InvalidAlarmRefError | StorageOperationError>;
|
|
@@ -523,17 +545,9 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
|
|
|
523
545
|
const cancelAlarm = Effect.fn("DurableObjectAlarm.cancelAlarm")(function* (input: AlarmRef) {
|
|
524
546
|
const ref = yield* decodeAlarmRef(input);
|
|
525
547
|
|
|
526
|
-
yield* state.storage.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
yield* state.storage.sql
|
|
530
|
-
.exec(
|
|
531
|
-
`DELETE FROM effect_cf_scheduled_alarms WHERE storage_id = ?`,
|
|
532
|
-
getScheduledEventId(ref),
|
|
533
|
-
)
|
|
534
|
-
.pipe(Effect.asVoid);
|
|
535
|
-
yield* reconcileAlarm();
|
|
536
|
-
}),
|
|
548
|
+
yield* state.storage.sql.exec(
|
|
549
|
+
`DELETE FROM effect_cf_scheduled_alarms WHERE storage_id = ?`,
|
|
550
|
+
getScheduledEventId(ref),
|
|
537
551
|
);
|
|
538
552
|
});
|
|
539
553
|
|
|
@@ -545,27 +559,62 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
|
|
|
545
559
|
const payload = yield* encodeStoredPayload(input.payload);
|
|
546
560
|
const runAt = DateTime.toEpochMillis(input.runAt);
|
|
547
561
|
|
|
548
|
-
yield* state.storage.
|
|
549
|
-
|
|
550
|
-
yield* ensureTable(state);
|
|
551
|
-
yield* state.storage.sql
|
|
552
|
-
.exec(
|
|
553
|
-
`INSERT OR REPLACE INTO effect_cf_scheduled_alarms
|
|
562
|
+
yield* state.storage.sql.exec(
|
|
563
|
+
`INSERT OR REPLACE INTO effect_cf_scheduled_alarms
|
|
554
564
|
(storage_id, alarm_id, tag, run_at, repeat_every_ms, payload)
|
|
555
565
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
)
|
|
563
|
-
.pipe(Effect.asVoid);
|
|
564
|
-
yield* reconcileAlarm();
|
|
565
|
-
}),
|
|
566
|
+
getScheduledEventId(ref),
|
|
567
|
+
ref.id,
|
|
568
|
+
ref.tag,
|
|
569
|
+
runAt,
|
|
570
|
+
repeatEveryMillis,
|
|
571
|
+
payload,
|
|
566
572
|
);
|
|
567
573
|
});
|
|
568
574
|
|
|
575
|
+
const transaction: AlarmScheduler["transaction"] = (closure) =>
|
|
576
|
+
state.storage.transaction(() =>
|
|
577
|
+
Effect.withFiber((owner) => {
|
|
578
|
+
let active = true;
|
|
579
|
+
|
|
580
|
+
// A callback-owned handle cannot escape via a returned Effect or a
|
|
581
|
+
// detached fiber and write after reconciliation or rollback.
|
|
582
|
+
const requireActive = <A, E>(effect: Effect.Effect<A, E>) =>
|
|
583
|
+
Effect.withFiber<A, E | StorageOperationError>((fiber) =>
|
|
584
|
+
active && fiber === owner
|
|
585
|
+
? effect
|
|
586
|
+
: Effect.fail(
|
|
587
|
+
new StorageOperationError({
|
|
588
|
+
operation: "alarm.transaction",
|
|
589
|
+
cause: new Error(
|
|
590
|
+
"Alarm mutations require their active transaction callback",
|
|
591
|
+
),
|
|
592
|
+
}),
|
|
593
|
+
),
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
return Effect.gen(function* () {
|
|
597
|
+
yield* ensureTable(state);
|
|
598
|
+
const result = yield* Effect.suspend(() =>
|
|
599
|
+
closure({
|
|
600
|
+
cancelAlarm: (input) => requireActive(cancelAlarm(input)),
|
|
601
|
+
scheduleAlarm: (input) => requireActive(scheduleAlarm(input)),
|
|
602
|
+
}),
|
|
603
|
+
).pipe(
|
|
604
|
+
Effect.ensuring(
|
|
605
|
+
Effect.sync(() => {
|
|
606
|
+
active = false;
|
|
607
|
+
}),
|
|
608
|
+
),
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
yield* reconcileAlarm();
|
|
612
|
+
|
|
613
|
+
return result;
|
|
614
|
+
});
|
|
615
|
+
}),
|
|
616
|
+
);
|
|
617
|
+
|
|
569
618
|
const processDueAlarms = Effect.fn("DurableObjectAlarm.processDueAlarms")(function* <
|
|
570
619
|
R,
|
|
571
620
|
E,
|
|
@@ -669,9 +718,10 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
|
|
|
669
718
|
});
|
|
670
719
|
|
|
671
720
|
return DurableObjectAlarm.of({
|
|
672
|
-
cancelAlarm,
|
|
721
|
+
cancelAlarm: (input) => transaction((alarms) => alarms.cancelAlarm(input)),
|
|
673
722
|
processDueAlarms,
|
|
674
|
-
scheduleAlarm,
|
|
723
|
+
scheduleAlarm: (input) => transaction((alarms) => alarms.scheduleAlarm(input)),
|
|
724
|
+
transaction,
|
|
675
725
|
});
|
|
676
726
|
}).pipe(Effect.withSpan("DurableObjectAlarm.layer")),
|
|
677
727
|
);
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * as Binding from "./Binding";
|
|
|
5
5
|
export * as BrowserRendering from "./BrowserRendering";
|
|
6
6
|
export * as Cache from "./Cache";
|
|
7
7
|
export * as CloudflareOtlp from "./CloudflareOtlp";
|
|
8
|
+
export * as CloudflareTracer from "./CloudflareTracer";
|
|
8
9
|
export * as ContainerNamespace from "./ContainerNamespace";
|
|
9
10
|
export * as D1 from "./D1";
|
|
10
11
|
export * as DurableObject from "./DurableObject";
|