effect-cf 0.20.1 → 0.22.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 +44 -0
- package/README.md +2 -2
- package/dist/{Hyperdrive-RTjgirMV.d.mts → Hyperdrive-COyg7R26.d.mts} +40 -13
- package/dist/HyperdrivePg.d.mts +13 -5
- package/dist/HyperdrivePg.mjs +12 -7
- package/dist/index.d.mts +708 -549
- package/dist/index.mjs +924 -587
- package/package.json +10 -5
- package/src/AiGateway.ts +82 -47
- package/src/AnalyticsEngine.ts +74 -58
- package/src/Binding.ts +66 -13
- package/src/BrowserRendering.ts +30 -7
- package/src/Cache.ts +32 -8
- package/src/CloudflareOtlp.ts +32 -9
- package/src/ContainerNamespace.ts +87 -55
- package/src/D1.ts +13 -3
- package/src/DurableObject.ts +27 -164
- package/src/DurableObjectAlarm.ts +30 -9
- package/src/DurableObjectDefinition.ts +58 -54
- package/src/DurableObjectNamespace.ts +99 -96
- package/src/DurableObjectRpcWebSocket.ts +14 -6
- package/src/DurableObjectSqlite.ts +6 -3
- package/src/DurableObjectState.ts +6 -9
- package/src/DurableObjectStorage.ts +7 -1
- package/src/DurableObjectWebSocket.ts +51 -41
- package/src/Email.ts +40 -13
- package/src/Environment.ts +26 -6
- package/src/Hyperdrive.ts +2 -2
- package/src/HyperdrivePg.ts +25 -13
- package/src/Images.ts +77 -82
- package/src/Kv.ts +37 -27
- package/src/Queue.ts +6 -1
- package/src/QueueBinding.ts +18 -21
- package/src/QueueDefinition.ts +15 -14
- package/src/R2.ts +107 -29
- package/src/Rpc.ts +3 -1
- package/src/RpcDefinition.ts +177 -133
- package/src/ServiceBinding.ts +112 -108
- package/src/Vectorize.ts +59 -14
- package/src/Worker.ts +172 -192
- package/src/WorkerDefinition.ts +5 -10
- package/src/WorkersAi.ts +27 -17
- package/src/Workflow.ts +54 -49
- package/src/WorkflowBinding.ts +19 -11
- package/src/WorkflowDefinition.ts +24 -27
- package/src/index.ts +4 -3
- package/src/internal/Entrypoint.ts +3 -1
- package/src/internal/ErrorMessage.ts +24 -0
- package/src/internal/RpcInvocation.ts +11 -8
- package/src/internal/Runtime.ts +52 -0
- package/src/internal/WorkerContext.ts +14 -2
- package/src/Entry.ts +0 -259
- package/src/internal/Clock.ts +0 -37
package/src/BrowserRendering.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Context, Data, Effect, type Layer } from "effect";
|
|
|
2
2
|
|
|
3
3
|
import * as Binding from "./Binding";
|
|
4
4
|
import type { WorkerEnvironment } from "./Environment";
|
|
5
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
5
6
|
|
|
6
7
|
const expectedBrowserRenderingBinding = "Browser Rendering binding resource";
|
|
7
8
|
|
|
@@ -12,7 +13,11 @@ export class BrowserRenderingOperationError extends Data.TaggedError(
|
|
|
12
13
|
readonly binding: string;
|
|
13
14
|
readonly operation: string;
|
|
14
15
|
readonly cause: unknown;
|
|
15
|
-
}> {
|
|
16
|
+
}> {
|
|
17
|
+
override get message(): string {
|
|
18
|
+
return `Browser Rendering ${this.operation} failed for binding "${this.binding}": ${ErrorMessage.causeMessage(this.cause)}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
16
21
|
|
|
17
22
|
/** Typed Browser Rendering binding definition. */
|
|
18
23
|
export interface BrowserRenderingDefinition {
|
|
@@ -106,7 +111,7 @@ export interface BrowserRenderingClient<
|
|
|
106
111
|
connect: BrowserRenderingConnect<RawBinding, Browser, ConnectOptions>,
|
|
107
112
|
options?: ConnectOptions,
|
|
108
113
|
) => Effect.Effect<BrowserRenderingBrowserClient<Browser, Page>, BrowserRenderingOperationError>;
|
|
109
|
-
readonly
|
|
114
|
+
readonly rawUnsafe: Effect.Effect<RawBinding>;
|
|
110
115
|
readonly definition: BrowserRenderingDefinition;
|
|
111
116
|
}
|
|
112
117
|
|
|
@@ -251,15 +256,33 @@ export const makeClient =
|
|
|
251
256
|
) =>
|
|
252
257
|
(binding: RawBinding): BrowserRenderingClient<RawBinding> => ({
|
|
253
258
|
definition,
|
|
254
|
-
launchWith:
|
|
259
|
+
launchWith: <
|
|
260
|
+
Browser extends BrowserRenderingBrowserLike<Page>,
|
|
261
|
+
Page extends BrowserRenderingPageLike = BrowserRenderingPageLike,
|
|
262
|
+
LaunchOptions = unknown,
|
|
263
|
+
>(
|
|
264
|
+
launch: BrowserRenderingLaunch<RawBinding, Browser, LaunchOptions>,
|
|
265
|
+
options?: LaunchOptions,
|
|
266
|
+
) =>
|
|
255
267
|
tryBrowserRenderingPromise(definition.binding, "launch", () => launch(binding, options)).pipe(
|
|
256
|
-
Effect.map((browser) => wrapBrowser(definition.binding, browser)),
|
|
268
|
+
Effect.map((browser) => wrapBrowser<Browser, Page>(definition.binding, browser)),
|
|
269
|
+
Effect.withSpan("BrowserRendering.launchWith"),
|
|
257
270
|
),
|
|
258
|
-
connectWith:
|
|
271
|
+
connectWith: <
|
|
272
|
+
Browser extends BrowserRenderingBrowserLike<Page>,
|
|
273
|
+
Page extends BrowserRenderingPageLike = BrowserRenderingPageLike,
|
|
274
|
+
ConnectOptions = unknown,
|
|
275
|
+
>(
|
|
276
|
+
connect: BrowserRenderingConnect<RawBinding, Browser, ConnectOptions>,
|
|
277
|
+
options?: ConnectOptions,
|
|
278
|
+
) =>
|
|
259
279
|
tryBrowserRenderingPromise(definition.binding, "connect", () =>
|
|
260
280
|
connect(binding, options),
|
|
261
|
-
).pipe(
|
|
262
|
-
|
|
281
|
+
).pipe(
|
|
282
|
+
Effect.map((browser) => wrapBrowser<Browser, Page>(definition.binding, browser)),
|
|
283
|
+
Effect.withSpan("BrowserRendering.connectWith"),
|
|
284
|
+
),
|
|
285
|
+
rawUnsafe: Effect.succeed(binding),
|
|
263
286
|
});
|
|
264
287
|
|
|
265
288
|
export const layer = <Self>(
|
package/src/Cache.ts
CHANGED
|
@@ -6,6 +6,8 @@ import type {
|
|
|
6
6
|
} from "@cloudflare/workers-types";
|
|
7
7
|
import { Context, Data, Effect, Layer, Option } from "effect";
|
|
8
8
|
|
|
9
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
10
|
+
|
|
9
11
|
/** Request key accepted by Cloudflare's Cache API. */
|
|
10
12
|
export type CacheRequest = CloudflareRequestInfo | URL;
|
|
11
13
|
|
|
@@ -20,7 +22,11 @@ export class CacheOperationError extends Data.TaggedError("CacheOperationError")
|
|
|
20
22
|
readonly cache: string;
|
|
21
23
|
readonly operation: CacheOperation;
|
|
22
24
|
readonly cause: unknown;
|
|
23
|
-
}> {
|
|
25
|
+
}> {
|
|
26
|
+
override get message(): string {
|
|
27
|
+
return `Cache ${this.operation} failed for cache "${this.cache}": ${ErrorMessage.causeMessage(this.cause)}`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
24
30
|
|
|
25
31
|
/** Effect wrapper around one Cloudflare `Cache` instance. */
|
|
26
32
|
export interface CacheClient {
|
|
@@ -42,7 +48,7 @@ export interface CacheClient {
|
|
|
42
48
|
options?: CacheQueryOptions,
|
|
43
49
|
) => Effect.Effect<boolean, CacheOperationError>;
|
|
44
50
|
/** Access to the native Cloudflare `Cache` instance. */
|
|
45
|
-
readonly
|
|
51
|
+
readonly rawUnsafe: Effect.Effect<CloudflareCache>;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/** Effect wrapper around Cloudflare's global `caches` object. */
|
|
@@ -52,7 +58,7 @@ export interface CacheStorageClient {
|
|
|
52
58
|
/** Opens a named cache. */
|
|
53
59
|
readonly open: (name: string) => Effect.Effect<CacheClient, CacheOperationError>;
|
|
54
60
|
/** Access to the native Cloudflare `CacheStorage` instance. */
|
|
55
|
-
readonly
|
|
61
|
+
readonly rawUnsafe: Effect.Effect<CloudflareCacheStorage>;
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/** Service for Cloudflare's global Cache API. */
|
|
@@ -73,17 +79,34 @@ const tryCachePromise = <A>(
|
|
|
73
79
|
catch: (cause) => cacheError(cache, operation, cause),
|
|
74
80
|
});
|
|
75
81
|
|
|
82
|
+
const spanOptions = (cache: string, operation: CacheOperation) => ({
|
|
83
|
+
attributes: { cache, operation },
|
|
84
|
+
});
|
|
85
|
+
|
|
76
86
|
/** Wraps a native Cloudflare `Cache` instance. */
|
|
77
87
|
export const makeCacheClient = (cache: CloudflareCache, name = "default"): CacheClient => ({
|
|
78
88
|
name,
|
|
79
|
-
match: (
|
|
89
|
+
match: Effect.fn(
|
|
90
|
+
"Cache.match",
|
|
91
|
+
spanOptions(name, "match"),
|
|
92
|
+
)((request: CacheRequest, options?: CacheQueryOptions) =>
|
|
80
93
|
tryCachePromise(name, "match", () => cache.match(request, options)).pipe(
|
|
81
94
|
Effect.map(Option.fromUndefinedOr),
|
|
82
95
|
),
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
),
|
|
97
|
+
put: Effect.fn(
|
|
98
|
+
"Cache.put",
|
|
99
|
+
spanOptions(name, "put"),
|
|
100
|
+
)((request: CacheRequest, response: Response) =>
|
|
101
|
+
tryCachePromise(name, "put", () => cache.put(request, response)),
|
|
102
|
+
),
|
|
103
|
+
delete: Effect.fn(
|
|
104
|
+
"Cache.delete",
|
|
105
|
+
spanOptions(name, "delete"),
|
|
106
|
+
)((request: CacheRequest, options?: CacheQueryOptions) =>
|
|
85
107
|
tryCachePromise(name, "delete", () => cache.delete(request, options)),
|
|
86
|
-
|
|
108
|
+
),
|
|
109
|
+
rawUnsafe: Effect.succeed(cache),
|
|
87
110
|
});
|
|
88
111
|
|
|
89
112
|
/** Wraps a native Cloudflare `CacheStorage` instance. */
|
|
@@ -92,8 +115,9 @@ export const makeClient = (storage: CloudflareCacheStorage): CacheStorageClient
|
|
|
92
115
|
open: (name) =>
|
|
93
116
|
tryCachePromise(name, "open", () => storage.open(name)).pipe(
|
|
94
117
|
Effect.map((cache) => makeCacheClient(cache, name)),
|
|
118
|
+
Effect.withSpan("Cache.open", spanOptions(name, "open")),
|
|
95
119
|
),
|
|
96
|
-
|
|
120
|
+
rawUnsafe: Effect.succeed(storage),
|
|
97
121
|
});
|
|
98
122
|
|
|
99
123
|
/** Provides Cache API services from an explicit native `CacheStorage` instance. */
|
package/src/CloudflareOtlp.ts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTLP telemetry layers for Cloudflare Workers and Durable Objects.
|
|
3
|
+
*
|
|
4
|
+
* Every layer exposes {@link OtlpExporter.Flusher}, which drains buffered
|
|
5
|
+
* telemetry on demand. Cloudflare isolates can freeze before the periodic
|
|
6
|
+
* export interval fires, so flush explicitly before returning a response, or
|
|
7
|
+
* hand the flush to `ctx.waitUntil`:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const flusher = yield* OtlpExporter.Flusher;
|
|
11
|
+
*
|
|
12
|
+
* yield* flusher.flush;
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
1
15
|
import { ConfigProvider, Effect, Layer, Option } from "effect";
|
|
2
16
|
import type * as Tracer from "effect/Tracer";
|
|
3
17
|
import { FetchHttpClient, type Headers } from "effect/unstable/http";
|
|
4
18
|
import {
|
|
19
|
+
OtlpExporter,
|
|
5
20
|
OtlpLogger,
|
|
6
21
|
OtlpMetrics,
|
|
7
22
|
OtlpSerialization,
|
|
@@ -138,7 +153,7 @@ const mergeSignalLayers = (layers: ReadonlyArray<SignalLayer>): SignalLayer => {
|
|
|
138
153
|
const makeLayer = (
|
|
139
154
|
options: LayerOptions = {},
|
|
140
155
|
runtimeAttributes: Record<string, unknown> = {},
|
|
141
|
-
): Layer.Layer<
|
|
156
|
+
): Layer.Layer<OtlpExporter.Flusher> => {
|
|
142
157
|
const signals = selectedSignals(options.signals);
|
|
143
158
|
const resource = makeResource(options, runtimeAttributes);
|
|
144
159
|
const layers: Array<SignalLayer> = [];
|
|
@@ -174,7 +189,7 @@ const makeLayer = (
|
|
|
174
189
|
}
|
|
175
190
|
|
|
176
191
|
if (layers.length === 0) {
|
|
177
|
-
return
|
|
192
|
+
return OtlpExporter.layerFlusher;
|
|
178
193
|
}
|
|
179
194
|
|
|
180
195
|
return mergeSignalLayers(layers).pipe(
|
|
@@ -191,16 +206,22 @@ const makeLayer = (
|
|
|
191
206
|
* layers. In Cloudflare Workers and Durable Objects, the current `env` object is
|
|
192
207
|
* installed as the primary `ConfigProvider`; outside Cloudflare, the ambient
|
|
193
208
|
* Effect `ConfigProvider` remains the fallback.
|
|
209
|
+
*
|
|
210
|
+
* The layer provides {@link OtlpExporter.Flusher} for draining buffered
|
|
211
|
+
* telemetry before the isolate freezes.
|
|
194
212
|
*/
|
|
195
|
-
export const layer = (options: LayerOptions = {}) =>
|
|
213
|
+
export const layer = (options: LayerOptions = {}): Layer.Layer<OtlpExporter.Flusher> =>
|
|
214
|
+
makeLayer(options);
|
|
196
215
|
|
|
197
216
|
/** Base OTLP telemetry layer forced to JSON serialization. */
|
|
198
|
-
export const layerJson = (
|
|
199
|
-
|
|
217
|
+
export const layerJson = (
|
|
218
|
+
options: Omit<LayerOptions, "serialization"> = {},
|
|
219
|
+
): Layer.Layer<OtlpExporter.Flusher> => layer({ ...options, serialization: "json" });
|
|
200
220
|
|
|
201
221
|
/** Base OTLP telemetry layer forced to protobuf serialization. */
|
|
202
|
-
export const layerProtobuf = (
|
|
203
|
-
|
|
222
|
+
export const layerProtobuf = (
|
|
223
|
+
options: Omit<LayerOptions, "serialization"> = {},
|
|
224
|
+
): Layer.Layer<OtlpExporter.Flusher> => layer({ ...options, serialization: "protobuf" });
|
|
204
225
|
|
|
205
226
|
/**
|
|
206
227
|
* OTLP layer with Cloudflare Worker resource attributes.
|
|
@@ -208,7 +229,7 @@ export const layerProtobuf = (options: Omit<LayerOptions, "serialization"> = {})
|
|
|
208
229
|
* Provide this layer at runtime scope for long-lived metrics aggregation, or at
|
|
209
230
|
* handler scope when traces/logs should flush as the Cloudflare event finishes.
|
|
210
231
|
*/
|
|
211
|
-
export const
|
|
232
|
+
export const layerWorker = (options: WorkerLayerOptions = {}): Layer.Layer<OtlpExporter.Flusher> =>
|
|
212
233
|
makeLayer(options, {
|
|
213
234
|
"cloudflare.resource_type": "worker",
|
|
214
235
|
"cloudflare.worker.name": options.workerName,
|
|
@@ -221,7 +242,9 @@ export const workerLayer = (options: WorkerLayerOptions = {}) =>
|
|
|
221
242
|
* Durable Object id. Prefer leaving `includeObjectId` disabled unless the
|
|
222
243
|
* backend can tolerate high-cardinality resource attributes.
|
|
223
244
|
*/
|
|
224
|
-
export const
|
|
245
|
+
export const layerDurableObject = (
|
|
246
|
+
options: DurableObjectLayerOptions = {},
|
|
247
|
+
): Layer.Layer<OtlpExporter.Flusher, never, DurableObjectState> =>
|
|
225
248
|
Layer.unwrap(
|
|
226
249
|
Effect.map(DurableObjectState, (state) =>
|
|
227
250
|
makeLayer(options, {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Context, Data, Effect, Schema, type Layer } from "effect";
|
|
1
|
+
import { Context, Data, Effect, Schema as S, type Layer } from "effect";
|
|
2
2
|
|
|
3
3
|
import * as Binding from "./Binding";
|
|
4
4
|
import type { WorkerEnvironment } from "./Environment";
|
|
5
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
5
6
|
|
|
6
7
|
const expectedContainerNamespace = "Container namespace binding with getByName()";
|
|
7
8
|
|
|
@@ -38,15 +39,15 @@ export interface ContainerStartAndWaitForPortsOptions {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/** Serializable state reported by a Cloudflare Container instance. */
|
|
41
|
-
export const ContainerState =
|
|
42
|
-
|
|
43
|
-
lastChange:
|
|
44
|
-
status:
|
|
42
|
+
export const ContainerState = S.Union([
|
|
43
|
+
S.Struct({
|
|
44
|
+
lastChange: S.Finite,
|
|
45
|
+
status: S.Literals(["running", "stopping", "stopped", "healthy"]),
|
|
45
46
|
}),
|
|
46
|
-
|
|
47
|
-
lastChange:
|
|
48
|
-
status:
|
|
49
|
-
exitCode:
|
|
47
|
+
S.Struct({
|
|
48
|
+
lastChange: S.Finite,
|
|
49
|
+
status: S.Literal("stopped_with_code"),
|
|
50
|
+
exitCode: S.optionalKey(S.Int),
|
|
50
51
|
}),
|
|
51
52
|
]);
|
|
52
53
|
export type ContainerState = typeof ContainerState.Type;
|
|
@@ -86,11 +87,15 @@ export class ContainerOperationError extends Data.TaggedError("ContainerOperatio
|
|
|
86
87
|
readonly instance: string;
|
|
87
88
|
readonly operation: string;
|
|
88
89
|
readonly cause: unknown;
|
|
89
|
-
}> {
|
|
90
|
+
}> {
|
|
91
|
+
override get message(): string {
|
|
92
|
+
return `Container ${this.operation} failed for binding "${this.binding}" instance "${this.instance}": ${ErrorMessage.causeMessage(this.cause)}`;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
90
95
|
|
|
91
96
|
/** Effect-wrapped client for one named Container instance. */
|
|
92
97
|
export interface ContainerInstanceClient {
|
|
93
|
-
readonly
|
|
98
|
+
readonly rawUnsafe: Effect.Effect<ContainerStub, ContainerOperationError>;
|
|
94
99
|
readonly state: Effect.Effect<ContainerState, ContainerOperationError>;
|
|
95
100
|
readonly fetch: (
|
|
96
101
|
input: RequestInfo | URL,
|
|
@@ -118,7 +123,7 @@ export interface ContainerNamespaceClient {
|
|
|
118
123
|
name: string,
|
|
119
124
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
120
125
|
) => ContainerInstanceClient;
|
|
121
|
-
readonly
|
|
126
|
+
readonly rawUnsafe: Effect.Effect<ContainerNamespaceResource>;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
export type ContainerNamespaceStaticClient<R> = {
|
|
@@ -144,9 +149,9 @@ export type ContainerNamespaceStaticClient<R> = {
|
|
|
144
149
|
) => Effect.Effect<void, ContainerOperationError, R>;
|
|
145
150
|
readonly stop: (signal?: ContainerSignal) => Effect.Effect<void, ContainerOperationError, R>;
|
|
146
151
|
readonly destroy: Effect.Effect<void, ContainerOperationError, R>;
|
|
147
|
-
readonly
|
|
152
|
+
readonly rawUnsafe: Effect.Effect<ContainerStub, ContainerOperationError, R>;
|
|
148
153
|
};
|
|
149
|
-
readonly
|
|
154
|
+
readonly rawUnsafe: Effect.Effect<ContainerNamespaceResource, never, R>;
|
|
150
155
|
};
|
|
151
156
|
|
|
152
157
|
export type LayerOptions = {
|
|
@@ -155,7 +160,7 @@ export type LayerOptions = {
|
|
|
155
160
|
|
|
156
161
|
export interface TagClass<Self, Id extends string>
|
|
157
162
|
extends
|
|
158
|
-
Context.ServiceClass<Self, Id
|
|
163
|
+
Context.ServiceClass<Self, `effect-cf/Container/${Id}`, ContainerNamespaceClient>,
|
|
159
164
|
ContainerNamespaceStaticClient<Self> {
|
|
160
165
|
readonly id: Id;
|
|
161
166
|
readonly layer: (
|
|
@@ -188,32 +193,62 @@ const makeInstanceClient = (
|
|
|
188
193
|
definition: ContainerNamespaceDefinition,
|
|
189
194
|
instance: string,
|
|
190
195
|
stub: ContainerStub,
|
|
191
|
-
): ContainerInstanceClient =>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
196
|
+
): ContainerInstanceClient => {
|
|
197
|
+
const spanOptions = (operation: string) => ({
|
|
198
|
+
attributes: { binding: definition.binding, instance, operation },
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
rawUnsafe: Effect.succeed(stub),
|
|
203
|
+
state: tryContainerPromise(definition, instance, "state", () => stub.getState()).pipe(
|
|
204
|
+
Effect.flatMap(S.decodeUnknownEffect(ContainerState)),
|
|
205
|
+
Effect.mapError((cause) =>
|
|
206
|
+
cause instanceof ContainerOperationError
|
|
207
|
+
? cause
|
|
208
|
+
: new ContainerOperationError({
|
|
209
|
+
binding: definition.binding,
|
|
210
|
+
instance,
|
|
211
|
+
operation: "state",
|
|
212
|
+
cause,
|
|
213
|
+
}),
|
|
214
|
+
),
|
|
215
|
+
Effect.withSpan("ContainerNamespace.state", spanOptions("state")),
|
|
204
216
|
),
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
217
|
+
fetch: Effect.fn(
|
|
218
|
+
"ContainerNamespace.fetch",
|
|
219
|
+
spanOptions("fetch"),
|
|
220
|
+
)(function* (input: RequestInfo | URL, init?: RequestInit) {
|
|
221
|
+
return yield* tryContainerPromise(definition, instance, "fetch", () =>
|
|
222
|
+
stub.fetch(input, init),
|
|
223
|
+
);
|
|
224
|
+
}),
|
|
225
|
+
start: Effect.fn(
|
|
226
|
+
"ContainerNamespace.start",
|
|
227
|
+
spanOptions("start"),
|
|
228
|
+
)(function* (options?: ContainerStartOptions, waitOptions?: ContainerWaitOptions) {
|
|
229
|
+
return yield* tryContainerPromise(definition, instance, "start", () =>
|
|
230
|
+
stub.start(options, waitOptions),
|
|
231
|
+
);
|
|
232
|
+
}),
|
|
233
|
+
startAndWaitForPorts: Effect.fn(
|
|
234
|
+
"ContainerNamespace.startAndWaitForPorts",
|
|
235
|
+
spanOptions("startAndWaitForPorts"),
|
|
236
|
+
)(function* (options?: ContainerStartAndWaitForPortsOptions) {
|
|
237
|
+
return yield* tryContainerPromise(definition, instance, "startAndWaitForPorts", () =>
|
|
238
|
+
stub.startAndWaitForPorts(options),
|
|
239
|
+
);
|
|
240
|
+
}),
|
|
241
|
+
stop: Effect.fn(
|
|
242
|
+
"ContainerNamespace.stop",
|
|
243
|
+
spanOptions("stop"),
|
|
244
|
+
)(function* (signal?: ContainerSignal) {
|
|
245
|
+
return yield* tryContainerPromise(definition, instance, "stop", () => stub.stop(signal));
|
|
246
|
+
}),
|
|
247
|
+
destroy: tryContainerPromise(definition, instance, "destroy", () => stub.destroy()).pipe(
|
|
248
|
+
Effect.withSpan("ContainerNamespace.destroy", spanOptions("destroy")),
|
|
213
249
|
),
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
});
|
|
250
|
+
};
|
|
251
|
+
};
|
|
217
252
|
|
|
218
253
|
export const isContainerNamespaceResource = (value: unknown): value is ContainerNamespaceResource =>
|
|
219
254
|
typeof value === "object" &&
|
|
@@ -245,7 +280,7 @@ export const makeClient =
|
|
|
245
280
|
const instance = getByName(name, options);
|
|
246
281
|
|
|
247
282
|
return {
|
|
248
|
-
|
|
283
|
+
rawUnsafe: Effect.flatMap(instance, (client) => client.rawUnsafe),
|
|
249
284
|
state: Effect.flatMap(instance, (client) => client.state),
|
|
250
285
|
fetch: (input, init) => Effect.flatMap(instance, (client) => client.fetch(input, init)),
|
|
251
286
|
start: (startOptions, waitOptions) =>
|
|
@@ -261,7 +296,7 @@ export const makeClient =
|
|
|
261
296
|
definition,
|
|
262
297
|
getByName,
|
|
263
298
|
byName,
|
|
264
|
-
|
|
299
|
+
rawUnsafe: Effect.succeed(namespace),
|
|
265
300
|
};
|
|
266
301
|
};
|
|
267
302
|
|
|
@@ -288,18 +323,19 @@ export interface ContainerNamespaceService<Id extends string> {
|
|
|
288
323
|
export const Tag =
|
|
289
324
|
<Self>() =>
|
|
290
325
|
<Id extends string>(id: Id) => {
|
|
291
|
-
const tag = Context.Service<Self, ContainerNamespaceClient>()(
|
|
326
|
+
const tag = Context.Service<Self, ContainerNamespaceClient>()(
|
|
327
|
+
`effect-cf/Container/${id}` as const,
|
|
328
|
+
);
|
|
292
329
|
const makeLayer = (definition: LayerOptions) => layer(tag, definition);
|
|
293
330
|
|
|
294
|
-
const getByName = (
|
|
331
|
+
const getByName = Effect.fnUntraced(function* (
|
|
295
332
|
name: string,
|
|
296
333
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
const namespace = yield* tag;
|
|
334
|
+
) {
|
|
335
|
+
const namespace = yield* tag;
|
|
300
336
|
|
|
301
|
-
|
|
302
|
-
|
|
337
|
+
return yield* namespace.getByName(name, options);
|
|
338
|
+
});
|
|
303
339
|
|
|
304
340
|
const byName = (
|
|
305
341
|
name: string,
|
|
@@ -319,21 +355,17 @@ export const Tag =
|
|
|
319
355
|
stop: (signal?: ContainerSignal) =>
|
|
320
356
|
Effect.flatMap(getByName(name, options), (instance) => instance.stop(signal)),
|
|
321
357
|
destroy: Effect.flatMap(getByName(name, options), (instance) => instance.destroy),
|
|
322
|
-
|
|
358
|
+
rawUnsafe: Effect.flatMap(getByName(name, options), (instance) => instance.rawUnsafe),
|
|
323
359
|
});
|
|
324
360
|
|
|
325
|
-
const
|
|
326
|
-
const namespace = yield* tag;
|
|
327
|
-
|
|
328
|
-
return yield* namespace.unsafeRaw;
|
|
329
|
-
});
|
|
361
|
+
const rawUnsafe = Effect.flatMap(tag, (namespace) => namespace.rawUnsafe);
|
|
330
362
|
|
|
331
363
|
return Object.assign(tag, {
|
|
332
364
|
id,
|
|
333
365
|
layer: makeLayer,
|
|
334
366
|
getByName,
|
|
335
367
|
byName,
|
|
336
|
-
|
|
368
|
+
rawUnsafe,
|
|
337
369
|
}) as TagClass<Self, Id>;
|
|
338
370
|
};
|
|
339
371
|
|
package/src/D1.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { D1Client } from "@effect/sql-d1";
|
|
2
|
-
import { Effect, Layer } from "effect";
|
|
2
|
+
import { Effect, Layer, type Config } from "effect";
|
|
3
|
+
import type { SqlClient } from "effect/unstable/sql";
|
|
3
4
|
|
|
4
5
|
import * as Binding from "./Binding";
|
|
6
|
+
import type { WorkerEnvironment } from "./Environment";
|
|
5
7
|
|
|
6
|
-
const TypeId = "effect-cf/D1" as const;
|
|
8
|
+
const TypeId = "~effect-cf/D1" as const;
|
|
9
|
+
|
|
10
|
+
export type TypeId = typeof TypeId;
|
|
7
11
|
const expectedD1Database = "D1 database binding with prepare(), batch(), and exec()";
|
|
8
12
|
|
|
9
13
|
/** Typed D1 binding definition. */
|
|
@@ -66,7 +70,13 @@ export const Service =
|
|
|
66
70
|
expected: expectedD1Database,
|
|
67
71
|
});
|
|
68
72
|
|
|
69
|
-
const sqlLayer = (
|
|
73
|
+
const sqlLayer = (
|
|
74
|
+
options?: D1SqlLayerOptions,
|
|
75
|
+
): Layer.Layer<
|
|
76
|
+
D1Client.D1Client | SqlClient.SqlClient,
|
|
77
|
+
Config.ConfigError | Binding.BindingNotFoundError | Binding.BindingValidationError,
|
|
78
|
+
WorkerEnvironment
|
|
79
|
+
> =>
|
|
70
80
|
Layer.unwrap(
|
|
71
81
|
Effect.gen(function* () {
|
|
72
82
|
const db = yield* tag;
|