effect-cf 0.20.1 → 0.23.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 +52 -0
- package/README.md +27 -3
- 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 +1113 -922
- package/dist/index.mjs +980 -604
- 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 +251 -80
- 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 +63 -39
- 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 +39 -17
- package/src/Entry.ts +0 -259
- package/src/internal/Clock.ts +0 -37
|
@@ -1,13 +1,17 @@
|
|
|
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
|
|
|
8
|
-
/**
|
|
9
|
+
/** Named signal accepted by Cloudflare Container instances. */
|
|
9
10
|
export type ContainerSignal = "SIGKILL" | "SIGINT" | "SIGTERM";
|
|
10
11
|
|
|
12
|
+
/** Named or numeric signal accepted by Container `stop()`. */
|
|
13
|
+
export type ContainerStopSignal = ContainerSignal | number;
|
|
14
|
+
|
|
11
15
|
/** Per-instance Container startup configuration. */
|
|
12
16
|
export interface ContainerStartOptions {
|
|
13
17
|
readonly envVars?: Record<string, string>;
|
|
@@ -38,15 +42,15 @@ export interface ContainerStartAndWaitForPortsOptions {
|
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
/** Serializable state reported by a Cloudflare Container instance. */
|
|
41
|
-
export const ContainerState =
|
|
42
|
-
|
|
43
|
-
lastChange:
|
|
44
|
-
status:
|
|
45
|
+
export const ContainerState = S.Union([
|
|
46
|
+
S.Struct({
|
|
47
|
+
lastChange: S.Finite,
|
|
48
|
+
status: S.Literals(["running", "stopping", "stopped", "healthy"]),
|
|
45
49
|
}),
|
|
46
|
-
|
|
47
|
-
lastChange:
|
|
48
|
-
status:
|
|
49
|
-
exitCode:
|
|
50
|
+
S.Struct({
|
|
51
|
+
lastChange: S.Finite,
|
|
52
|
+
status: S.Literal("stopped_with_code"),
|
|
53
|
+
exitCode: S.optionalKey(S.Int),
|
|
50
54
|
}),
|
|
51
55
|
]);
|
|
52
56
|
export type ContainerState = typeof ContainerState.Type;
|
|
@@ -62,8 +66,15 @@ export interface ContainerStub {
|
|
|
62
66
|
getState(): Promise<ContainerState>;
|
|
63
67
|
start(options?: ContainerStartOptions, waitOptions?: ContainerWaitOptions): Promise<void>;
|
|
64
68
|
startAndWaitForPorts(options?: ContainerStartAndWaitForPortsOptions): Promise<void>;
|
|
65
|
-
|
|
69
|
+
waitForPort(options: ContainerWaitOptions): Promise<number>;
|
|
70
|
+
stop(signal?: ContainerStopSignal): Promise<void>;
|
|
66
71
|
destroy(): Promise<void>;
|
|
72
|
+
setAllowedHosts(hosts: Array<string>): Promise<void>;
|
|
73
|
+
setDeniedHosts(hosts: Array<string>): Promise<void>;
|
|
74
|
+
allowHost(hostname: string): Promise<void>;
|
|
75
|
+
denyHost(hostname: string): Promise<void>;
|
|
76
|
+
removeAllowedHost(hostname: string): Promise<void>;
|
|
77
|
+
removeDeniedHost(hostname: string): Promise<void>;
|
|
67
78
|
}
|
|
68
79
|
|
|
69
80
|
/** Native Container namespace binding shape. */
|
|
@@ -74,6 +85,11 @@ export interface ContainerNamespaceResource {
|
|
|
74
85
|
): ContainerStub;
|
|
75
86
|
}
|
|
76
87
|
|
|
88
|
+
/** Exact native stub type produced by a Container namespace binding. */
|
|
89
|
+
export type ContainerStubOf<Namespace extends ContainerNamespaceResource> = ReturnType<
|
|
90
|
+
Namespace["getByName"]
|
|
91
|
+
>;
|
|
92
|
+
|
|
77
93
|
/** Container namespace binding metadata. */
|
|
78
94
|
export interface ContainerNamespaceDefinition {
|
|
79
95
|
/** Binding name as configured in `wrangler.jsonc`. */
|
|
@@ -86,11 +102,15 @@ export class ContainerOperationError extends Data.TaggedError("ContainerOperatio
|
|
|
86
102
|
readonly instance: string;
|
|
87
103
|
readonly operation: string;
|
|
88
104
|
readonly cause: unknown;
|
|
89
|
-
}> {
|
|
105
|
+
}> {
|
|
106
|
+
override get message(): string {
|
|
107
|
+
return `Container ${this.operation} failed for binding "${this.binding}" instance "${this.instance}": ${ErrorMessage.causeMessage(this.cause)}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
90
110
|
|
|
91
111
|
/** Effect-wrapped client for one named Container instance. */
|
|
92
|
-
export interface ContainerInstanceClient {
|
|
93
|
-
readonly
|
|
112
|
+
export interface ContainerInstanceClient<Stub extends ContainerStub = ContainerStub> {
|
|
113
|
+
readonly rawUnsafe: Effect.Effect<Stub, ContainerOperationError>;
|
|
94
114
|
readonly state: Effect.Effect<ContainerState, ContainerOperationError>;
|
|
95
115
|
readonly fetch: (
|
|
96
116
|
input: RequestInfo | URL,
|
|
@@ -103,29 +123,51 @@ export interface ContainerInstanceClient {
|
|
|
103
123
|
readonly startAndWaitForPorts: (
|
|
104
124
|
options?: ContainerStartAndWaitForPortsOptions,
|
|
105
125
|
) => Effect.Effect<void, ContainerOperationError>;
|
|
106
|
-
readonly
|
|
126
|
+
readonly waitForPort: (
|
|
127
|
+
options: ContainerWaitOptions,
|
|
128
|
+
) => Effect.Effect<number, ContainerOperationError>;
|
|
129
|
+
readonly stop: (signal?: ContainerStopSignal) => Effect.Effect<void, ContainerOperationError>;
|
|
107
130
|
readonly destroy: Effect.Effect<void, ContainerOperationError>;
|
|
131
|
+
readonly setAllowedHosts: (
|
|
132
|
+
hosts: ReadonlyArray<string>,
|
|
133
|
+
) => Effect.Effect<void, ContainerOperationError>;
|
|
134
|
+
readonly setDeniedHosts: (
|
|
135
|
+
hosts: ReadonlyArray<string>,
|
|
136
|
+
) => Effect.Effect<void, ContainerOperationError>;
|
|
137
|
+
readonly allowHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
138
|
+
readonly denyHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
139
|
+
readonly removeAllowedHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
140
|
+
readonly removeDeniedHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
108
141
|
}
|
|
109
142
|
|
|
110
143
|
/** Effect client for a Container namespace binding. */
|
|
111
|
-
export interface ContainerNamespaceClient
|
|
144
|
+
export interface ContainerNamespaceClient<
|
|
145
|
+
Namespace extends ContainerNamespaceResource = ContainerNamespaceResource,
|
|
146
|
+
> {
|
|
112
147
|
readonly definition: ContainerNamespaceDefinition;
|
|
113
148
|
readonly getByName: (
|
|
114
149
|
name: string,
|
|
115
150
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
116
|
-
) => Effect.Effect<ContainerInstanceClient
|
|
151
|
+
) => Effect.Effect<ContainerInstanceClient<ContainerStubOf<Namespace>>, ContainerOperationError>;
|
|
117
152
|
readonly byName: (
|
|
118
153
|
name: string,
|
|
119
154
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
120
|
-
) => ContainerInstanceClient
|
|
121
|
-
readonly
|
|
155
|
+
) => ContainerInstanceClient<ContainerStubOf<Namespace>>;
|
|
156
|
+
readonly rawUnsafe: Effect.Effect<Namespace>;
|
|
122
157
|
}
|
|
123
158
|
|
|
124
|
-
export type ContainerNamespaceStaticClient<
|
|
159
|
+
export type ContainerNamespaceStaticClient<
|
|
160
|
+
R,
|
|
161
|
+
Namespace extends ContainerNamespaceResource = ContainerNamespaceResource,
|
|
162
|
+
> = {
|
|
125
163
|
readonly getByName: (
|
|
126
164
|
name: string,
|
|
127
165
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
128
|
-
) => Effect.Effect<
|
|
166
|
+
) => Effect.Effect<
|
|
167
|
+
ContainerInstanceClient<ContainerStubOf<Namespace>>,
|
|
168
|
+
ContainerOperationError,
|
|
169
|
+
R
|
|
170
|
+
>;
|
|
129
171
|
readonly byName: (
|
|
130
172
|
name: string,
|
|
131
173
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
@@ -142,21 +184,44 @@ export type ContainerNamespaceStaticClient<R> = {
|
|
|
142
184
|
readonly startAndWaitForPorts: (
|
|
143
185
|
options?: ContainerStartAndWaitForPortsOptions,
|
|
144
186
|
) => Effect.Effect<void, ContainerOperationError, R>;
|
|
145
|
-
readonly
|
|
187
|
+
readonly waitForPort: (
|
|
188
|
+
options: ContainerWaitOptions,
|
|
189
|
+
) => Effect.Effect<number, ContainerOperationError, R>;
|
|
190
|
+
readonly stop: (
|
|
191
|
+
signal?: ContainerStopSignal,
|
|
192
|
+
) => Effect.Effect<void, ContainerOperationError, R>;
|
|
146
193
|
readonly destroy: Effect.Effect<void, ContainerOperationError, R>;
|
|
147
|
-
readonly
|
|
194
|
+
readonly setAllowedHosts: (
|
|
195
|
+
hosts: ReadonlyArray<string>,
|
|
196
|
+
) => Effect.Effect<void, ContainerOperationError, R>;
|
|
197
|
+
readonly setDeniedHosts: (
|
|
198
|
+
hosts: ReadonlyArray<string>,
|
|
199
|
+
) => Effect.Effect<void, ContainerOperationError, R>;
|
|
200
|
+
readonly allowHost: (hostname: string) => Effect.Effect<void, ContainerOperationError, R>;
|
|
201
|
+
readonly denyHost: (hostname: string) => Effect.Effect<void, ContainerOperationError, R>;
|
|
202
|
+
readonly removeAllowedHost: (
|
|
203
|
+
hostname: string,
|
|
204
|
+
) => Effect.Effect<void, ContainerOperationError, R>;
|
|
205
|
+
readonly removeDeniedHost: (
|
|
206
|
+
hostname: string,
|
|
207
|
+
) => Effect.Effect<void, ContainerOperationError, R>;
|
|
208
|
+
readonly rawUnsafe: Effect.Effect<ContainerStubOf<Namespace>, ContainerOperationError, R>;
|
|
148
209
|
};
|
|
149
|
-
readonly
|
|
210
|
+
readonly rawUnsafe: Effect.Effect<Namespace, never, R>;
|
|
150
211
|
};
|
|
151
212
|
|
|
152
213
|
export type LayerOptions = {
|
|
153
214
|
readonly binding: string;
|
|
154
215
|
};
|
|
155
216
|
|
|
156
|
-
export interface TagClass<
|
|
217
|
+
export interface TagClass<
|
|
218
|
+
Self,
|
|
219
|
+
Id extends string,
|
|
220
|
+
Namespace extends ContainerNamespaceResource = ContainerNamespaceResource,
|
|
221
|
+
>
|
|
157
222
|
extends
|
|
158
|
-
Context.ServiceClass<Self, Id
|
|
159
|
-
ContainerNamespaceStaticClient<Self> {
|
|
223
|
+
Context.ServiceClass<Self, `effect-cf/Container/${Id}`, ContainerNamespaceClient<Namespace>>,
|
|
224
|
+
ContainerNamespaceStaticClient<Self, Namespace> {
|
|
160
225
|
readonly id: Id;
|
|
161
226
|
readonly layer: (
|
|
162
227
|
options: LayerOptions,
|
|
@@ -184,36 +249,100 @@ const tryContainerPromise = <A>(
|
|
|
184
249
|
}),
|
|
185
250
|
});
|
|
186
251
|
|
|
187
|
-
const makeInstanceClient = (
|
|
252
|
+
const makeInstanceClient = <Stub extends ContainerStub>(
|
|
188
253
|
definition: ContainerNamespaceDefinition,
|
|
189
254
|
instance: string,
|
|
190
|
-
stub:
|
|
191
|
-
): ContainerInstanceClient =>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
255
|
+
stub: Stub,
|
|
256
|
+
): ContainerInstanceClient<Stub> => {
|
|
257
|
+
const spanOptions = (operation: string) => ({
|
|
258
|
+
attributes: { binding: definition.binding, instance, operation },
|
|
259
|
+
});
|
|
260
|
+
const hostListOperation = (operation: "setAllowedHosts" | "setDeniedHosts") =>
|
|
261
|
+
Effect.fn(
|
|
262
|
+
`ContainerNamespace.${operation}`,
|
|
263
|
+
spanOptions(operation),
|
|
264
|
+
)(function* (hosts: ReadonlyArray<string>) {
|
|
265
|
+
return yield* tryContainerPromise(definition, instance, operation, () =>
|
|
266
|
+
stub[operation]([...hosts]),
|
|
267
|
+
);
|
|
268
|
+
});
|
|
269
|
+
const hostnameOperation = (
|
|
270
|
+
operation: "allowHost" | "denyHost" | "removeAllowedHost" | "removeDeniedHost",
|
|
271
|
+
) =>
|
|
272
|
+
Effect.fn(
|
|
273
|
+
`ContainerNamespace.${operation}`,
|
|
274
|
+
spanOptions(operation),
|
|
275
|
+
)(function* (hostname: string) {
|
|
276
|
+
return yield* tryContainerPromise(definition, instance, operation, () =>
|
|
277
|
+
stub[operation](hostname),
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
rawUnsafe: Effect.succeed(stub),
|
|
283
|
+
state: tryContainerPromise(definition, instance, "state", () => stub.getState()).pipe(
|
|
284
|
+
Effect.flatMap(S.decodeUnknownEffect(ContainerState)),
|
|
285
|
+
Effect.mapError((cause) =>
|
|
286
|
+
cause instanceof ContainerOperationError
|
|
287
|
+
? cause
|
|
288
|
+
: new ContainerOperationError({
|
|
289
|
+
binding: definition.binding,
|
|
290
|
+
instance,
|
|
291
|
+
operation: "state",
|
|
292
|
+
cause,
|
|
293
|
+
}),
|
|
294
|
+
),
|
|
295
|
+
Effect.withSpan("ContainerNamespace.state", spanOptions("state")),
|
|
204
296
|
),
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
297
|
+
fetch: Effect.fn(
|
|
298
|
+
"ContainerNamespace.fetch",
|
|
299
|
+
spanOptions("fetch"),
|
|
300
|
+
)(function* (input: RequestInfo | URL, init?: RequestInit) {
|
|
301
|
+
return yield* tryContainerPromise(definition, instance, "fetch", () =>
|
|
302
|
+
stub.fetch(input, init),
|
|
303
|
+
);
|
|
304
|
+
}),
|
|
305
|
+
start: Effect.fn(
|
|
306
|
+
"ContainerNamespace.start",
|
|
307
|
+
spanOptions("start"),
|
|
308
|
+
)(function* (options?: ContainerStartOptions, waitOptions?: ContainerWaitOptions) {
|
|
309
|
+
return yield* tryContainerPromise(definition, instance, "start", () =>
|
|
310
|
+
stub.start(options, waitOptions),
|
|
311
|
+
);
|
|
312
|
+
}),
|
|
313
|
+
startAndWaitForPorts: Effect.fn(
|
|
314
|
+
"ContainerNamespace.startAndWaitForPorts",
|
|
315
|
+
spanOptions("startAndWaitForPorts"),
|
|
316
|
+
)(function* (options?: ContainerStartAndWaitForPortsOptions) {
|
|
317
|
+
return yield* tryContainerPromise(definition, instance, "startAndWaitForPorts", () =>
|
|
318
|
+
stub.startAndWaitForPorts(options),
|
|
319
|
+
);
|
|
320
|
+
}),
|
|
321
|
+
waitForPort: Effect.fn(
|
|
322
|
+
"ContainerNamespace.waitForPort",
|
|
323
|
+
spanOptions("waitForPort"),
|
|
324
|
+
)(function* (options: ContainerWaitOptions) {
|
|
325
|
+
return yield* tryContainerPromise(definition, instance, "waitForPort", () =>
|
|
326
|
+
stub.waitForPort(options),
|
|
327
|
+
);
|
|
328
|
+
}),
|
|
329
|
+
stop: Effect.fn(
|
|
330
|
+
"ContainerNamespace.stop",
|
|
331
|
+
spanOptions("stop"),
|
|
332
|
+
)(function* (signal?: ContainerStopSignal) {
|
|
333
|
+
return yield* tryContainerPromise(definition, instance, "stop", () => stub.stop(signal));
|
|
334
|
+
}),
|
|
335
|
+
destroy: tryContainerPromise(definition, instance, "destroy", () => stub.destroy()).pipe(
|
|
336
|
+
Effect.withSpan("ContainerNamespace.destroy", spanOptions("destroy")),
|
|
213
337
|
),
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
338
|
+
setAllowedHosts: hostListOperation("setAllowedHosts"),
|
|
339
|
+
setDeniedHosts: hostListOperation("setDeniedHosts"),
|
|
340
|
+
allowHost: hostnameOperation("allowHost"),
|
|
341
|
+
denyHost: hostnameOperation("denyHost"),
|
|
342
|
+
removeAllowedHost: hostnameOperation("removeAllowedHost"),
|
|
343
|
+
removeDeniedHost: hostnameOperation("removeDeniedHost"),
|
|
344
|
+
};
|
|
345
|
+
};
|
|
217
346
|
|
|
218
347
|
export const isContainerNamespaceResource = (value: unknown): value is ContainerNamespaceResource =>
|
|
219
348
|
typeof value === "object" &&
|
|
@@ -222,13 +351,22 @@ export const isContainerNamespaceResource = (value: unknown): value is Container
|
|
|
222
351
|
|
|
223
352
|
export const makeClient =
|
|
224
353
|
(definition: ContainerNamespaceDefinition) =>
|
|
225
|
-
|
|
354
|
+
<Namespace extends ContainerNamespaceResource>(
|
|
355
|
+
namespace: Namespace,
|
|
356
|
+
): ContainerNamespaceClient<Namespace> => {
|
|
226
357
|
const getByName = (
|
|
227
358
|
name: string,
|
|
228
359
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
229
360
|
) =>
|
|
230
361
|
Effect.try({
|
|
231
|
-
try: () =>
|
|
362
|
+
try: () =>
|
|
363
|
+
makeInstanceClient(
|
|
364
|
+
definition,
|
|
365
|
+
name,
|
|
366
|
+
// getByName has a single call signature, so its return type is
|
|
367
|
+
// exactly the namespace's stub type.
|
|
368
|
+
namespace.getByName(name, options) as ContainerStubOf<Namespace>,
|
|
369
|
+
),
|
|
232
370
|
catch: (cause) =>
|
|
233
371
|
new ContainerOperationError({
|
|
234
372
|
binding: definition.binding,
|
|
@@ -241,19 +379,31 @@ export const makeClient =
|
|
|
241
379
|
const byName = (
|
|
242
380
|
name: string,
|
|
243
381
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
244
|
-
): ContainerInstanceClient => {
|
|
382
|
+
): ContainerInstanceClient<ContainerStubOf<Namespace>> => {
|
|
245
383
|
const instance = getByName(name, options);
|
|
246
384
|
|
|
247
385
|
return {
|
|
248
|
-
|
|
386
|
+
rawUnsafe: Effect.flatMap(instance, (client) => client.rawUnsafe),
|
|
249
387
|
state: Effect.flatMap(instance, (client) => client.state),
|
|
250
388
|
fetch: (input, init) => Effect.flatMap(instance, (client) => client.fetch(input, init)),
|
|
251
389
|
start: (startOptions, waitOptions) =>
|
|
252
390
|
Effect.flatMap(instance, (client) => client.start(startOptions, waitOptions)),
|
|
253
391
|
startAndWaitForPorts: (startOptions) =>
|
|
254
392
|
Effect.flatMap(instance, (client) => client.startAndWaitForPorts(startOptions)),
|
|
393
|
+
waitForPort: (waitOptions) =>
|
|
394
|
+
Effect.flatMap(instance, (client) => client.waitForPort(waitOptions)),
|
|
255
395
|
stop: (signal) => Effect.flatMap(instance, (client) => client.stop(signal)),
|
|
256
396
|
destroy: Effect.flatMap(instance, (client) => client.destroy),
|
|
397
|
+
setAllowedHosts: (hosts) =>
|
|
398
|
+
Effect.flatMap(instance, (client) => client.setAllowedHosts(hosts)),
|
|
399
|
+
setDeniedHosts: (hosts) =>
|
|
400
|
+
Effect.flatMap(instance, (client) => client.setDeniedHosts(hosts)),
|
|
401
|
+
allowHost: (hostname) => Effect.flatMap(instance, (client) => client.allowHost(hostname)),
|
|
402
|
+
denyHost: (hostname) => Effect.flatMap(instance, (client) => client.denyHost(hostname)),
|
|
403
|
+
removeAllowedHost: (hostname) =>
|
|
404
|
+
Effect.flatMap(instance, (client) => client.removeAllowedHost(hostname)),
|
|
405
|
+
removeDeniedHost: (hostname) =>
|
|
406
|
+
Effect.flatMap(instance, (client) => client.removeDeniedHost(hostname)),
|
|
257
407
|
};
|
|
258
408
|
};
|
|
259
409
|
|
|
@@ -261,17 +411,25 @@ export const makeClient =
|
|
|
261
411
|
definition,
|
|
262
412
|
getByName,
|
|
263
413
|
byName,
|
|
264
|
-
|
|
414
|
+
rawUnsafe: Effect.succeed(namespace),
|
|
265
415
|
};
|
|
266
416
|
};
|
|
267
417
|
|
|
268
|
-
export const layer = <Self>(
|
|
269
|
-
tag: Context.Service<Self, ContainerNamespaceClient
|
|
418
|
+
export const layer = <Self, Namespace extends ContainerNamespaceResource>(
|
|
419
|
+
tag: Context.Service<Self, ContainerNamespaceClient<Namespace>>,
|
|
270
420
|
definition: ContainerNamespaceDefinition,
|
|
271
421
|
) =>
|
|
272
|
-
Binding.layer(
|
|
273
|
-
|
|
274
|
-
|
|
422
|
+
Binding.layer(
|
|
423
|
+
tag,
|
|
424
|
+
definition.binding,
|
|
425
|
+
// Runtime validation stays structural; the exact namespace type is
|
|
426
|
+
// asserted by the consumer's binding declaration, like env typing.
|
|
427
|
+
isContainerNamespaceResource as (value: unknown) => value is Namespace,
|
|
428
|
+
makeClient(definition),
|
|
429
|
+
{
|
|
430
|
+
expected: expectedContainerNamespace,
|
|
431
|
+
},
|
|
432
|
+
);
|
|
275
433
|
|
|
276
434
|
export const make = <Id extends string>(id: Id) => Tag<ContainerNamespaceService<Id>>()<Id>(id);
|
|
277
435
|
|
|
@@ -286,20 +444,21 @@ export interface ContainerNamespaceService<Id extends string> {
|
|
|
286
444
|
|
|
287
445
|
/** Creates a typed Effect service for a Cloudflare Container namespace. */
|
|
288
446
|
export const Tag =
|
|
289
|
-
<Self>() =>
|
|
447
|
+
<Self, Namespace extends ContainerNamespaceResource = ContainerNamespaceResource>() =>
|
|
290
448
|
<Id extends string>(id: Id) => {
|
|
291
|
-
const tag = Context.Service<Self, ContainerNamespaceClient
|
|
449
|
+
const tag = Context.Service<Self, ContainerNamespaceClient<Namespace>>()(
|
|
450
|
+
`effect-cf/Container/${id}` as const,
|
|
451
|
+
);
|
|
292
452
|
const makeLayer = (definition: LayerOptions) => layer(tag, definition);
|
|
293
453
|
|
|
294
|
-
const getByName = (
|
|
454
|
+
const getByName = Effect.fnUntraced(function* (
|
|
295
455
|
name: string,
|
|
296
456
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
const namespace = yield* tag;
|
|
457
|
+
) {
|
|
458
|
+
const namespace = yield* tag;
|
|
300
459
|
|
|
301
|
-
|
|
302
|
-
|
|
460
|
+
return yield* namespace.getByName(name, options);
|
|
461
|
+
});
|
|
303
462
|
|
|
304
463
|
const byName = (
|
|
305
464
|
name: string,
|
|
@@ -316,25 +475,37 @@ export const Tag =
|
|
|
316
475
|
Effect.flatMap(getByName(name, options), (instance) =>
|
|
317
476
|
instance.startAndWaitForPorts(startOptions),
|
|
318
477
|
),
|
|
319
|
-
|
|
478
|
+
waitForPort: (waitOptions: ContainerWaitOptions) =>
|
|
479
|
+
Effect.flatMap(getByName(name, options), (instance) => instance.waitForPort(waitOptions)),
|
|
480
|
+
stop: (signal?: ContainerStopSignal) =>
|
|
320
481
|
Effect.flatMap(getByName(name, options), (instance) => instance.stop(signal)),
|
|
321
482
|
destroy: Effect.flatMap(getByName(name, options), (instance) => instance.destroy),
|
|
322
|
-
|
|
483
|
+
setAllowedHosts: (hosts: ReadonlyArray<string>) =>
|
|
484
|
+
Effect.flatMap(getByName(name, options), (instance) => instance.setAllowedHosts(hosts)),
|
|
485
|
+
setDeniedHosts: (hosts: ReadonlyArray<string>) =>
|
|
486
|
+
Effect.flatMap(getByName(name, options), (instance) => instance.setDeniedHosts(hosts)),
|
|
487
|
+
allowHost: (hostname: string) =>
|
|
488
|
+
Effect.flatMap(getByName(name, options), (instance) => instance.allowHost(hostname)),
|
|
489
|
+
denyHost: (hostname: string) =>
|
|
490
|
+
Effect.flatMap(getByName(name, options), (instance) => instance.denyHost(hostname)),
|
|
491
|
+
removeAllowedHost: (hostname: string) =>
|
|
492
|
+
Effect.flatMap(getByName(name, options), (instance) =>
|
|
493
|
+
instance.removeAllowedHost(hostname),
|
|
494
|
+
),
|
|
495
|
+
removeDeniedHost: (hostname: string) =>
|
|
496
|
+
Effect.flatMap(getByName(name, options), (instance) => instance.removeDeniedHost(hostname)),
|
|
497
|
+
rawUnsafe: Effect.flatMap(getByName(name, options), (instance) => instance.rawUnsafe),
|
|
323
498
|
});
|
|
324
499
|
|
|
325
|
-
const
|
|
326
|
-
const namespace = yield* tag;
|
|
327
|
-
|
|
328
|
-
return yield* namespace.unsafeRaw;
|
|
329
|
-
});
|
|
500
|
+
const rawUnsafe = Effect.flatMap(tag, (namespace) => namespace.rawUnsafe);
|
|
330
501
|
|
|
331
502
|
return Object.assign(tag, {
|
|
332
503
|
id,
|
|
333
504
|
layer: makeLayer,
|
|
334
505
|
getByName,
|
|
335
506
|
byName,
|
|
336
|
-
|
|
337
|
-
}) as TagClass<Self, Id>;
|
|
507
|
+
rawUnsafe,
|
|
508
|
+
}) as TagClass<Self, Id, Namespace>;
|
|
338
509
|
};
|
|
339
510
|
|
|
340
511
|
export const ContainerNamespace = Tag;
|
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;
|