effect-cf 0.5.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/dist/index.mjs CHANGED
@@ -46,13 +46,11 @@ const getBinding = (env, binding, isResource) => Effect.gen(function* () {
46
46
  if (!isResource(resource)) return yield* Effect.fail(new BindingValidationError({ binding }));
47
47
  return resource;
48
48
  });
49
- /**
50
- * Creates a Context tag + layer for reading and validating a Cloudflare binding.
51
- */
52
- const Service$6 = () => (id, binding, isResource) => {
49
+ const Service$6 = () => (id, binding, isResource, wrap) => {
53
50
  const tag = Context.Service()(id);
54
51
  const layer = Layer.effect(tag, Effect.gen(function* () {
55
- return yield* getBinding(yield* WorkerEnvironment, binding, isResource);
52
+ const resource = yield* getBinding(yield* WorkerEnvironment, binding, isResource);
53
+ return wrap === void 0 ? resource : wrap(resource);
56
54
  }));
57
55
  return Object.assign(tag, {
58
56
  [TypeId$6]: TypeId$6,
@@ -171,32 +169,43 @@ const make$10 = (id, definition) => Service$4()(id, definition);
171
169
  * Builds an Effect service around a Cloudflare Queue producer binding.
172
170
  */
173
171
  const Service$4 = () => (id, definition) => {
174
- const tag = Service$6()(id, definition.binding, (value) => isQueue(value));
175
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);
176
190
  const send = Effect.fnUntraced(function* (message, options) {
177
- const queue = yield* tag;
178
- const encoded = yield* encodeMessage(message);
179
- return yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
191
+ yield* (yield* tag).send(message, options);
180
192
  });
181
193
  const sendBatch = Effect.fnUntraced(function* (messages, options) {
182
- const queue = yield* tag;
183
- const encodedMessages = [];
184
- for (const message of messages) encodedMessages.push({
185
- ...message,
186
- body: yield* encodeMessage(message.body)
187
- });
188
- return yield* tryQueuePromise(definition.binding, "sendBatch", () => queue.sendBatch(encodedMessages, options));
194
+ yield* (yield* tag).sendBatch(messages, options);
189
195
  });
190
196
  const metrics = Effect.fnUntraced(function* () {
191
- const queue = yield* tag;
192
- return yield* tryQueuePromise(definition.binding, "metrics", () => queue.metrics());
197
+ return yield* (yield* tag).metrics();
198
+ });
199
+ const unsafeRaw = Effect.fnUntraced(function* () {
200
+ return yield* (yield* tag).unsafeRaw;
193
201
  });
194
202
  return Object.assign(tag, {
195
203
  [TypeId$4]: TypeId$4,
196
204
  binding: definition.binding,
197
205
  send,
198
206
  sendBatch,
199
- metrics
207
+ metrics,
208
+ unsafeRaw
200
209
  });
201
210
  };
202
211
  //#endregion
@@ -504,46 +513,63 @@ var ServiceBindingRpcError = class extends Data.TaggedError("ServiceBindingRpcEr
504
513
  * ```
505
514
  */
506
515
  const Service$3 = () => (id, definition) => {
507
- const tag = Service$6()(id, definition.binding, (value) => typeof value === "object" && value !== null && "fetch" in value);
508
- const fetch = (input, init) => Effect.gen(function* () {
509
- const service = yield* tag;
510
- return yield* Effect.tryPromise({
516
+ const makeClient = (service) => {
517
+ const fetch = (input, init) => Effect.tryPromise({
511
518
  try: () => service.fetch(input, init),
512
519
  catch: (cause) => new ServiceBindingFetchError({
513
520
  binding: definition.binding,
514
521
  cause
515
522
  })
516
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);
517
564
  });
518
565
  const rpc = (method, ...args) => Effect.gen(function* () {
519
- const service = yield* tag;
520
- const methodName = String(method);
521
- return yield* invokeRpcMethod(service, method, definition.definition === void 0 ? args : yield* encodeArgs(definition.definition, methodName, args).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
522
- binding: definition.binding,
523
- method: methodName,
524
- cause
525
- }))), (cause) => new ServiceBindingRpcError({
526
- binding: definition.binding,
527
- method: methodName,
528
- cause
529
- }));
566
+ return yield* (yield* tag).rpc(method, ...args);
530
567
  });
531
568
  const call = (method, ...args) => Effect.gen(function* () {
532
- const methodName = String(method);
533
- const value = yield* resolve(yield* rpc(method, ...args)).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
534
- binding: definition.binding,
535
- method: methodName,
536
- cause
537
- })));
538
- if (definition.definition === void 0) return value;
539
- return yield* decodeSuccess(definition.definition, methodName, value).pipe(Effect.mapError((cause) => new ServiceBindingRpcError({
540
- binding: definition.binding,
541
- method: methodName,
542
- cause
543
- })));
569
+ return yield* (yield* tag).call(method, ...args);
544
570
  });
545
571
  const scopedCall = (method, ...args) => Effect.gen(function* () {
546
- return yield* scoped(yield* rpc(method, ...args));
572
+ return yield* (yield* tag).scopedCall(method, ...args);
547
573
  });
548
574
  const directMethods = makeDirectMethods$1(definition.definition, call);
549
575
  return Object.assign(tag, directMethods, {
@@ -1089,24 +1115,87 @@ var DurableObjectFetchError = class extends Data.TaggedError("DurableObjectFetch
1089
1115
  const Service$2 = () => (id, definition) => {
1090
1116
  const hasFunction = (value, key) => typeof Reflect.get(value, key) === "function";
1091
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");
1092
- const tag = Service$6()(id, definition.binding, (value) => isDurableObjectNamespaceClient(value));
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);
1093
1182
  const newUniqueId = Effect.fnUntraced(function* (options) {
1094
- return (yield* tag).newUniqueId(options);
1183
+ return yield* (yield* tag).newUniqueId(options);
1095
1184
  });
1096
1185
  const idFromName = Effect.fnUntraced(function* (name) {
1097
- return (yield* tag).idFromName(name);
1186
+ return yield* (yield* tag).idFromName(name);
1098
1187
  });
1099
1188
  const idFromString = Effect.fnUntraced(function* (id) {
1100
- return (yield* tag).idFromString(id);
1189
+ return yield* (yield* tag).idFromString(id);
1101
1190
  });
1102
1191
  const get = Effect.fnUntraced(function* (id, options) {
1103
- return (yield* tag).get(id, options);
1192
+ return yield* (yield* tag).get(id, options);
1104
1193
  });
1105
1194
  const getByName = Effect.fnUntraced(function* (name, options) {
1106
- return (yield* tag).getByName(name, options);
1195
+ return yield* (yield* tag).getByName(name, options);
1107
1196
  });
1108
1197
  const jurisdiction = Effect.fnUntraced(function* (value) {
1109
- return (yield* tag).jurisdiction(value);
1198
+ return yield* (yield* tag).jurisdiction(value);
1110
1199
  });
1111
1200
  const fetch = (stub, input, init) => Effect.tryPromise({
1112
1201
  try: () => stub.fetch(input, init),
@@ -1144,6 +1233,9 @@ const Service$2 = () => (id, definition) => {
1144
1233
  const scopedCall = (stub, method, ...args) => Effect.gen(function* () {
1145
1234
  return yield* scoped(yield* rpc(stub, method, ...args));
1146
1235
  });
1236
+ const unsafeRaw = Effect.fnUntraced(function* () {
1237
+ return yield* (yield* tag).unsafeRaw;
1238
+ });
1147
1239
  const directMethods = makeDirectMethods(definition.definition, {
1148
1240
  call,
1149
1241
  fetch,
@@ -1162,7 +1254,8 @@ const Service$2 = () => (id, definition) => {
1162
1254
  fetch,
1163
1255
  rpc,
1164
1256
  call,
1165
- scopedCall
1257
+ scopedCall,
1258
+ unsafeRaw
1166
1259
  });
1167
1260
  };
1168
1261
  const makeDirectMethods = (rpcDefinition, helpers) => {
@@ -1853,69 +1946,83 @@ const Tag$2 = () => (id, definition) => {
1853
1946
  * ```
1854
1947
  */
1855
1948
  const Service$1 = () => (id, definition) => {
1856
- const tag = Service$6()(id, definition.binding, (value) => {
1857
- if (typeof value !== "object" || value === null) return false;
1858
- const resource = value;
1859
- return typeof resource.get === "function" && typeof resource.put === "function" && typeof resource.delete === "function" && typeof resource.getWithMetadata === "function" && typeof resource.list === "function";
1860
- });
1861
1949
  const encodeKey = Schema.encodeEffect(definition.key);
1862
1950
  const decodeKey = Schema.decodeUnknownEffect(definition.key);
1863
1951
  const encodeValue = Schema.encodeEffect(Schema.fromJsonString(Schema.toCodecJson(definition.value)));
1864
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);
1865
2009
  const put = Effect.fnUntraced(function* (key, value, options) {
1866
- const kv = yield* tag;
1867
- const keyEncoded = yield* encodeKey(key);
1868
- const valueEncoded = yield* encodeValue(value);
1869
- yield* tryKvPromise(definition.binding, "put", () => kv.put(keyEncoded, valueEncoded, options));
2010
+ yield* (yield* tag).put(key, value, options);
1870
2011
  });
1871
2012
  const get = Effect.fnUntraced(function* (key) {
1872
- const kv = yield* tag;
1873
- const keyEncoded = yield* encodeKey(key);
1874
- const valueEncoded = yield* tryKvPromise(definition.binding, "get", () => kv.get(keyEncoded));
1875
- if (valueEncoded === null) return Option.none();
1876
- return yield* decodeValue(valueEncoded).pipe(Effect.map(Option.some));
2013
+ return yield* (yield* tag).get(key);
1877
2014
  });
1878
2015
  const getWithMetadata = Effect.fnUntraced(function* (key, metadataSchema) {
1879
- const kv = yield* tag;
1880
- const keyEncoded = yield* encodeKey(key);
1881
- const result = yield* tryKvPromise(definition.binding, "getWithMetadata", () => kv.getWithMetadata(keyEncoded));
1882
- if (result.value === null) return Option.none();
1883
- const value = yield* decodeValue(result.value);
1884
- const metadata = result.metadata === null ? Option.none() : Option.some(yield* Schema.decodeUnknownEffect(metadataSchema)(result.metadata));
1885
- return Option.some({
1886
- value,
1887
- metadata,
1888
- cacheStatus: maybeString(result.cacheStatus)
1889
- });
2016
+ return yield* (yield* tag).getWithMetadata(key, metadataSchema);
1890
2017
  });
1891
2018
  const list = Effect.fnUntraced(function* (options) {
1892
- const kv = yield* tag;
1893
- const { metadataSchema, ...kvOptions } = options ?? {};
1894
- const result = yield* tryKvPromise(definition.binding, "list", () => kv.list(kvOptions));
1895
- const keys = [];
1896
- for (const key of result.keys) {
1897
- const decodedName = yield* decodeKey(key.name);
1898
- const decodedMetadata = key.metadata === void 0 ? Option.none() : metadataSchema === void 0 ? Option.some(key.metadata) : Option.some(yield* Schema.decodeUnknownEffect(metadataSchema)(key.metadata));
1899
- keys.push({
1900
- name: decodedName,
1901
- expiration: maybeNumber(key.expiration),
1902
- metadata: decodedMetadata
1903
- });
1904
- }
1905
- return {
1906
- keys,
1907
- listComplete: result.list_complete,
1908
- cursor: maybeString("cursor" in result ? result.cursor : void 0),
1909
- cacheStatus: maybeString(result.cacheStatus)
1910
- };
2019
+ return yield* (yield* tag).list(options);
1911
2020
  });
1912
2021
  const remove = Effect.fnUntraced(function* (key) {
1913
- const kv = yield* tag;
1914
- const keyEncoded = yield* encodeKey(key);
1915
- yield* tryKvPromise(definition.binding, "delete", () => kv.delete(keyEncoded));
2022
+ yield* (yield* tag).remove(key);
1916
2023
  });
1917
2024
  const unsafeRaw = Effect.fnUntraced(function* () {
1918
- return yield* tag;
2025
+ return yield* (yield* tag).unsafeRaw;
1919
2026
  });
1920
2027
  return Object.assign(tag, {
1921
2028
  [TypeId$1]: TypeId$1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
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
- const tag = Context.Service<Self, Resource>()(id);
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
- return yield* getBinding(env, binding, isResource);
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
  };