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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-cf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Effect-native primitives for Cloudflare Workers and bindings.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"src"
|
|
15
15
|
],
|
|
16
16
|
"type": "module",
|
|
17
|
+
"sideEffects": [],
|
|
17
18
|
"types": "./dist/index.d.mts",
|
|
18
19
|
"exports": {
|
|
19
20
|
".": {
|
|
@@ -52,12 +53,16 @@
|
|
|
52
53
|
"vitest": "catalog:"
|
|
53
54
|
},
|
|
54
55
|
"peerDependencies": {
|
|
55
|
-
"@
|
|
56
|
-
"@effect/sql-
|
|
57
|
-
"@effect/sql-
|
|
58
|
-
"effect": "
|
|
56
|
+
"@cloudflare/workers-types": "^4.20260611.1",
|
|
57
|
+
"@effect/sql-d1": "4.0.0-beta.105",
|
|
58
|
+
"@effect/sql-pg": "4.0.0-beta.105",
|
|
59
|
+
"@effect/sql-sqlite-do": "4.0.0-beta.105",
|
|
60
|
+
"effect": "4.0.0-beta.105"
|
|
59
61
|
},
|
|
60
62
|
"peerDependenciesMeta": {
|
|
63
|
+
"@cloudflare/workers-types": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
61
66
|
"@effect/sql-pg": {
|
|
62
67
|
"optional": true
|
|
63
68
|
}
|
package/src/AiGateway.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { AiGateway as CloudflareAiGateway } from "@cloudflare/workers-types
|
|
|
4
4
|
import * as Binding from "./Binding";
|
|
5
5
|
import type { WorkerEnvironment } from "./Environment";
|
|
6
6
|
import { isWorkersAiBinding, type WorkersAiBinding } from "./WorkersAi";
|
|
7
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
7
8
|
|
|
8
9
|
const expectedAiGatewayBinding = "Workers AI binding with gateway()";
|
|
9
10
|
|
|
@@ -12,7 +13,11 @@ export class AiGatewayOperationError extends Data.TaggedError("AiGatewayOperatio
|
|
|
12
13
|
readonly binding: string;
|
|
13
14
|
readonly operation: string;
|
|
14
15
|
readonly cause: unknown;
|
|
15
|
-
}> {
|
|
16
|
+
}> {
|
|
17
|
+
override get message(): string {
|
|
18
|
+
return `AI Gateway ${this.operation} failed for binding "${this.binding}": ${ErrorMessage.causeMessage(this.cause)}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
16
21
|
|
|
17
22
|
/** Typed AI Gateway client definition. */
|
|
18
23
|
export interface AiGatewayDefinition {
|
|
@@ -53,7 +58,7 @@ export interface AiGatewayClient {
|
|
|
53
58
|
data: AiGatewayPatchLog,
|
|
54
59
|
) => Effect.Effect<void, AiGatewayOperationError>;
|
|
55
60
|
readonly getLog: (logId: string) => Effect.Effect<AiGatewayLog, AiGatewayOperationError>;
|
|
56
|
-
readonly
|
|
61
|
+
readonly rawUnsafe: Effect.Effect<AiGatewayBinding, AiGatewayOperationError>;
|
|
57
62
|
readonly definition: AiGatewayDefinition;
|
|
58
63
|
}
|
|
59
64
|
|
|
@@ -93,13 +98,19 @@ const aiGatewayError = (binding: string, operation: string, cause: unknown) =>
|
|
|
93
98
|
const tryAiGatewayPromise = <A>(
|
|
94
99
|
binding: string,
|
|
95
100
|
operation: string,
|
|
96
|
-
evaluate: () => Promise<A>,
|
|
101
|
+
evaluate: (signal: AbortSignal) => Promise<A>,
|
|
97
102
|
): Effect.Effect<A, AiGatewayOperationError> =>
|
|
98
103
|
Effect.tryPromise({
|
|
99
104
|
try: evaluate,
|
|
100
105
|
catch: (cause) => aiGatewayError(binding, operation, cause),
|
|
101
106
|
});
|
|
102
107
|
|
|
108
|
+
const mergeAbortSignals = (
|
|
109
|
+
userSignal: AbortSignal | null | undefined,
|
|
110
|
+
signal: AbortSignal,
|
|
111
|
+
): AbortSignal =>
|
|
112
|
+
userSignal === null || userSignal === undefined ? signal : AbortSignal.any([userSignal, signal]);
|
|
113
|
+
|
|
103
114
|
const tryAiGatewaySync = <A>(
|
|
104
115
|
binding: string,
|
|
105
116
|
operation: string,
|
|
@@ -126,32 +137,42 @@ export const isAiGatewayBinding = (value: unknown): value is WorkersAiBinding =>
|
|
|
126
137
|
export const makeClient = (definition: AiGatewayDefinition, gateway: AiGatewayBinding) =>
|
|
127
138
|
({
|
|
128
139
|
definition,
|
|
129
|
-
run: (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
run: Effect.fn("AiGateway.run")(
|
|
141
|
+
(
|
|
142
|
+
data: AiGatewayUniversalRequest | ReadonlyArray<AiGatewayUniversalRequest>,
|
|
143
|
+
options?: AiGatewayRunOptions,
|
|
144
|
+
) =>
|
|
145
|
+
tryAiGatewayPromise(definition.binding, "run", () =>
|
|
146
|
+
gateway.run(
|
|
147
|
+
(Array.isArray(data) ? [...data] : data) as
|
|
148
|
+
| AiGatewayUniversalRequest
|
|
149
|
+
| Array<AiGatewayUniversalRequest>,
|
|
150
|
+
options,
|
|
151
|
+
),
|
|
136
152
|
),
|
|
137
|
-
|
|
138
|
-
getUrl: (provider) =>
|
|
153
|
+
),
|
|
154
|
+
getUrl: Effect.fn("AiGateway.getUrl")((provider?: AiGatewayProvider) =>
|
|
139
155
|
tryAiGatewayPromise(definition.binding, "getUrl", () => gateway.getUrl(provider)),
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
156
|
+
),
|
|
157
|
+
fetch: Effect.fn("AiGateway.fetch")(function* (options: AiGatewayFetchOptions) {
|
|
158
|
+
const baseUrl = yield* tryAiGatewayPromise(definition.binding, "getUrl", () =>
|
|
159
|
+
gateway.getUrl(options.provider),
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
return yield* tryAiGatewayPromise(definition.binding, "fetch", (signal) =>
|
|
163
|
+
fetch(providerUrl(baseUrl, options.path).href, {
|
|
164
|
+
...options.init,
|
|
165
|
+
signal: mergeAbortSignals(options.init?.signal, signal),
|
|
166
|
+
}),
|
|
167
|
+
);
|
|
168
|
+
}),
|
|
169
|
+
patchLog: Effect.fn("AiGateway.patchLog")((logId: string, data: AiGatewayPatchLog) =>
|
|
151
170
|
tryAiGatewayPromise(definition.binding, "patchLog", () => gateway.patchLog(logId, data)),
|
|
152
|
-
|
|
171
|
+
),
|
|
172
|
+
getLog: Effect.fn("AiGateway.getLog")((logId: string) =>
|
|
153
173
|
tryAiGatewayPromise(definition.binding, "getLog", () => gateway.getLog(logId)),
|
|
154
|
-
|
|
174
|
+
),
|
|
175
|
+
rawUnsafe: Effect.succeed(gateway),
|
|
155
176
|
}) satisfies AiGatewayClient;
|
|
156
177
|
|
|
157
178
|
export const makeClientFromAi = (
|
|
@@ -174,7 +195,7 @@ export const makeClientFromAi = (
|
|
|
174
195
|
patchLog: (logId, data) =>
|
|
175
196
|
withGateway((raw) => makeClient(definition, raw).patchLog(logId, data)),
|
|
176
197
|
getLog: (logId) => withGateway((raw) => makeClient(definition, raw).getLog(logId)),
|
|
177
|
-
|
|
198
|
+
rawUnsafe: gateway,
|
|
178
199
|
};
|
|
179
200
|
};
|
|
180
201
|
|
|
@@ -214,45 +235,59 @@ export const makeHttpClient = (
|
|
|
214
235
|
|
|
215
236
|
return {
|
|
216
237
|
definition: clientDefinition,
|
|
217
|
-
run: (
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
238
|
+
run: Effect.fn("AiGateway.run")(
|
|
239
|
+
(
|
|
240
|
+
data: AiGatewayUniversalRequest | ReadonlyArray<AiGatewayUniversalRequest>,
|
|
241
|
+
options?: AiGatewayRunOptions,
|
|
242
|
+
) =>
|
|
243
|
+
tryAiGatewayPromise(binding, "run", (signal) =>
|
|
244
|
+
request(gatewayUrl(definition), {
|
|
245
|
+
method: "POST",
|
|
246
|
+
body: JSON.stringify(data),
|
|
247
|
+
headers: new Headers({
|
|
248
|
+
"content-type": "application/json",
|
|
249
|
+
...Object.fromEntries(new Headers(extraHeaders(options)).entries()),
|
|
250
|
+
}),
|
|
251
|
+
signal: mergeAbortSignals(options?.signal, signal),
|
|
225
252
|
}),
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
),
|
|
253
|
+
),
|
|
254
|
+
),
|
|
229
255
|
getUrl,
|
|
230
|
-
fetch: (options) =>
|
|
256
|
+
fetch: Effect.fn("AiGateway.fetch")((options: AiGatewayFetchOptions) =>
|
|
231
257
|
getUrl(options.provider).pipe(
|
|
232
258
|
Effect.flatMap((baseUrl) =>
|
|
233
|
-
tryAiGatewayPromise(binding, "fetch", () =>
|
|
234
|
-
request(providerUrl(baseUrl, options.path).href,
|
|
259
|
+
tryAiGatewayPromise(binding, "fetch", (signal) =>
|
|
260
|
+
request(providerUrl(baseUrl, options.path).href, {
|
|
261
|
+
...options.init,
|
|
262
|
+
signal: mergeAbortSignals(options.init?.signal, signal),
|
|
263
|
+
}),
|
|
235
264
|
),
|
|
236
265
|
),
|
|
237
266
|
),
|
|
238
|
-
|
|
239
|
-
|
|
267
|
+
),
|
|
268
|
+
patchLog: Effect.fn("AiGateway.patchLog")((logId: string, data: AiGatewayPatchLog) =>
|
|
269
|
+
tryAiGatewayPromise(binding, "patchLog", (signal) =>
|
|
240
270
|
request(providerUrl(gatewayUrl(definition), `logs/${logId}`).href, {
|
|
241
271
|
method: "PATCH",
|
|
242
272
|
body: JSON.stringify(data),
|
|
243
273
|
headers: { "content-type": "application/json" },
|
|
274
|
+
signal,
|
|
244
275
|
}).then(() => undefined),
|
|
245
276
|
),
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
277
|
+
),
|
|
278
|
+
getLog: Effect.fn("AiGateway.getLog")((logId: string) =>
|
|
279
|
+
tryAiGatewayPromise(binding, "getLog", async (signal) => {
|
|
280
|
+
const response = await request(providerUrl(gatewayUrl(definition), `logs/${logId}`).href, {
|
|
281
|
+
signal,
|
|
282
|
+
});
|
|
249
283
|
|
|
250
284
|
return (await response.json()) as AiGatewayLog;
|
|
251
285
|
}),
|
|
252
|
-
|
|
286
|
+
),
|
|
287
|
+
rawUnsafe: Effect.fail(
|
|
253
288
|
aiGatewayError(
|
|
254
289
|
binding,
|
|
255
|
-
"
|
|
290
|
+
"rawUnsafe",
|
|
256
291
|
new TypeError("HTTP AI Gateway clients have no raw binding"),
|
|
257
292
|
),
|
|
258
293
|
),
|
package/src/AnalyticsEngine.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
|
|
24
24
|
import * as Binding from "./Binding";
|
|
25
25
|
import type { WorkerEnvironment } from "./Environment";
|
|
26
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
26
27
|
|
|
27
28
|
const expectedAnalyticsEngineDataset = "Analytics Engine dataset binding with writeDataPoint()";
|
|
28
29
|
const defaultQueryApiBaseUrl = "https://api.cloudflare.com/client/v4";
|
|
@@ -70,7 +71,11 @@ export class AnalyticsEngineOperationError extends Data.TaggedError(
|
|
|
70
71
|
readonly binding: string;
|
|
71
72
|
readonly operation: string;
|
|
72
73
|
readonly cause: unknown;
|
|
73
|
-
}> {
|
|
74
|
+
}> {
|
|
75
|
+
override get message(): string {
|
|
76
|
+
return `Analytics Engine ${this.operation} failed for binding "${this.binding}": ${ErrorMessage.causeMessage(this.cause)}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
74
79
|
|
|
75
80
|
export interface AnalyticsEngineWriteViolation {
|
|
76
81
|
readonly path: string;
|
|
@@ -87,7 +92,11 @@ export class AnalyticsEngineWriteValidationError extends Data.TaggedError(
|
|
|
87
92
|
readonly operation: string;
|
|
88
93
|
readonly violations: ReadonlyArray<AnalyticsEngineWriteViolation>;
|
|
89
94
|
readonly cause?: unknown;
|
|
90
|
-
}> {
|
|
95
|
+
}> {
|
|
96
|
+
override get message(): string {
|
|
97
|
+
return `Analytics Engine ${this.operation} for binding "${this.binding}" failed validation: ${ErrorMessage.violationsMessage(this.violations)}`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
91
100
|
|
|
92
101
|
/** Error raised when an Analytics Engine SQL API query fails. */
|
|
93
102
|
export class AnalyticsEngineQueryError extends Data.TaggedError("AnalyticsEngineQueryError")<{
|
|
@@ -170,7 +179,7 @@ export interface AnalyticsEngineClient {
|
|
|
170
179
|
dataPoints: ReadonlyArray<AnalyticsEngineDataPoint>,
|
|
171
180
|
options?: AnalyticsEngineWriteBatchOptions,
|
|
172
181
|
) => Effect.Effect<void, AnalyticsEngineWriteError>;
|
|
173
|
-
readonly
|
|
182
|
+
readonly rawUnsafe: Effect.Effect<AnalyticsEngineBinding>;
|
|
174
183
|
readonly definition: AnalyticsEngineDefinition;
|
|
175
184
|
}
|
|
176
185
|
|
|
@@ -257,11 +266,11 @@ export interface QueryTagClass<Self, Id extends string> extends Context.ServiceC
|
|
|
257
266
|
readonly layer: (
|
|
258
267
|
definition: AnalyticsEngineQueryDefinition,
|
|
259
268
|
) => Layer.Layer<Self, never, HttpClient.HttpClient>;
|
|
260
|
-
readonly
|
|
269
|
+
readonly layerFetch: (definition: AnalyticsEngineQueryDefinition) => Layer.Layer<Self>;
|
|
261
270
|
readonly layerConfig: (
|
|
262
271
|
config?: Config.Config<AnalyticsEngineQueryDefinition>,
|
|
263
272
|
) => Layer.Layer<Self, Config.ConfigError, HttpClient.HttpClient>;
|
|
264
|
-
readonly
|
|
273
|
+
readonly layerFetchConfig: (
|
|
265
274
|
config?: Config.Config<AnalyticsEngineQueryDefinition>,
|
|
266
275
|
) => Layer.Layer<Self, Config.ConfigError>;
|
|
267
276
|
}
|
|
@@ -633,26 +642,30 @@ const makeQueryClientWith = (
|
|
|
633
642
|
definition: AnalyticsEngineQueryDefinition,
|
|
634
643
|
httpClient: HttpClient.HttpClient,
|
|
635
644
|
): AnalyticsEngineQueryClient => {
|
|
636
|
-
const raw = (
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
645
|
+
const raw = Effect.fn("AnalyticsEngine.raw")(
|
|
646
|
+
(sql: string, options?: AnalyticsEngineQueryOptions) =>
|
|
647
|
+
executeQueryRequest(definition, httpClient, sql, options),
|
|
648
|
+
);
|
|
649
|
+
const query = Effect.fn("AnalyticsEngine.query")(function* (
|
|
650
|
+
sql: string,
|
|
651
|
+
options?: AnalyticsEngineQueryOptions,
|
|
652
|
+
) {
|
|
653
|
+
const response = yield* raw(sql, options);
|
|
654
|
+
const json = yield* response.json.pipe(
|
|
655
|
+
Effect.catch((cause) =>
|
|
656
|
+
Effect.fail(
|
|
657
|
+
analyticsEngineQueryError(
|
|
658
|
+
definition,
|
|
659
|
+
"json",
|
|
660
|
+
"Failed to read Analytics Engine SQL API JSON response body",
|
|
661
|
+
{ cause },
|
|
650
662
|
),
|
|
651
663
|
),
|
|
652
|
-
)
|
|
664
|
+
),
|
|
665
|
+
);
|
|
653
666
|
|
|
654
|
-
|
|
655
|
-
|
|
667
|
+
return yield* decodeQueryResponse(json);
|
|
668
|
+
});
|
|
656
669
|
const queryResult = <Row>(
|
|
657
670
|
row: S.Codec<Row, unknown>,
|
|
658
671
|
sql: string,
|
|
@@ -672,7 +685,7 @@ const makeQueryClientWith = (
|
|
|
672
685
|
data,
|
|
673
686
|
rows: result.rows,
|
|
674
687
|
} satisfies AnalyticsEngineQueryResult<Row>;
|
|
675
|
-
});
|
|
688
|
+
}).pipe(Effect.withSpan("AnalyticsEngine.queryResult"));
|
|
676
689
|
|
|
677
690
|
return {
|
|
678
691
|
definition,
|
|
@@ -680,17 +693,23 @@ const makeQueryClientWith = (
|
|
|
680
693
|
query,
|
|
681
694
|
queryResult,
|
|
682
695
|
queryRows: (row, sql, options) =>
|
|
683
|
-
queryResult(row, sql, options).pipe(
|
|
696
|
+
queryResult(row, sql, options).pipe(
|
|
697
|
+
Effect.map((result) => result.data),
|
|
698
|
+
Effect.withSpan("AnalyticsEngine.queryRows"),
|
|
699
|
+
),
|
|
684
700
|
queryOne: (row, sql, options) =>
|
|
685
701
|
queryResult(row, sql, options).pipe(
|
|
686
702
|
Effect.map((result) =>
|
|
687
703
|
result.data[0] === undefined ? Option.none() : Option.some(result.data[0]),
|
|
688
704
|
),
|
|
705
|
+
Effect.withSpan("AnalyticsEngine.queryOne"),
|
|
689
706
|
),
|
|
690
|
-
queryText: (
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
707
|
+
queryText: Effect.fn("AnalyticsEngine.queryText")(
|
|
708
|
+
(sql: string, options?: AnalyticsEngineQueryOptions) =>
|
|
709
|
+
raw(sql, options).pipe(
|
|
710
|
+
Effect.flatMap((response) => responseText(definition, response, "text")),
|
|
711
|
+
),
|
|
712
|
+
),
|
|
694
713
|
};
|
|
695
714
|
};
|
|
696
715
|
|
|
@@ -708,7 +727,7 @@ export const isAnalyticsEngineDataset = (value: unknown): value is AnalyticsEngi
|
|
|
708
727
|
export const makeClient =
|
|
709
728
|
(definition: AnalyticsEngineDefinition, defaults?: AnalyticsEngineWritePolicy) =>
|
|
710
729
|
(dataset: AnalyticsEngineBinding): AnalyticsEngineClient => {
|
|
711
|
-
const writeDataPoint = (
|
|
730
|
+
const writeDataPoint = Effect.fn("AnalyticsEngine.writeDataPoint")((
|
|
712
731
|
dataPoint?: AnalyticsEngineDataPoint,
|
|
713
732
|
options?: AnalyticsEngineWriteOptions,
|
|
714
733
|
) => {
|
|
@@ -724,31 +743,28 @@ export const makeClient =
|
|
|
724
743
|
),
|
|
725
744
|
}),
|
|
726
745
|
);
|
|
727
|
-
};
|
|
746
|
+
});
|
|
728
747
|
|
|
729
|
-
const writeDataPoints = (
|
|
748
|
+
const writeDataPoints = Effect.fn("AnalyticsEngine.writeDataPoints")(function* (
|
|
730
749
|
dataPoints: ReadonlyArray<AnalyticsEngineDataPoint>,
|
|
731
750
|
options?: AnalyticsEngineWriteBatchOptions,
|
|
732
|
-
)
|
|
751
|
+
) {
|
|
733
752
|
const policy = resolveWritePolicy(defaults, options);
|
|
753
|
+
const validPoints = yield* validateDataPoints(
|
|
754
|
+
definition.binding,
|
|
755
|
+
"writeDataPoints",
|
|
756
|
+
dataPoints,
|
|
757
|
+
policy,
|
|
758
|
+
);
|
|
734
759
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
yield* writeChunks(
|
|
744
|
-
definition.binding,
|
|
745
|
-
"writeDataPoints",
|
|
746
|
-
dataset,
|
|
747
|
-
validPoints,
|
|
748
|
-
policy.batchSize,
|
|
749
|
-
);
|
|
750
|
-
});
|
|
751
|
-
};
|
|
760
|
+
yield* writeChunks(
|
|
761
|
+
definition.binding,
|
|
762
|
+
"writeDataPoints",
|
|
763
|
+
dataset,
|
|
764
|
+
validPoints,
|
|
765
|
+
policy.batchSize,
|
|
766
|
+
);
|
|
767
|
+
});
|
|
752
768
|
|
|
753
769
|
return {
|
|
754
770
|
definition,
|
|
@@ -756,7 +772,7 @@ export const makeClient =
|
|
|
756
772
|
write: writeDataPoint,
|
|
757
773
|
writeDataPoints,
|
|
758
774
|
writeBatch: writeDataPoints,
|
|
759
|
-
|
|
775
|
+
rawUnsafe: Effect.succeed(dataset),
|
|
760
776
|
};
|
|
761
777
|
};
|
|
762
778
|
|
|
@@ -774,7 +790,7 @@ export const queryLayer = <Self>(
|
|
|
774
790
|
definition: AnalyticsEngineQueryDefinition,
|
|
775
791
|
) => Layer.effect(tag, makeQueryClient(definition));
|
|
776
792
|
|
|
777
|
-
export const
|
|
793
|
+
export const layerFetch = <Self>(
|
|
778
794
|
tag: Context.Service<Self, AnalyticsEngineQueryClient>,
|
|
779
795
|
definition: AnalyticsEngineQueryDefinition,
|
|
780
796
|
) => queryLayer(tag, definition).pipe(Layer.provide(FetchHttpClient.layer));
|
|
@@ -792,7 +808,7 @@ export const queryLayerConfig = <Self>(
|
|
|
792
808
|
}),
|
|
793
809
|
);
|
|
794
810
|
|
|
795
|
-
export const
|
|
811
|
+
export const layerFetchConfig = <Self>(
|
|
796
812
|
tag: Context.Service<Self, AnalyticsEngineQueryClient>,
|
|
797
813
|
config: Config.Config<AnalyticsEngineQueryDefinition> = queryConfig(),
|
|
798
814
|
) => queryLayerConfig(tag, config).pipe(Layer.provide(FetchHttpClient.layer));
|
|
@@ -834,18 +850,18 @@ export const QueryTag =
|
|
|
834
850
|
<Id extends string>(id: Id) => {
|
|
835
851
|
const tag = Context.Service<Self, AnalyticsEngineQueryClient>()(id);
|
|
836
852
|
const makeLayer = (definition: AnalyticsEngineQueryDefinition) => queryLayer(tag, definition);
|
|
837
|
-
const
|
|
838
|
-
|
|
853
|
+
const makeLayerFetch = (definition: AnalyticsEngineQueryDefinition) =>
|
|
854
|
+
layerFetch(tag, definition);
|
|
839
855
|
const makeLayerConfig = (config?: Config.Config<AnalyticsEngineQueryDefinition>) =>
|
|
840
856
|
queryLayerConfig(tag, config);
|
|
841
|
-
const
|
|
842
|
-
|
|
857
|
+
const makeLayerFetchConfig = (config?: Config.Config<AnalyticsEngineQueryDefinition>) =>
|
|
858
|
+
layerFetchConfig(tag, config);
|
|
843
859
|
|
|
844
860
|
return Object.assign(tag, {
|
|
845
861
|
id,
|
|
846
862
|
layer: makeLayer,
|
|
847
|
-
|
|
863
|
+
layerFetch: makeLayerFetch,
|
|
848
864
|
layerConfig: makeLayerConfig,
|
|
849
|
-
|
|
865
|
+
layerFetchConfig: makeLayerFetchConfig,
|
|
850
866
|
}) as QueryTagClass<Self, Id>;
|
|
851
867
|
};
|
package/src/Binding.ts
CHANGED
|
@@ -3,7 +3,10 @@ import { Context, Data, Effect, Layer } from "effect";
|
|
|
3
3
|
import { WorkerEnvironment, type WorkerEnv } from "./Environment";
|
|
4
4
|
|
|
5
5
|
/** Internal type id marker used by binding helper services. */
|
|
6
|
-
export const TypeId = "effect-cf/Binding" as const;
|
|
6
|
+
export const TypeId = "~effect-cf/Binding" as const;
|
|
7
|
+
|
|
8
|
+
/** Internal type id marker used by binding helper services. */
|
|
9
|
+
export type TypeId = typeof TypeId;
|
|
7
10
|
|
|
8
11
|
/** Error raised when a configured binding does not exist on `env`. */
|
|
9
12
|
export class BindingNotFoundError extends Data.TaggedError("BindingNotFoundError")<{
|
|
@@ -161,13 +164,17 @@ const getBinding = <Resource>(
|
|
|
161
164
|
|
|
162
165
|
/**
|
|
163
166
|
* Creates a Context tag + layer for reading and validating a Cloudflare binding.
|
|
167
|
+
*
|
|
168
|
+
* The Context key is namespaced as `effect-cf/Binding/<id>`; `id` stays the
|
|
169
|
+
* bare user-supplied identifier.
|
|
164
170
|
*/
|
|
165
171
|
export interface BindingService<Self, Id extends string, Service> extends Context.ServiceClass<
|
|
166
172
|
Self,
|
|
167
|
-
Id
|
|
173
|
+
`effect-cf/Binding/${Id}`,
|
|
168
174
|
Service
|
|
169
175
|
> {
|
|
170
|
-
readonly [TypeId]:
|
|
176
|
+
readonly [TypeId]: TypeId;
|
|
177
|
+
readonly id: Id;
|
|
171
178
|
readonly binding: string;
|
|
172
179
|
readonly layer: Layer.Layer<
|
|
173
180
|
Self,
|
|
@@ -176,12 +183,17 @@ export interface BindingService<Self, Id extends string, Service> extends Contex
|
|
|
176
183
|
>;
|
|
177
184
|
}
|
|
178
185
|
|
|
179
|
-
|
|
186
|
+
/**
|
|
187
|
+
* The overloads on {@link layer} and {@link Service} guarantee that
|
|
188
|
+
* `Service = Resource` whenever `wrap` is absent, making the fallback cast
|
|
189
|
+
* safe.
|
|
190
|
+
*/
|
|
191
|
+
const makeBindingLayer = <Self, Resource, Service>(
|
|
180
192
|
tag: Context.Service<Self, Service>,
|
|
181
193
|
binding: string,
|
|
182
194
|
isResource: (value: unknown) => value is Resource,
|
|
183
|
-
wrap
|
|
184
|
-
options
|
|
195
|
+
wrap: ((resource: Resource) => Service) | undefined,
|
|
196
|
+
options: ValidationOptions | undefined,
|
|
185
197
|
): Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment> =>
|
|
186
198
|
Layer.effect(
|
|
187
199
|
tag,
|
|
@@ -193,21 +205,62 @@ export const layer = <Self, Resource, Service = Resource>(
|
|
|
193
205
|
}),
|
|
194
206
|
);
|
|
195
207
|
|
|
196
|
-
export
|
|
197
|
-
<Self
|
|
198
|
-
|
|
208
|
+
export function layer<Self, Resource>(
|
|
209
|
+
tag: Context.Service<Self, Resource>,
|
|
210
|
+
binding: string,
|
|
211
|
+
isResource: (value: unknown) => value is Resource,
|
|
212
|
+
wrap?: undefined,
|
|
213
|
+
options?: ValidationOptions,
|
|
214
|
+
): Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
215
|
+
export function layer<Self, Resource, Service>(
|
|
216
|
+
tag: Context.Service<Self, Service>,
|
|
217
|
+
binding: string,
|
|
218
|
+
isResource: (value: unknown) => value is Resource,
|
|
219
|
+
wrap: (resource: Resource) => Service,
|
|
220
|
+
options?: ValidationOptions,
|
|
221
|
+
): Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
222
|
+
export function layer<Self, Resource, Service = Resource>(
|
|
223
|
+
tag: Context.Service<Self, Service>,
|
|
224
|
+
binding: string,
|
|
225
|
+
isResource: (value: unknown) => value is Resource,
|
|
226
|
+
wrap?: (resource: Resource) => Service,
|
|
227
|
+
options?: ValidationOptions,
|
|
228
|
+
): Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment> {
|
|
229
|
+
return makeBindingLayer(tag, binding, isResource, wrap, options);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export const Service = <Self>() => {
|
|
233
|
+
function makeService<Id extends string, Resource>(
|
|
234
|
+
id: Id,
|
|
235
|
+
binding: string,
|
|
236
|
+
isResource: (value: unknown) => value is Resource,
|
|
237
|
+
wrap?: undefined,
|
|
238
|
+
options?: ValidationOptions,
|
|
239
|
+
): BindingService<Self, Id, Resource>;
|
|
240
|
+
function makeService<Id extends string, Resource, Service>(
|
|
241
|
+
id: Id,
|
|
242
|
+
binding: string,
|
|
243
|
+
isResource: (value: unknown) => value is Resource,
|
|
244
|
+
wrap: (resource: Resource) => Service,
|
|
245
|
+
options?: ValidationOptions,
|
|
246
|
+
): BindingService<Self, Id, Service>;
|
|
247
|
+
function makeService<Id extends string, Resource, Service = Resource>(
|
|
199
248
|
id: Id,
|
|
200
249
|
binding: string,
|
|
201
250
|
isResource: (value: unknown) => value is Resource,
|
|
202
251
|
wrap?: (resource: Resource) => Service,
|
|
203
252
|
options?: ValidationOptions,
|
|
204
|
-
): BindingService<Self, Id, Service>
|
|
205
|
-
const tag = Context.Service<Self, Service>()(id);
|
|
206
|
-
const serviceLayer =
|
|
253
|
+
): BindingService<Self, Id, Service> {
|
|
254
|
+
const tag = Context.Service<Self, Service>()(`effect-cf/Binding/${id}` as const);
|
|
255
|
+
const serviceLayer = makeBindingLayer(tag, binding, isResource, wrap, options);
|
|
207
256
|
|
|
208
257
|
return Object.assign(tag, {
|
|
209
258
|
[TypeId]: TypeId,
|
|
259
|
+
id,
|
|
210
260
|
binding,
|
|
211
261
|
layer: serviceLayer,
|
|
212
262
|
}) as BindingService<Self, Id, Service>;
|
|
213
|
-
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return makeService;
|
|
266
|
+
};
|