effect-cf 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +9 -2
- package/dist/index.d.mts +237 -335
- package/dist/index.mjs +299 -109
- package/package.json +3 -1
- package/src/Binding.ts +21 -5
- package/src/D1.ts +135 -0
- package/src/DurableObjectNamespace.ts +227 -32
- package/src/Kv.ts +133 -80
- package/src/QueueBinding.ts +51 -18
- package/src/ServiceBinding.ts +147 -84
- package/src/index.ts +1 -0
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
|
|
2
2
|
import { Cause, Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Layer, ManagedRuntime, Option, Queue, Schema } from "effect";
|
|
3
|
+
import { D1Client } from "@effect/sql-d1";
|
|
3
4
|
import { DurableObject, RpcStub, RpcTarget, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
|
|
4
5
|
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
5
6
|
import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
|
|
@@ -28,11 +29,11 @@ let WorkerConfig;
|
|
|
28
29
|
var Binding_exports = /* @__PURE__ */ __exportAll({
|
|
29
30
|
BindingNotFoundError: () => BindingNotFoundError,
|
|
30
31
|
BindingValidationError: () => BindingValidationError,
|
|
31
|
-
Service: () => Service$
|
|
32
|
-
TypeId: () => TypeId$
|
|
32
|
+
Service: () => Service$6,
|
|
33
|
+
TypeId: () => TypeId$6
|
|
33
34
|
});
|
|
34
35
|
/** Internal type id marker used by binding helper services. */
|
|
35
|
-
const TypeId$
|
|
36
|
+
const TypeId$6 = "effect-cf/Binding";
|
|
36
37
|
/** Error raised when a configured binding does not exist on `env`. */
|
|
37
38
|
var BindingNotFoundError = class extends Data.TaggedError("BindingNotFoundError") {};
|
|
38
39
|
/** Error raised when a binding exists but does not match the expected shape. */
|
|
@@ -45,21 +46,101 @@ const getBinding = (env, binding, isResource) => Effect.gen(function* () {
|
|
|
45
46
|
if (!isResource(resource)) return yield* Effect.fail(new BindingValidationError({ binding }));
|
|
46
47
|
return resource;
|
|
47
48
|
});
|
|
48
|
-
|
|
49
|
-
* Creates a Context tag + layer for reading and validating a Cloudflare binding.
|
|
50
|
-
*/
|
|
51
|
-
const Service$5 = () => (id, binding, isResource) => {
|
|
49
|
+
const Service$6 = () => (id, binding, isResource, wrap) => {
|
|
52
50
|
const tag = Context.Service()(id);
|
|
53
51
|
const layer = Layer.effect(tag, Effect.gen(function* () {
|
|
54
|
-
|
|
52
|
+
const resource = yield* getBinding(yield* WorkerEnvironment, binding, isResource);
|
|
53
|
+
return wrap === void 0 ? resource : wrap(resource);
|
|
55
54
|
}));
|
|
56
55
|
return Object.assign(tag, {
|
|
57
|
-
[TypeId$
|
|
56
|
+
[TypeId$6]: TypeId$6,
|
|
58
57
|
binding,
|
|
59
58
|
layer
|
|
60
59
|
});
|
|
61
60
|
};
|
|
62
61
|
//#endregion
|
|
62
|
+
//#region src/D1.ts
|
|
63
|
+
var D1_exports = /* @__PURE__ */ __exportAll({
|
|
64
|
+
D1OperationError: () => D1OperationError,
|
|
65
|
+
Service: () => Service$5,
|
|
66
|
+
make: () => make$11
|
|
67
|
+
});
|
|
68
|
+
const TypeId$5 = "effect-cf/D1";
|
|
69
|
+
/** Error raised when a D1 operation fails. */
|
|
70
|
+
var D1OperationError = class extends Data.TaggedError("D1OperationError") {};
|
|
71
|
+
const isD1Database = (value) => {
|
|
72
|
+
if (typeof value !== "object" || value === null) return false;
|
|
73
|
+
const resource = value;
|
|
74
|
+
return typeof resource.prepare === "function" && typeof resource.batch === "function" && typeof resource.exec === "function";
|
|
75
|
+
};
|
|
76
|
+
const d1Error = (binding, operation, cause) => new D1OperationError({
|
|
77
|
+
binding,
|
|
78
|
+
operation,
|
|
79
|
+
cause
|
|
80
|
+
});
|
|
81
|
+
const tryD1Promise = (binding, operation, evaluate) => Effect.tryPromise({
|
|
82
|
+
try: evaluate,
|
|
83
|
+
catch: (cause) => d1Error(binding, operation, cause)
|
|
84
|
+
});
|
|
85
|
+
const tryD1Sync = (binding, operation, evaluate) => Effect.try({
|
|
86
|
+
try: evaluate,
|
|
87
|
+
catch: (cause) => d1Error(binding, operation, cause)
|
|
88
|
+
});
|
|
89
|
+
/**
|
|
90
|
+
* Creates a typed D1 service tag plus Effect helpers.
|
|
91
|
+
*/
|
|
92
|
+
const make$11 = (id, definition) => Service$5()(id, definition);
|
|
93
|
+
/**
|
|
94
|
+
* Builds a D1 service around a Cloudflare D1 database binding.
|
|
95
|
+
*
|
|
96
|
+
* The returned service exposes the raw `D1Database` binding, small native D1
|
|
97
|
+
* helpers, and `sqlLayer(...)` for providing `effect/unstable/sql` via
|
|
98
|
+
* `@effect/sql-d1`.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* class TodoDatabase extends D1.Service<TodoDatabase>()("TodoDatabase", {
|
|
103
|
+
* binding: "TODO_DB",
|
|
104
|
+
* }) {}
|
|
105
|
+
*
|
|
106
|
+
* const SqlLive = TodoDatabase.sqlLayer();
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
const Service$5 = () => (id, definition) => {
|
|
110
|
+
const tag = Service$6()(id, definition.binding, isD1Database);
|
|
111
|
+
const sqlLayer = (options) => Layer.unwrap(Effect.gen(function* () {
|
|
112
|
+
const db = yield* tag;
|
|
113
|
+
return D1Client.layer({
|
|
114
|
+
...options,
|
|
115
|
+
db
|
|
116
|
+
});
|
|
117
|
+
})).pipe(Layer.provide(tag.layer));
|
|
118
|
+
const prepare = Effect.fnUntraced(function* (query) {
|
|
119
|
+
const db = yield* tag;
|
|
120
|
+
return yield* tryD1Sync(definition.binding, "prepare", () => db.prepare(query));
|
|
121
|
+
});
|
|
122
|
+
const batch = Effect.fnUntraced(function* (statements) {
|
|
123
|
+
const db = yield* tag;
|
|
124
|
+
return yield* tryD1Promise(definition.binding, "batch", () => db.batch([...statements]));
|
|
125
|
+
});
|
|
126
|
+
const exec = Effect.fnUntraced(function* (query) {
|
|
127
|
+
const db = yield* tag;
|
|
128
|
+
return yield* tryD1Promise(definition.binding, "exec", () => db.exec(query));
|
|
129
|
+
});
|
|
130
|
+
const unsafeRaw = Effect.fnUntraced(function* () {
|
|
131
|
+
return yield* tag;
|
|
132
|
+
});
|
|
133
|
+
return Object.assign(tag, {
|
|
134
|
+
[TypeId$5]: TypeId$5,
|
|
135
|
+
definition,
|
|
136
|
+
sqlLayer,
|
|
137
|
+
prepare,
|
|
138
|
+
batch,
|
|
139
|
+
exec,
|
|
140
|
+
unsafeRaw
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
//#endregion
|
|
63
144
|
//#region src/QueueBinding.ts
|
|
64
145
|
var QueueBinding_exports = /* @__PURE__ */ __exportAll({
|
|
65
146
|
QueueOperationError: () => QueueOperationError,
|
|
@@ -88,32 +169,43 @@ const make$10 = (id, definition) => Service$4()(id, definition);
|
|
|
88
169
|
* Builds an Effect service around a Cloudflare Queue producer binding.
|
|
89
170
|
*/
|
|
90
171
|
const Service$4 = () => (id, definition) => {
|
|
91
|
-
const tag = Service$5()(id, definition.binding, (value) => isQueue(value));
|
|
92
172
|
const encodeMessage = Schema.encodeEffect(definition.message);
|
|
173
|
+
const makeClient = (queue) => ({
|
|
174
|
+
send: Effect.fnUntraced(function* (message, options) {
|
|
175
|
+
const encoded = yield* encodeMessage(message);
|
|
176
|
+
yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
|
|
177
|
+
}),
|
|
178
|
+
sendBatch: Effect.fnUntraced(function* (messages, options) {
|
|
179
|
+
const encodedMessages = [];
|
|
180
|
+
for (const message of messages) encodedMessages.push({
|
|
181
|
+
...message,
|
|
182
|
+
body: yield* encodeMessage(message.body)
|
|
183
|
+
});
|
|
184
|
+
yield* tryQueuePromise(definition.binding, "sendBatch", () => queue.sendBatch(encodedMessages, options));
|
|
185
|
+
}),
|
|
186
|
+
metrics: () => tryQueuePromise(definition.binding, "metrics", () => queue.metrics()),
|
|
187
|
+
unsafeRaw: Effect.succeed(queue)
|
|
188
|
+
});
|
|
189
|
+
const tag = Service$6()(id, definition.binding, (value) => isQueue(value), makeClient);
|
|
93
190
|
const send = Effect.fnUntraced(function* (message, options) {
|
|
94
|
-
|
|
95
|
-
const encoded = yield* encodeMessage(message);
|
|
96
|
-
return yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
|
|
191
|
+
yield* (yield* tag).send(message, options);
|
|
97
192
|
});
|
|
98
193
|
const sendBatch = Effect.fnUntraced(function* (messages, options) {
|
|
99
|
-
|
|
100
|
-
const encodedMessages = [];
|
|
101
|
-
for (const message of messages) encodedMessages.push({
|
|
102
|
-
...message,
|
|
103
|
-
body: yield* encodeMessage(message.body)
|
|
104
|
-
});
|
|
105
|
-
return yield* tryQueuePromise(definition.binding, "sendBatch", () => queue.sendBatch(encodedMessages, options));
|
|
194
|
+
yield* (yield* tag).sendBatch(messages, options);
|
|
106
195
|
});
|
|
107
196
|
const metrics = Effect.fnUntraced(function* () {
|
|
108
|
-
|
|
109
|
-
|
|
197
|
+
return yield* (yield* tag).metrics();
|
|
198
|
+
});
|
|
199
|
+
const unsafeRaw = Effect.fnUntraced(function* () {
|
|
200
|
+
return yield* (yield* tag).unsafeRaw;
|
|
110
201
|
});
|
|
111
202
|
return Object.assign(tag, {
|
|
112
203
|
[TypeId$4]: TypeId$4,
|
|
113
204
|
binding: definition.binding,
|
|
114
205
|
send,
|
|
115
206
|
sendBatch,
|
|
116
|
-
metrics
|
|
207
|
+
metrics,
|
|
208
|
+
unsafeRaw
|
|
117
209
|
});
|
|
118
210
|
};
|
|
119
211
|
//#endregion
|
|
@@ -421,46 +513,63 @@ var ServiceBindingRpcError = class extends Data.TaggedError("ServiceBindingRpcEr
|
|
|
421
513
|
* ```
|
|
422
514
|
*/
|
|
423
515
|
const Service$3 = () => (id, definition) => {
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
const service = yield* tag;
|
|
427
|
-
return yield* Effect.tryPromise({
|
|
516
|
+
const makeClient = (service) => {
|
|
517
|
+
const fetch = (input, init) => Effect.tryPromise({
|
|
428
518
|
try: () => service.fetch(input, init),
|
|
429
519
|
catch: (cause) => new ServiceBindingFetchError({
|
|
430
520
|
binding: definition.binding,
|
|
431
521
|
cause
|
|
432
522
|
})
|
|
433
523
|
});
|
|
524
|
+
const rpc = (method, ...args) => Effect.gen(function* () {
|
|
525
|
+
const methodName = String(method);
|
|
526
|
+
return yield* invokeRpcMethod(service, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
527
|
+
binding: definition.binding,
|
|
528
|
+
method: methodName,
|
|
529
|
+
cause
|
|
530
|
+
}))), (cause) => new ServiceBindingRpcError({
|
|
531
|
+
binding: definition.binding,
|
|
532
|
+
method: methodName,
|
|
533
|
+
cause
|
|
534
|
+
}));
|
|
535
|
+
});
|
|
536
|
+
const call = (method, ...args) => Effect.gen(function* () {
|
|
537
|
+
const methodName = String(method);
|
|
538
|
+
const value = yield* resolve(yield* rpc(method, ...args)).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
539
|
+
binding: definition.binding,
|
|
540
|
+
method: methodName,
|
|
541
|
+
cause
|
|
542
|
+
})));
|
|
543
|
+
if (definition.definition === void 0) return value;
|
|
544
|
+
return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
545
|
+
binding: definition.binding,
|
|
546
|
+
method: methodName,
|
|
547
|
+
cause
|
|
548
|
+
})));
|
|
549
|
+
});
|
|
550
|
+
const scopedCall = (method, ...args) => Effect.gen(function* () {
|
|
551
|
+
return yield* scoped(yield* rpc(method, ...args));
|
|
552
|
+
});
|
|
553
|
+
const directMethods = makeDirectMethods$1(definition.definition, call);
|
|
554
|
+
return Object.assign(directMethods, {
|
|
555
|
+
fetch,
|
|
556
|
+
rpc,
|
|
557
|
+
call,
|
|
558
|
+
scopedCall
|
|
559
|
+
});
|
|
560
|
+
};
|
|
561
|
+
const tag = Service$6()(id, definition.binding, (value) => typeof value === "object" && value !== null && "fetch" in value, makeClient);
|
|
562
|
+
const fetch = (input, init) => Effect.gen(function* () {
|
|
563
|
+
return yield* (yield* tag).fetch(input, init);
|
|
434
564
|
});
|
|
435
565
|
const rpc = (method, ...args) => Effect.gen(function* () {
|
|
436
|
-
|
|
437
|
-
const methodName = String(method);
|
|
438
|
-
return yield* invokeRpcMethod(service, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
439
|
-
binding: definition.binding,
|
|
440
|
-
method: methodName,
|
|
441
|
-
cause
|
|
442
|
-
}))), (cause) => new ServiceBindingRpcError({
|
|
443
|
-
binding: definition.binding,
|
|
444
|
-
method: methodName,
|
|
445
|
-
cause
|
|
446
|
-
}));
|
|
566
|
+
return yield* (yield* tag).rpc(method, ...args);
|
|
447
567
|
});
|
|
448
568
|
const call = (method, ...args) => Effect.gen(function* () {
|
|
449
|
-
|
|
450
|
-
const value = yield* resolve(yield* rpc(method, ...args)).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
451
|
-
binding: definition.binding,
|
|
452
|
-
method: methodName,
|
|
453
|
-
cause
|
|
454
|
-
})));
|
|
455
|
-
if (definition.definition === void 0) return value;
|
|
456
|
-
return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
|
|
457
|
-
binding: definition.binding,
|
|
458
|
-
method: methodName,
|
|
459
|
-
cause
|
|
460
|
-
})));
|
|
569
|
+
return yield* (yield* tag).call(method, ...args);
|
|
461
570
|
});
|
|
462
571
|
const scopedCall = (method, ...args) => Effect.gen(function* () {
|
|
463
|
-
return yield*
|
|
572
|
+
return yield* (yield* tag).scopedCall(method, ...args);
|
|
464
573
|
});
|
|
465
574
|
const directMethods = makeDirectMethods$1(definition.definition, call);
|
|
466
575
|
return Object.assign(tag, directMethods, {
|
|
@@ -1006,24 +1115,87 @@ var DurableObjectFetchError = class extends Data.TaggedError("DurableObjectFetch
|
|
|
1006
1115
|
const Service$2 = () => (id, definition) => {
|
|
1007
1116
|
const hasFunction = (value, key) => typeof Reflect.get(value, key) === "function";
|
|
1008
1117
|
const isDurableObjectNamespaceClient = (value) => typeof value === "object" && value !== null && hasFunction(value, "getByName") && hasFunction(value, "get") && hasFunction(value, "idFromName") && hasFunction(value, "idFromString") && hasFunction(value, "newUniqueId") && hasFunction(value, "jurisdiction");
|
|
1009
|
-
const
|
|
1118
|
+
const makeClient = (namespace) => {
|
|
1119
|
+
const newUniqueId = (options) => Effect.sync(() => namespace.newUniqueId(options));
|
|
1120
|
+
const idFromName = (name) => Effect.sync(() => namespace.idFromName(name));
|
|
1121
|
+
const idFromString = (id) => Effect.sync(() => namespace.idFromString(id));
|
|
1122
|
+
const get = (id, options) => Effect.sync(() => namespace.get(id, options));
|
|
1123
|
+
const getByName = (name, options) => Effect.sync(() => namespace.getByName(name, options));
|
|
1124
|
+
const jurisdiction = (value) => Effect.sync(() => namespace.jurisdiction(value));
|
|
1125
|
+
const fetch = (stub, input, init) => Effect.tryPromise({
|
|
1126
|
+
try: () => stub.fetch(input, init),
|
|
1127
|
+
catch: (cause) => new DurableObjectFetchError({
|
|
1128
|
+
binding: definition.binding,
|
|
1129
|
+
cause
|
|
1130
|
+
})
|
|
1131
|
+
});
|
|
1132
|
+
const rpc = (stub, method, ...args) => Effect.gen(function* () {
|
|
1133
|
+
const methodName = String(method);
|
|
1134
|
+
return yield* invokeRpcMethod(stub, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
|
|
1135
|
+
binding: definition.binding,
|
|
1136
|
+
method: methodName,
|
|
1137
|
+
cause
|
|
1138
|
+
}))), (cause) => new DurableObjectRpcError({
|
|
1139
|
+
binding: definition.binding,
|
|
1140
|
+
method: methodName,
|
|
1141
|
+
cause
|
|
1142
|
+
}));
|
|
1143
|
+
});
|
|
1144
|
+
const call = (stub, method, ...args) => Effect.gen(function* () {
|
|
1145
|
+
const methodName = String(method);
|
|
1146
|
+
const value = yield* resolve(yield* rpc(stub, method, ...args)).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
|
|
1147
|
+
binding: definition.binding,
|
|
1148
|
+
method: methodName,
|
|
1149
|
+
cause
|
|
1150
|
+
})));
|
|
1151
|
+
if (definition.definition === void 0) return value;
|
|
1152
|
+
return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new DurableObjectRpcError({
|
|
1153
|
+
binding: definition.binding,
|
|
1154
|
+
method: methodName,
|
|
1155
|
+
cause
|
|
1156
|
+
})));
|
|
1157
|
+
});
|
|
1158
|
+
const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
|
|
1159
|
+
return yield* scoped(yield* rpc(stub, method, ...args));
|
|
1160
|
+
});
|
|
1161
|
+
const directMethods = makeDirectMethods(definition.definition, {
|
|
1162
|
+
call,
|
|
1163
|
+
fetch,
|
|
1164
|
+
get,
|
|
1165
|
+
getByName
|
|
1166
|
+
});
|
|
1167
|
+
return Object.assign(directMethods, {
|
|
1168
|
+
newUniqueId,
|
|
1169
|
+
idFromName,
|
|
1170
|
+
idFromString,
|
|
1171
|
+
get,
|
|
1172
|
+
getByName,
|
|
1173
|
+
jurisdiction,
|
|
1174
|
+
fetch,
|
|
1175
|
+
rpc,
|
|
1176
|
+
call,
|
|
1177
|
+
scopedCall,
|
|
1178
|
+
unsafeRaw: Effect.succeed(namespace)
|
|
1179
|
+
});
|
|
1180
|
+
};
|
|
1181
|
+
const tag = Service$6()(id, definition.binding, (value) => isDurableObjectNamespaceClient(value), makeClient);
|
|
1010
1182
|
const newUniqueId = Effect.fnUntraced(function* (options) {
|
|
1011
|
-
return (yield* tag).newUniqueId(options);
|
|
1183
|
+
return yield* (yield* tag).newUniqueId(options);
|
|
1012
1184
|
});
|
|
1013
1185
|
const idFromName = Effect.fnUntraced(function* (name) {
|
|
1014
|
-
return (yield* tag).idFromName(name);
|
|
1186
|
+
return yield* (yield* tag).idFromName(name);
|
|
1015
1187
|
});
|
|
1016
1188
|
const idFromString = Effect.fnUntraced(function* (id) {
|
|
1017
|
-
return (yield* tag).idFromString(id);
|
|
1189
|
+
return yield* (yield* tag).idFromString(id);
|
|
1018
1190
|
});
|
|
1019
1191
|
const get = Effect.fnUntraced(function* (id, options) {
|
|
1020
|
-
return (yield* tag).get(id, options);
|
|
1192
|
+
return yield* (yield* tag).get(id, options);
|
|
1021
1193
|
});
|
|
1022
1194
|
const getByName = Effect.fnUntraced(function* (name, options) {
|
|
1023
|
-
return (yield* tag).getByName(name, options);
|
|
1195
|
+
return yield* (yield* tag).getByName(name, options);
|
|
1024
1196
|
});
|
|
1025
1197
|
const jurisdiction = Effect.fnUntraced(function* (value) {
|
|
1026
|
-
return (yield* tag).jurisdiction(value);
|
|
1198
|
+
return yield* (yield* tag).jurisdiction(value);
|
|
1027
1199
|
});
|
|
1028
1200
|
const fetch = (stub, input, init) => Effect.tryPromise({
|
|
1029
1201
|
try: () => stub.fetch(input, init),
|
|
@@ -1061,6 +1233,9 @@ const Service$2 = () => (id, definition) => {
|
|
|
1061
1233
|
const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
|
|
1062
1234
|
return yield* scoped(yield* rpc(stub, method, ...args));
|
|
1063
1235
|
});
|
|
1236
|
+
const unsafeRaw = Effect.fnUntraced(function* () {
|
|
1237
|
+
return yield* (yield* tag).unsafeRaw;
|
|
1238
|
+
});
|
|
1064
1239
|
const directMethods = makeDirectMethods(definition.definition, {
|
|
1065
1240
|
call,
|
|
1066
1241
|
fetch,
|
|
@@ -1079,7 +1254,8 @@ const Service$2 = () => (id, definition) => {
|
|
|
1079
1254
|
fetch,
|
|
1080
1255
|
rpc,
|
|
1081
1256
|
call,
|
|
1082
|
-
scopedCall
|
|
1257
|
+
scopedCall,
|
|
1258
|
+
unsafeRaw
|
|
1083
1259
|
});
|
|
1084
1260
|
};
|
|
1085
1261
|
const makeDirectMethods = (rpcDefinition, helpers) => {
|
|
@@ -1770,69 +1946,83 @@ const Tag$2 = () => (id, definition) => {
|
|
|
1770
1946
|
* ```
|
|
1771
1947
|
*/
|
|
1772
1948
|
const Service$1 = () => (id, definition) => {
|
|
1773
|
-
const tag = Service$5()(id, definition.binding, (value) => {
|
|
1774
|
-
if (typeof value !== "object" || value === null) return false;
|
|
1775
|
-
const resource = value;
|
|
1776
|
-
return typeof resource.get === "function" && typeof resource.put === "function" && typeof resource.delete === "function" && typeof resource.getWithMetadata === "function" && typeof resource.list === "function";
|
|
1777
|
-
});
|
|
1778
1949
|
const encodeKey = Schema.encodeEffect(definition.key);
|
|
1779
1950
|
const decodeKey = Schema.decodeUnknownEffect(definition.key);
|
|
1780
1951
|
const encodeValue = Schema.encodeEffect(Schema.fromJsonString(Schema.toCodecJson(definition.value)));
|
|
1781
1952
|
const decodeValue = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.toCodecJson(definition.value)));
|
|
1953
|
+
const makeClient = (kv) => ({
|
|
1954
|
+
definition,
|
|
1955
|
+
put: Effect.fnUntraced(function* (key, value, options) {
|
|
1956
|
+
const keyEncoded = yield* encodeKey(key);
|
|
1957
|
+
const valueEncoded = yield* encodeValue(value);
|
|
1958
|
+
yield* tryKvPromise(definition.binding, "put", () => kv.put(keyEncoded, valueEncoded, options));
|
|
1959
|
+
}),
|
|
1960
|
+
get: Effect.fnUntraced(function* (key) {
|
|
1961
|
+
const keyEncoded = yield* encodeKey(key);
|
|
1962
|
+
const valueEncoded = yield* tryKvPromise(definition.binding, "get", () => kv.get(keyEncoded));
|
|
1963
|
+
if (valueEncoded === null) return Option.none();
|
|
1964
|
+
return yield* decodeValue(valueEncoded).pipe(Effect.map(Option.some));
|
|
1965
|
+
}),
|
|
1966
|
+
getWithMetadata: Effect.fnUntraced(function* (key, metadataSchema) {
|
|
1967
|
+
const keyEncoded = yield* encodeKey(key);
|
|
1968
|
+
const result = yield* tryKvPromise(definition.binding, "getWithMetadata", () => kv.getWithMetadata(keyEncoded));
|
|
1969
|
+
if (result.value === null) return Option.none();
|
|
1970
|
+
const value = yield* decodeValue(result.value);
|
|
1971
|
+
const metadata = result.metadata === null ? Option.none() : Option.some(yield* Schema.decodeUnknownEffect(metadataSchema)(result.metadata));
|
|
1972
|
+
return Option.some({
|
|
1973
|
+
value,
|
|
1974
|
+
metadata,
|
|
1975
|
+
cacheStatus: maybeString(result.cacheStatus)
|
|
1976
|
+
});
|
|
1977
|
+
}),
|
|
1978
|
+
list: Effect.fnUntraced(function* (options) {
|
|
1979
|
+
const { metadataSchema, ...kvOptions } = options ?? {};
|
|
1980
|
+
const result = yield* tryKvPromise(definition.binding, "list", () => kv.list(kvOptions));
|
|
1981
|
+
const keys = [];
|
|
1982
|
+
for (const key of result.keys) {
|
|
1983
|
+
const decodedName = yield* decodeKey(key.name);
|
|
1984
|
+
const decodedMetadata = key.metadata === void 0 ? Option.none() : metadataSchema === void 0 ? Option.some(key.metadata) : Option.some(yield* Schema.decodeUnknownEffect(metadataSchema)(key.metadata));
|
|
1985
|
+
keys.push({
|
|
1986
|
+
name: decodedName,
|
|
1987
|
+
expiration: maybeNumber(key.expiration),
|
|
1988
|
+
metadata: decodedMetadata
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
return {
|
|
1992
|
+
keys,
|
|
1993
|
+
listComplete: result.list_complete,
|
|
1994
|
+
cursor: maybeString("cursor" in result ? result.cursor : void 0),
|
|
1995
|
+
cacheStatus: maybeString(result.cacheStatus)
|
|
1996
|
+
};
|
|
1997
|
+
}),
|
|
1998
|
+
remove: Effect.fnUntraced(function* (key) {
|
|
1999
|
+
const keyEncoded = yield* encodeKey(key);
|
|
2000
|
+
yield* tryKvPromise(definition.binding, "delete", () => kv.delete(keyEncoded));
|
|
2001
|
+
}),
|
|
2002
|
+
unsafeRaw: Effect.succeed(kv)
|
|
2003
|
+
});
|
|
2004
|
+
const tag = Service$6()(id, definition.binding, (value) => {
|
|
2005
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2006
|
+
const resource = value;
|
|
2007
|
+
return typeof resource.get === "function" && typeof resource.put === "function" && typeof resource.delete === "function" && typeof resource.getWithMetadata === "function" && typeof resource.list === "function";
|
|
2008
|
+
}, makeClient);
|
|
1782
2009
|
const put = Effect.fnUntraced(function* (key, value, options) {
|
|
1783
|
-
|
|
1784
|
-
const keyEncoded = yield* encodeKey(key);
|
|
1785
|
-
const valueEncoded = yield* encodeValue(value);
|
|
1786
|
-
yield* tryKvPromise(definition.binding, "put", () => kv.put(keyEncoded, valueEncoded, options));
|
|
2010
|
+
yield* (yield* tag).put(key, value, options);
|
|
1787
2011
|
});
|
|
1788
2012
|
const get = Effect.fnUntraced(function* (key) {
|
|
1789
|
-
|
|
1790
|
-
const keyEncoded = yield* encodeKey(key);
|
|
1791
|
-
const valueEncoded = yield* tryKvPromise(definition.binding, "get", () => kv.get(keyEncoded));
|
|
1792
|
-
if (valueEncoded === null) return Option.none();
|
|
1793
|
-
return yield* decodeValue(valueEncoded).pipe(Effect.map(Option.some));
|
|
2013
|
+
return yield* (yield* tag).get(key);
|
|
1794
2014
|
});
|
|
1795
2015
|
const getWithMetadata = Effect.fnUntraced(function* (key, metadataSchema) {
|
|
1796
|
-
|
|
1797
|
-
const keyEncoded = yield* encodeKey(key);
|
|
1798
|
-
const result = yield* tryKvPromise(definition.binding, "getWithMetadata", () => kv.getWithMetadata(keyEncoded));
|
|
1799
|
-
if (result.value === null) return Option.none();
|
|
1800
|
-
const value = yield* decodeValue(result.value);
|
|
1801
|
-
const metadata = result.metadata === null ? Option.none() : Option.some(yield* Schema.decodeUnknownEffect(metadataSchema)(result.metadata));
|
|
1802
|
-
return Option.some({
|
|
1803
|
-
value,
|
|
1804
|
-
metadata,
|
|
1805
|
-
cacheStatus: maybeString(result.cacheStatus)
|
|
1806
|
-
});
|
|
2016
|
+
return yield* (yield* tag).getWithMetadata(key, metadataSchema);
|
|
1807
2017
|
});
|
|
1808
2018
|
const list = Effect.fnUntraced(function* (options) {
|
|
1809
|
-
|
|
1810
|
-
const { metadataSchema, ...kvOptions } = options ?? {};
|
|
1811
|
-
const result = yield* tryKvPromise(definition.binding, "list", () => kv.list(kvOptions));
|
|
1812
|
-
const keys = [];
|
|
1813
|
-
for (const key of result.keys) {
|
|
1814
|
-
const decodedName = yield* decodeKey(key.name);
|
|
1815
|
-
const decodedMetadata = key.metadata === void 0 ? Option.none() : metadataSchema === void 0 ? Option.some(key.metadata) : Option.some(yield* Schema.decodeUnknownEffect(metadataSchema)(key.metadata));
|
|
1816
|
-
keys.push({
|
|
1817
|
-
name: decodedName,
|
|
1818
|
-
expiration: maybeNumber(key.expiration),
|
|
1819
|
-
metadata: decodedMetadata
|
|
1820
|
-
});
|
|
1821
|
-
}
|
|
1822
|
-
return {
|
|
1823
|
-
keys,
|
|
1824
|
-
listComplete: result.list_complete,
|
|
1825
|
-
cursor: maybeString("cursor" in result ? result.cursor : void 0),
|
|
1826
|
-
cacheStatus: maybeString(result.cacheStatus)
|
|
1827
|
-
};
|
|
2019
|
+
return yield* (yield* tag).list(options);
|
|
1828
2020
|
});
|
|
1829
2021
|
const remove = Effect.fnUntraced(function* (key) {
|
|
1830
|
-
|
|
1831
|
-
const keyEncoded = yield* encodeKey(key);
|
|
1832
|
-
yield* tryKvPromise(definition.binding, "delete", () => kv.delete(keyEncoded));
|
|
2022
|
+
yield* (yield* tag).remove(key);
|
|
1833
2023
|
});
|
|
1834
2024
|
const unsafeRaw = Effect.fnUntraced(function* () {
|
|
1835
|
-
return yield* tag;
|
|
2025
|
+
return yield* (yield* tag).unsafeRaw;
|
|
1836
2026
|
});
|
|
1837
2027
|
return Object.assign(tag, {
|
|
1838
2028
|
[TypeId$1]: TypeId$1,
|
|
@@ -1872,7 +2062,7 @@ const isWorkflow = (value) => {
|
|
|
1872
2062
|
};
|
|
1873
2063
|
const make$2 = (id, definition) => Service()(id, definition);
|
|
1874
2064
|
const Service = () => (id, definition) => {
|
|
1875
|
-
const tag = Service$
|
|
2065
|
+
const tag = Service$6()(id, definition.binding, (value) => isWorkflow(value));
|
|
1876
2066
|
const encodePayload = Schema.encodeEffect(definition.payload);
|
|
1877
2067
|
const decodeResult = Schema.decodeUnknownEffect(definition.result);
|
|
1878
2068
|
const wrapInstance = (raw) => {
|
|
@@ -2056,4 +2246,4 @@ const waitForEvent = (name, options) => Effect.flatMap(WorkflowStep$1.asEffect()
|
|
|
2056
2246
|
const Tag = Tag$1;
|
|
2057
2247
|
const implement = implement$1;
|
|
2058
2248
|
//#endregion
|
|
2059
|
-
export { Binding_exports as Binding, DurableObject_exports as DurableObject, DurableObjectAlarm_exports as DurableObjectAlarm, DurableObjectDefinition_exports as DurableObjectDefinition, DurableObjectNamespace_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_exports as DurableObjectRpcWebSocket, DurableObjectState_exports as DurableObjectState, DurableObjectStorage_exports as DurableObjectStorage, DurableObjectWebSocket_exports as DurableObjectWebSocket, Kv_exports as Kv, Queue_exports as Queue, QueueBinding_exports as QueueBinding, QueueDefinition_exports as QueueDefinition, Rpc_exports as Rpc, RpcDefinition_exports as RpcDefinition, ServiceBinding_exports as ServiceBinding, Worker_exports as Worker, WorkerConfig, WorkerDefinition_exports as WorkerDefinition, WorkerEnvironment, Workflow_exports as Workflow, WorkflowBinding_exports as WorkflowBinding, WorkflowDefinition_exports as WorkflowDefinition };
|
|
2249
|
+
export { Binding_exports as Binding, D1_exports as D1, DurableObject_exports as DurableObject, DurableObjectAlarm_exports as DurableObjectAlarm, DurableObjectDefinition_exports as DurableObjectDefinition, DurableObjectNamespace_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_exports as DurableObjectRpcWebSocket, DurableObjectState_exports as DurableObjectState, DurableObjectStorage_exports as DurableObjectStorage, DurableObjectWebSocket_exports as DurableObjectWebSocket, Kv_exports as Kv, Queue_exports as Queue, QueueBinding_exports as QueueBinding, QueueDefinition_exports as QueueDefinition, Rpc_exports as Rpc, RpcDefinition_exports as RpcDefinition, ServiceBinding_exports as ServiceBinding, Worker_exports as Worker, WorkerConfig, WorkerDefinition_exports as WorkerDefinition, WorkerEnvironment, 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.6.0",
|
|
4
4
|
"description": "Effect-native primitives for Cloudflare Workers and bindings.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@cloudflare/vitest-pool-workers": "^0.15.0",
|
|
38
38
|
"@cloudflare/workers-types": "^4.20260421.1",
|
|
39
|
+
"@effect/sql-d1": "catalog:",
|
|
39
40
|
"@effect/vitest": "catalog:",
|
|
40
41
|
"effect": "catalog:",
|
|
41
42
|
"typescript": "^6.0.2",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"vitest": "catalog:"
|
|
44
45
|
},
|
|
45
46
|
"peerDependencies": {
|
|
47
|
+
"@effect/sql-d1": "^4.0.0-beta.65",
|
|
46
48
|
"effect": "^4.0.0-beta.65"
|
|
47
49
|
}
|
|
48
50
|
}
|
package/src/Binding.ts
CHANGED
|
@@ -45,20 +45,36 @@ const getBinding = <Resource>(
|
|
|
45
45
|
/**
|
|
46
46
|
* Creates a Context tag + layer for reading and validating a Cloudflare binding.
|
|
47
47
|
*/
|
|
48
|
+
export interface BindingService<Self, Id extends string, Service> extends Context.ServiceClass<
|
|
49
|
+
Self,
|
|
50
|
+
Id,
|
|
51
|
+
Service
|
|
52
|
+
> {
|
|
53
|
+
readonly [TypeId]: typeof TypeId;
|
|
54
|
+
readonly binding: string;
|
|
55
|
+
readonly layer: Layer.Layer<
|
|
56
|
+
Self,
|
|
57
|
+
BindingNotFoundError | BindingValidationError,
|
|
58
|
+
WorkerEnvironment
|
|
59
|
+
>;
|
|
60
|
+
}
|
|
61
|
+
|
|
48
62
|
export const Service =
|
|
49
63
|
<Self>() =>
|
|
50
|
-
<Id extends string, Resource>(
|
|
64
|
+
<Id extends string, Resource, Service = Resource>(
|
|
51
65
|
id: Id,
|
|
52
66
|
binding: string,
|
|
53
67
|
isResource: (value: unknown) => value is Resource,
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
wrap?: (resource: Resource) => Service,
|
|
69
|
+
): BindingService<Self, Id, Service> => {
|
|
70
|
+
const tag = Context.Service<Self, Service>()(id);
|
|
56
71
|
|
|
57
72
|
const layer = Layer.effect(
|
|
58
73
|
tag,
|
|
59
74
|
Effect.gen(function* () {
|
|
60
75
|
const env = yield* WorkerEnvironment;
|
|
61
|
-
|
|
76
|
+
const resource = yield* getBinding(env, binding, isResource);
|
|
77
|
+
return wrap === undefined ? (resource as unknown as Service) : wrap(resource);
|
|
62
78
|
}),
|
|
63
79
|
);
|
|
64
80
|
|
|
@@ -66,5 +82,5 @@ export const Service =
|
|
|
66
82
|
[TypeId]: TypeId,
|
|
67
83
|
binding,
|
|
68
84
|
layer,
|
|
69
|
-
})
|
|
85
|
+
}) as BindingService<Self, Id, Service>;
|
|
70
86
|
};
|