effect-cf 0.23.1 → 0.25.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 +20 -0
- package/README.md +157 -7
- package/dist/{Hyperdrive-COyg7R26.d.mts → Binding-DI7u3fEY.d.mts} +5 -39
- package/dist/DurableObjectState-B5RCFnRy.mjs +384 -0
- package/dist/Hyperdrive-BwYp8Rsz.d.mts +36 -0
- package/dist/HyperdrivePg.d.mts +2 -1
- package/dist/Vitest.d.mts +192 -0
- package/dist/Vitest.mjs +184 -0
- package/dist/WorkflowBinding--eMVaixT.d.mts +1081 -0
- package/dist/index.d.mts +84 -1177
- package/dist/index.mjs +18 -435
- package/package.json +15 -6
- package/src/AnalyticsEngine.ts +7 -53
- package/src/DurableObjectAlarm.ts +0 -2
- package/src/Email.ts +5 -34
- package/src/Environment.ts +1 -4
- package/src/Vitest.ts +500 -0
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { a as DurableObjectWebSocket_exports, c as causeMessage, d as WorkerConfig, f as WorkerEnvironment, i as fromExecutionContext, l as violationsMessage, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState, u as Environment_exports } from "./DurableObjectState-B5RCFnRy.mjs";
|
|
3
|
+
import { Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Function as Function$1, Layer, ManagedRuntime, Option, Predicate, Queue, Result, Schema } from "effect";
|
|
3
4
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
4
5
|
import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
5
6
|
import { D1Client } from "@effect/sql-d1";
|
|
@@ -8,29 +9,6 @@ import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
|
|
|
8
9
|
import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
|
|
9
10
|
import * as RpcServer from "effect/unstable/rpc/RpcServer";
|
|
10
11
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
11
|
-
//#region src/Environment.ts
|
|
12
|
-
var Environment_exports = /* @__PURE__ */ __exportAll({
|
|
13
|
-
WorkerConfig: () => WorkerConfig,
|
|
14
|
-
WorkerEnvironment: () => WorkerEnvironment
|
|
15
|
-
});
|
|
16
|
-
/**
|
|
17
|
-
* Context service for reading worker bindings from the current `env` object.
|
|
18
|
-
*/
|
|
19
|
-
var WorkerEnvironment = class extends Context.Service()("effect-cf/WorkerEnvironment") {};
|
|
20
|
-
let WorkerConfig;
|
|
21
|
-
(function(_WorkerConfig) {
|
|
22
|
-
_WorkerConfig.string = (name) => Config.string(name);
|
|
23
|
-
_WorkerConfig.redacted = (name) => Config.redacted(name);
|
|
24
|
-
_WorkerConfig.number = (name) => Config.number(name);
|
|
25
|
-
_WorkerConfig.integer = (name) => Config.int(name);
|
|
26
|
-
_WorkerConfig.boolean = (name) => Config.boolean(name);
|
|
27
|
-
const providerFromEnv = _WorkerConfig.providerFromEnv = (env, options) => ConfigProvider.fromUnknown(env, options);
|
|
28
|
-
const providerWith = _WorkerConfig.providerWith = (makeProvider) => Effect.map(WorkerEnvironment, makeProvider);
|
|
29
|
-
const provider = _WorkerConfig.provider = providerWith(providerFromEnv);
|
|
30
|
-
_WorkerConfig.layer = _WorkerConfig.providerLayer = ConfigProvider.layer(provider);
|
|
31
|
-
_WorkerConfig.layerWith = (makeProvider) => ConfigProvider.layer(providerWith(makeProvider));
|
|
32
|
-
})(WorkerConfig || (WorkerConfig = {}));
|
|
33
|
-
//#endregion
|
|
34
12
|
//#region src/Binding.ts
|
|
35
13
|
var Binding_exports = /* @__PURE__ */ __exportAll({
|
|
36
14
|
BindingNotFoundError: () => BindingNotFoundError,
|
|
@@ -149,25 +127,6 @@ const Service$2 = () => {
|
|
|
149
127
|
return makeService;
|
|
150
128
|
};
|
|
151
129
|
//#endregion
|
|
152
|
-
//#region src/internal/ErrorMessage.ts
|
|
153
|
-
/**
|
|
154
|
-
* Renders the most useful human-readable description of an unknown `cause`
|
|
155
|
-
* for use in tagged error `message` getters.
|
|
156
|
-
*/
|
|
157
|
-
const causeMessage = (cause) => {
|
|
158
|
-
if (typeof cause === "object" && cause !== null) {
|
|
159
|
-
const message = Reflect.get(cause, "message");
|
|
160
|
-
if (typeof message === "string" && message.length > 0) return message;
|
|
161
|
-
}
|
|
162
|
-
try {
|
|
163
|
-
return String(cause);
|
|
164
|
-
} catch {
|
|
165
|
-
return "unknown cause";
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
/** Renders a violation list as a single `path: message; ...` line. */
|
|
169
|
-
const violationsMessage = (violations) => violations.map((violation) => `${violation.path}: ${violation.message}`).join("; ");
|
|
170
|
-
//#endregion
|
|
171
130
|
//#region src/WorkersAi.ts
|
|
172
131
|
var WorkersAi_exports = /* @__PURE__ */ __exportAll({
|
|
173
132
|
Tag: () => Tag$16,
|
|
@@ -433,14 +392,7 @@ const tryAnalyticsEngineSync = (binding, operation, evaluate) => Effect.try({
|
|
|
433
392
|
try: evaluate,
|
|
434
393
|
catch: (cause) => analyticsEngineError(binding, operation, cause)
|
|
435
394
|
});
|
|
436
|
-
const
|
|
437
|
-
if (batchSize === void 0 || !Number.isFinite(batchSize) || batchSize <= 0) return writeLimits.maxDataPointsPerInvocation;
|
|
438
|
-
return Math.min(Math.floor(batchSize), writeLimits.maxDataPointsPerInvocation);
|
|
439
|
-
};
|
|
440
|
-
const resolveWritePolicy = (defaults, options) => ({
|
|
441
|
-
onInvalid: options?.onInvalid ?? defaults?.onInvalid ?? "error",
|
|
442
|
-
batchSize: normalizeBatchSize(options?.batchSize ?? defaults?.batchSize)
|
|
443
|
-
});
|
|
395
|
+
const resolveWritePolicy = (defaults, options) => ({ onInvalid: options?.onInvalid ?? defaults?.onInvalid ?? "error" });
|
|
444
396
|
const fieldPath = (prefix, field) => prefix === "" ? field : `${prefix}.${field}`;
|
|
445
397
|
const indexedPath = (prefix, field, index) => `${fieldPath(prefix, field)}[${index}]`;
|
|
446
398
|
const byteLength$1 = (value) => {
|
|
@@ -498,13 +450,8 @@ const validateDataPoints = (binding, operation, dataPoints, policy) => Effect.ge
|
|
|
498
450
|
if (violations.length > 0) return yield* Effect.fail(analyticsEngineWriteValidationError(binding, operation, violations));
|
|
499
451
|
return validPoints;
|
|
500
452
|
});
|
|
501
|
-
const writeChunks = (binding, operation, dataset, dataPoints
|
|
502
|
-
const
|
|
503
|
-
for (let index = 0; index < dataPoints.length; index += batchSize) {
|
|
504
|
-
const chunk = dataPoints.slice(index, index + batchSize);
|
|
505
|
-
if (typeof writeDataPoints === "function") yield* tryAnalyticsEngineSync(binding, operation, () => writeDataPoints.call(dataset, chunk));
|
|
506
|
-
else for (const point of chunk) yield* tryAnalyticsEngineSync(binding, operation, () => dataset.writeDataPoint(point));
|
|
507
|
-
}
|
|
453
|
+
const writeChunks = (binding, operation, dataset, dataPoints) => Effect.gen(function* () {
|
|
454
|
+
for (const point of dataPoints) yield* tryAnalyticsEngineSync(binding, operation, () => dataset.writeDataPoint(point));
|
|
508
455
|
});
|
|
509
456
|
const queryApiUrl = (definition) => {
|
|
510
457
|
const baseUrl = new URL(definition.apiBaseUrl ?? defaultQueryApiBaseUrl);
|
|
@@ -561,24 +508,20 @@ const isAnalyticsEngineDataset = (value) => {
|
|
|
561
508
|
return typeof Reflect.get(value, "writeDataPoint") === "function";
|
|
562
509
|
};
|
|
563
510
|
const makeClient$13 = (definition, defaults) => (dataset) => {
|
|
564
|
-
const writeDataPoint = Effect.fn("AnalyticsEngine.writeDataPoint")((dataPoint, options) => {
|
|
565
|
-
const policy = resolveWritePolicy(defaults, options);
|
|
566
|
-
return validateOptionalDataPoint(definition.binding, "writeDataPoint", dataPoint).pipe(Effect.matchEffect({
|
|
567
|
-
onFailure: (error) => policy.onInvalid === "drop" ? Effect.succeed(void 0) : Effect.fail(error),
|
|
568
|
-
onSuccess: (point) => tryAnalyticsEngineSync(definition.binding, "writeDataPoint", () => dataset.writeDataPoint(point))
|
|
569
|
-
}));
|
|
570
|
-
});
|
|
571
|
-
const writeDataPoints = Effect.fn("AnalyticsEngine.writeDataPoints")(function* (dataPoints, options) {
|
|
572
|
-
const policy = resolveWritePolicy(defaults, options);
|
|
573
|
-
const validPoints = yield* validateDataPoints(definition.binding, "writeDataPoints", dataPoints, policy);
|
|
574
|
-
yield* writeChunks(definition.binding, "writeDataPoints", dataset, validPoints, policy.batchSize);
|
|
575
|
-
});
|
|
576
511
|
return {
|
|
577
512
|
definition,
|
|
578
|
-
writeDataPoint,
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
513
|
+
writeDataPoint: Effect.fn("AnalyticsEngine.writeDataPoint")((dataPoint, options) => {
|
|
514
|
+
const policy = resolveWritePolicy(defaults, options);
|
|
515
|
+
return validateOptionalDataPoint(definition.binding, "writeDataPoint", dataPoint).pipe(Effect.matchEffect({
|
|
516
|
+
onFailure: (error) => policy.onInvalid === "drop" ? Effect.succeed(void 0) : Effect.fail(error),
|
|
517
|
+
onSuccess: (point) => tryAnalyticsEngineSync(definition.binding, "writeDataPoint", () => dataset.writeDataPoint(point))
|
|
518
|
+
}));
|
|
519
|
+
}),
|
|
520
|
+
writeDataPoints: Effect.fn("AnalyticsEngine.writeDataPoints")(function* (dataPoints, options) {
|
|
521
|
+
const policy = resolveWritePolicy(defaults, options);
|
|
522
|
+
const validPoints = yield* validateDataPoints(definition.binding, "writeDataPoints", dataPoints, policy);
|
|
523
|
+
yield* writeChunks(definition.binding, "writeDataPoints", dataset, validPoints);
|
|
524
|
+
}),
|
|
582
525
|
rawUnsafe: Effect.succeed(dataset)
|
|
583
526
|
};
|
|
584
527
|
};
|
|
@@ -734,345 +677,6 @@ const layerFrom = (storage) => Layer.succeed(CacheStorage, makeClient$11(storage
|
|
|
734
677
|
/** Provides Cache API services from Cloudflare's global `caches` object. */
|
|
735
678
|
const layer$14 = Layer.sync(CacheStorage, () => makeClient$11(caches));
|
|
736
679
|
//#endregion
|
|
737
|
-
//#region src/DurableObjectStorage.ts
|
|
738
|
-
var DurableObjectStorage_exports = /* @__PURE__ */ __exportAll({
|
|
739
|
-
StorageOperationError: () => StorageOperationError,
|
|
740
|
-
fromDurableObjectStorage: () => fromDurableObjectStorage
|
|
741
|
-
});
|
|
742
|
-
/** Error type used when a storage operation throws or rejects. */
|
|
743
|
-
var StorageOperationError = class extends Data.TaggedError("StorageOperationError") {
|
|
744
|
-
get message() {
|
|
745
|
-
return `Durable Object storage ${this.operation} failed: ${causeMessage(this.cause)}`;
|
|
746
|
-
}
|
|
747
|
-
};
|
|
748
|
-
const storageError = (operation, cause) => new StorageOperationError({
|
|
749
|
-
operation,
|
|
750
|
-
cause
|
|
751
|
-
});
|
|
752
|
-
const tryStorageSync = (operation, evaluate) => Effect.try({
|
|
753
|
-
try: evaluate,
|
|
754
|
-
catch: (cause) => storageError(operation, cause)
|
|
755
|
-
});
|
|
756
|
-
const tryStoragePromise = (operation, evaluate) => Effect.tryPromise({
|
|
757
|
-
try: evaluate,
|
|
758
|
-
catch: (cause) => storageError(operation, cause)
|
|
759
|
-
});
|
|
760
|
-
const fromSqlCursor = (cursor) => ({
|
|
761
|
-
next: () => tryStorageSync("sql.next", () => cursor.next()),
|
|
762
|
-
toArray: () => tryStorageSync("sql.toArray", () => cursor.toArray()),
|
|
763
|
-
one: () => tryStorageSync("sql.one", () => cursor.one()),
|
|
764
|
-
raw: () => tryStorageSync("sql.raw", () => cursor.raw()),
|
|
765
|
-
get columnNames() {
|
|
766
|
-
return cursor.columnNames;
|
|
767
|
-
},
|
|
768
|
-
rowsRead: tryStorageSync("sql.rowsRead", () => cursor.rowsRead),
|
|
769
|
-
rowsWritten: tryStorageSync("sql.rowsWritten", () => cursor.rowsWritten)
|
|
770
|
-
});
|
|
771
|
-
const fromSqlStorage = (sql) => ({
|
|
772
|
-
exec: (query, ...bindings) => tryStorageSync("sql.exec", () => fromSqlCursor(sql.exec(query, ...bindings))),
|
|
773
|
-
get databaseSize() {
|
|
774
|
-
return sql.databaseSize;
|
|
775
|
-
}
|
|
776
|
-
});
|
|
777
|
-
const schemaBackedSyncKvStorage = (kv, definition) => {
|
|
778
|
-
const encodeKey = Schema.encodeEffect(definition.key);
|
|
779
|
-
const decodeKey = Schema.decodeUnknownEffect(definition.key);
|
|
780
|
-
const encodeValue = Schema.encodeEffect(definition.value);
|
|
781
|
-
const decodeValue = Schema.decodeUnknownEffect(definition.value);
|
|
782
|
-
return {
|
|
783
|
-
get: (key) => Effect.gen(function* () {
|
|
784
|
-
const encodedKey = yield* encodeKey(key);
|
|
785
|
-
const encodedValue = yield* tryStorageSync("kv.get", () => kv.get(encodedKey));
|
|
786
|
-
if (encodedValue === void 0) return Option.none();
|
|
787
|
-
return yield* decodeValue(encodedValue).pipe(Effect.map(Option.some));
|
|
788
|
-
}),
|
|
789
|
-
put: (key, value) => Effect.gen(function* () {
|
|
790
|
-
const encodedKey = yield* encodeKey(key);
|
|
791
|
-
const encodedValue = yield* encodeValue(value);
|
|
792
|
-
yield* tryStorageSync("kv.put", () => kv.put(encodedKey, encodedValue));
|
|
793
|
-
}),
|
|
794
|
-
delete: (key) => Effect.gen(function* () {
|
|
795
|
-
const encodedKey = yield* encodeKey(key);
|
|
796
|
-
return yield* tryStorageSync("kv.delete", () => kv.delete(encodedKey));
|
|
797
|
-
}),
|
|
798
|
-
list: (options) => Effect.gen(function* () {
|
|
799
|
-
const entries = Array.from(yield* tryStorageSync("kv.list", () => kv.list(options)));
|
|
800
|
-
const decoded = [];
|
|
801
|
-
for (const [key, value] of entries) decoded.push([yield* decodeKey(key), yield* decodeValue(value)]);
|
|
802
|
-
return decoded;
|
|
803
|
-
})
|
|
804
|
-
};
|
|
805
|
-
};
|
|
806
|
-
const fromSyncKvStorage = (kv) => ({
|
|
807
|
-
get: (key) => tryStorageSync("kv.get", () => kv.get(key)),
|
|
808
|
-
put: (key, value) => tryStorageSync("kv.put", () => kv.put(key, value)),
|
|
809
|
-
delete: (key) => tryStorageSync("kv.delete", () => kv.delete(key)),
|
|
810
|
-
list: (options) => tryStorageSync("kv.list", () => Array.from(kv.list(options))),
|
|
811
|
-
schema: (definition) => schemaBackedSyncKvStorage(kv, definition)
|
|
812
|
-
});
|
|
813
|
-
const fromDurableObjectTransaction = (txn) => ({
|
|
814
|
-
get: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)) : tryStoragePromise("transaction.get", () => txn.get(keyOrKeys, options)),
|
|
815
|
-
list: (options) => tryStoragePromise("transaction.list", () => txn.list(options)),
|
|
816
|
-
put: (keyOrEntries, valueOrOptions, maybeOptions) => tryStoragePromise("transaction.put", () => typeof keyOrEntries === "string" ? txn.put(keyOrEntries, valueOrOptions, maybeOptions) : txn.put(keyOrEntries, valueOrOptions)),
|
|
817
|
-
delete: (keyOrKeys, options) => Array.isArray(keyOrKeys) ? tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)) : tryStoragePromise("transaction.delete", () => txn.delete(keyOrKeys, options)),
|
|
818
|
-
rollback: () => tryStorageSync("transaction.rollback", () => txn.rollback()),
|
|
819
|
-
getAlarm: (options) => tryStoragePromise("transaction.getAlarm", () => txn.getAlarm(options)),
|
|
820
|
-
setAlarm: (scheduledTime, options) => tryStoragePromise("transaction.setAlarm", () => txn.setAlarm(scheduledTime, options)),
|
|
821
|
-
deleteAlarm: (options) => tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options))
|
|
822
|
-
});
|
|
823
|
-
/**
|
|
824
|
-
* Wraps native Cloudflare storage APIs as Effect-returning helpers.
|
|
825
|
-
*/
|
|
826
|
-
const fromDurableObjectStorage = (storage) => ({
|
|
827
|
-
get: (key, options) => tryStoragePromise("get", () => storage.get(key, options)),
|
|
828
|
-
put: (key, value, options) => tryStoragePromise("put", () => storage.put(key, value, options)),
|
|
829
|
-
delete: (key, options) => tryStoragePromise("delete", () => storage.delete(key, options)),
|
|
830
|
-
deleteAll: (options) => tryStoragePromise("deleteAll", () => storage.deleteAll(options)),
|
|
831
|
-
getAlarm: (options) => tryStoragePromise("getAlarm", () => storage.getAlarm(options)),
|
|
832
|
-
setAlarm: (scheduledTime, options) => tryStoragePromise("setAlarm", () => storage.setAlarm(scheduledTime, options)),
|
|
833
|
-
deleteAlarm: (options) => tryStoragePromise("deleteAlarm", () => storage.deleteAlarm(options)),
|
|
834
|
-
transactionSync: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.suspend(() => {
|
|
835
|
-
try {
|
|
836
|
-
return Effect.succeed(storage.transactionSync(() => {
|
|
837
|
-
const exit = Effect.runSyncExitWith(context)(closure());
|
|
838
|
-
if (Exit.isSuccess(exit)) return exit.value;
|
|
839
|
-
throw exit;
|
|
840
|
-
}));
|
|
841
|
-
} catch (cause) {
|
|
842
|
-
if (Exit.isExit(cause) && Exit.isFailure(cause)) return Effect.failCause(cause.cause);
|
|
843
|
-
return Effect.fail(storageError("transactionSync", cause));
|
|
844
|
-
}
|
|
845
|
-
}))),
|
|
846
|
-
transaction: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.callback((resume) => {
|
|
847
|
-
storage.transaction(async (txn) => {
|
|
848
|
-
const exit = await Effect.runPromiseExitWith(context)(closure(fromDurableObjectTransaction(txn)));
|
|
849
|
-
if (Exit.isSuccess(exit)) return exit.value;
|
|
850
|
-
throw exit;
|
|
851
|
-
}).then((value) => resume(Effect.succeed(value)), (cause) => {
|
|
852
|
-
if (Exit.isExit(cause) && Exit.isFailure(cause)) resume(Effect.failCause(cause.cause));
|
|
853
|
-
else resume(Effect.fail(storageError("transaction", cause)));
|
|
854
|
-
});
|
|
855
|
-
}))),
|
|
856
|
-
sync: () => tryStoragePromise("sync", () => storage.sync()),
|
|
857
|
-
getCurrentBookmark: () => tryStoragePromise("getCurrentBookmark", () => storage.getCurrentBookmark()),
|
|
858
|
-
onNextSessionRestoreBookmark: (bookmark) => tryStoragePromise("onNextSessionRestoreBookmark", () => storage.onNextSessionRestoreBookmark(bookmark)),
|
|
859
|
-
sql: fromSqlStorage(storage.sql),
|
|
860
|
-
kv: fromSyncKvStorage(storage.kv)
|
|
861
|
-
});
|
|
862
|
-
//#endregion
|
|
863
|
-
//#region src/DurableObjectWebSocket.ts
|
|
864
|
-
var DurableObjectWebSocket_exports = /* @__PURE__ */ __exportAll({
|
|
865
|
-
DurableWebSocketAttachmentError: () => DurableWebSocketAttachmentError,
|
|
866
|
-
DurableWebSocketCloseError: () => DurableWebSocketCloseError,
|
|
867
|
-
DurableWebSocketSendError: () => DurableWebSocketSendError,
|
|
868
|
-
acceptUpgrade: () => acceptUpgrade,
|
|
869
|
-
attachment: () => attachment,
|
|
870
|
-
fromWebSocket: () => fromWebSocket,
|
|
871
|
-
handlers: () => handlers
|
|
872
|
-
});
|
|
873
|
-
/** Error raised when sending on a Durable Object websocket fails. */
|
|
874
|
-
var DurableWebSocketSendError = class extends Data.TaggedError("DurableWebSocketSendError") {
|
|
875
|
-
get message() {
|
|
876
|
-
return `Durable Object websocket send failed: ${causeMessage(this.cause)}`;
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
/** Error raised when closing a Durable Object websocket fails. */
|
|
880
|
-
var DurableWebSocketCloseError = class extends Data.TaggedError("DurableWebSocketCloseError") {
|
|
881
|
-
get message() {
|
|
882
|
-
return `Durable Object websocket close failed: ${causeMessage(this.cause)}`;
|
|
883
|
-
}
|
|
884
|
-
};
|
|
885
|
-
/** Error raised when serializing or deserializing a websocket attachment fails. */
|
|
886
|
-
var DurableWebSocketAttachmentError = class extends Data.TaggedError("DurableWebSocketAttachmentError") {
|
|
887
|
-
get message() {
|
|
888
|
-
return `Durable Object websocket attachment ${this.operation} failed: ${causeMessage(this.cause)}`;
|
|
889
|
-
}
|
|
890
|
-
};
|
|
891
|
-
const wrappers = /* @__PURE__ */ new WeakMap();
|
|
892
|
-
/** Wraps a native Cloudflare websocket in the Effect-native Durable Object API. */
|
|
893
|
-
const fromWebSocket = (raw) => {
|
|
894
|
-
const existing = wrappers.get(raw);
|
|
895
|
-
if (existing !== void 0) return existing;
|
|
896
|
-
const socket = {
|
|
897
|
-
raw,
|
|
898
|
-
send: (data) => Effect.try({
|
|
899
|
-
try: () => raw.send(data),
|
|
900
|
-
catch: (cause) => new DurableWebSocketSendError({ cause })
|
|
901
|
-
}),
|
|
902
|
-
close: (code, reason) => Effect.try({
|
|
903
|
-
try: () => raw.close(code, reason),
|
|
904
|
-
catch: (cause) => new DurableWebSocketCloseError({ cause })
|
|
905
|
-
}),
|
|
906
|
-
serializeAttachment: (value) => Effect.try({
|
|
907
|
-
try: () => raw.serializeAttachment(value),
|
|
908
|
-
catch: (cause) => new DurableWebSocketAttachmentError({
|
|
909
|
-
operation: "serialize",
|
|
910
|
-
cause
|
|
911
|
-
})
|
|
912
|
-
}),
|
|
913
|
-
deserializeAttachment: Effect.try({
|
|
914
|
-
try: () => raw.deserializeAttachment(),
|
|
915
|
-
catch: (cause) => new DurableWebSocketAttachmentError({
|
|
916
|
-
operation: "deserialize",
|
|
917
|
-
cause
|
|
918
|
-
})
|
|
919
|
-
})
|
|
920
|
-
};
|
|
921
|
-
wrappers.set(raw, socket);
|
|
922
|
-
return socket;
|
|
923
|
-
};
|
|
924
|
-
/**
|
|
925
|
-
* Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
|
|
926
|
-
*
|
|
927
|
-
* @example
|
|
928
|
-
* ```ts
|
|
929
|
-
* const response = yield* DurableObjectWebSocket.acceptUpgrade({
|
|
930
|
-
* tags: ["room:general"],
|
|
931
|
-
* });
|
|
932
|
-
*
|
|
933
|
-
* return response.response;
|
|
934
|
-
* ```
|
|
935
|
-
*/
|
|
936
|
-
const acceptUpgrade = Effect.fn("DurableObjectWebSocket.acceptUpgrade")(function* (options = {}) {
|
|
937
|
-
const state = yield* DurableObjectState;
|
|
938
|
-
const pair = new WebSocketPair();
|
|
939
|
-
const client = pair[0];
|
|
940
|
-
const server = fromWebSocket(pair[1]);
|
|
941
|
-
if (options.attachment !== void 0) yield* server.serializeAttachment(options.attachment);
|
|
942
|
-
yield* state.acceptWebSocket(server, options.tags === void 0 ? void 0 : [...options.tags]);
|
|
943
|
-
return {
|
|
944
|
-
client,
|
|
945
|
-
server,
|
|
946
|
-
response: new Response(null, {
|
|
947
|
-
status: 101,
|
|
948
|
-
webSocket: client
|
|
949
|
-
})
|
|
950
|
-
};
|
|
951
|
-
});
|
|
952
|
-
/** Creates typed attachment helpers for accepted and rehydrated sockets. */
|
|
953
|
-
const attachment = (schema) => {
|
|
954
|
-
const serialize = (socket, value) => Schema.encodeEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
|
|
955
|
-
operation: "serialize",
|
|
956
|
-
cause
|
|
957
|
-
})), Effect.flatMap((encoded) => socket.serializeAttachment(encoded)));
|
|
958
|
-
const deserialize = (socket) => Effect.gen(function* () {
|
|
959
|
-
const value = yield* socket.deserializeAttachment;
|
|
960
|
-
if (value === null || value === void 0) return Option.none();
|
|
961
|
-
return Option.some(yield* Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
|
|
962
|
-
operation: "deserialize",
|
|
963
|
-
cause
|
|
964
|
-
}))));
|
|
965
|
-
});
|
|
966
|
-
const rehydrate = (options = {}) => Effect.gen(function* () {
|
|
967
|
-
const sockets = yield* (yield* DurableObjectState).getWebSockets(options.tag);
|
|
968
|
-
const restored = [];
|
|
969
|
-
const onInvalid = options.onInvalid ?? "ignore";
|
|
970
|
-
for (const socket of sockets) {
|
|
971
|
-
const decoded = yield* Effect.result(deserialize(socket));
|
|
972
|
-
if (Result.isSuccess(decoded) && Option.isSome(decoded.success)) {
|
|
973
|
-
restored.push({
|
|
974
|
-
socket,
|
|
975
|
-
attachment: decoded.success.value
|
|
976
|
-
});
|
|
977
|
-
continue;
|
|
978
|
-
}
|
|
979
|
-
if (Result.isFailure(decoded) && onInvalid === "fail") return yield* Effect.fail(decoded.failure);
|
|
980
|
-
if (Result.isFailure(decoded) && onInvalid === "ignore-and-close") yield* socket.close(1008, "invalid websocket attachment").pipe(Effect.ignore);
|
|
981
|
-
}
|
|
982
|
-
return restored;
|
|
983
|
-
});
|
|
984
|
-
return {
|
|
985
|
-
serialize,
|
|
986
|
-
deserialize,
|
|
987
|
-
rehydrate,
|
|
988
|
-
schema
|
|
989
|
-
};
|
|
990
|
-
};
|
|
991
|
-
/** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
|
|
992
|
-
const handlers = (options) => ({
|
|
993
|
-
webSocketMessage: options.message,
|
|
994
|
-
webSocketClose: options.close,
|
|
995
|
-
webSocketError: options.error
|
|
996
|
-
});
|
|
997
|
-
//#endregion
|
|
998
|
-
//#region src/internal/WorkerContext.ts
|
|
999
|
-
const causeError = (cause) => {
|
|
1000
|
-
const squashed = Cause.squash(cause);
|
|
1001
|
-
return squashed instanceof Error ? squashed : new Error(Cause.pretty(cause), { cause: squashed });
|
|
1002
|
-
};
|
|
1003
|
-
const failureHandler = (label, cause, options) => (options?.onFailure?.(cause) ?? Effect.logError(`${label} failed`, Cause.pretty(cause))).pipe(Effect.catchCause((handlerCause) => Effect.logError(`${label} failure handler failed`, Cause.pretty(cause), Cause.pretty(handlerCause))));
|
|
1004
|
-
/**
|
|
1005
|
-
* Builds a `waitUntil` scheduler for any Cloudflare lifecycle that accepts
|
|
1006
|
-
* background promises (`ExecutionContext`, `DurableObjectState`).
|
|
1007
|
-
*
|
|
1008
|
-
* Background effects capture the calling fiber's context via `Effect.context`
|
|
1009
|
-
* before being registered, so the default module-level `Effect.runPromiseExit`
|
|
1010
|
-
* runner is sufficient; entrypoints may still pass a runtime-bound runner.
|
|
1011
|
-
*/
|
|
1012
|
-
const makeWaitUntilScheduler = (label, register, runPromiseExit = (effect) => Effect.runPromiseExit(effect)) => {
|
|
1013
|
-
return (effect, options, mode) => Effect.context().pipe(Effect.flatMap((context) => Effect.sync(() => {
|
|
1014
|
-
const runHandler = (cause) => runPromiseExit(Effect.scoped(Effect.provideContext(failureHandler(label, cause, options), context))).then((exit) => {
|
|
1015
|
-
if (Exit.isFailure(exit)) console.error(`${label} failure handler failed`, Cause.pretty(exit.cause));
|
|
1016
|
-
});
|
|
1017
|
-
register(runPromiseExit(Effect.scoped(Effect.provideContext(effect, context))).then(async (exit) => {
|
|
1018
|
-
if (Exit.isSuccess(exit)) return;
|
|
1019
|
-
await runHandler(exit.cause);
|
|
1020
|
-
if (mode === "propagate") throw causeError(exit.cause);
|
|
1021
|
-
}));
|
|
1022
|
-
})));
|
|
1023
|
-
};
|
|
1024
|
-
/**
|
|
1025
|
-
* Builds the `WorkerContext` service from a native `ExecutionContext`.
|
|
1026
|
-
*/
|
|
1027
|
-
const fromExecutionContext = (ctx, runPromiseExit = (effect) => Effect.runPromiseExit(effect)) => {
|
|
1028
|
-
const schedule = makeWaitUntilScheduler("WorkerContext.waitUntil", (promise) => ctx.waitUntil(promise), runPromiseExit);
|
|
1029
|
-
return {
|
|
1030
|
-
raw: ctx,
|
|
1031
|
-
waitUntil: (effect, options) => schedule(effect, options, options?.mode ?? "observe"),
|
|
1032
|
-
waitUntilPropagating: (effect, options) => schedule(effect, options, "propagate"),
|
|
1033
|
-
passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
|
|
1034
|
-
};
|
|
1035
|
-
};
|
|
1036
|
-
//#endregion
|
|
1037
|
-
//#region src/DurableObjectState.ts
|
|
1038
|
-
var DurableObjectState_exports = /* @__PURE__ */ __exportAll({
|
|
1039
|
-
DurableObjectState: () => DurableObjectState,
|
|
1040
|
-
fromDurableObjectState: () => fromDurableObjectState
|
|
1041
|
-
});
|
|
1042
|
-
/**
|
|
1043
|
-
* Context tag for accessing the current Durable Object state service.
|
|
1044
|
-
*/
|
|
1045
|
-
var DurableObjectState = class extends Context.Service()("effect-cf/DurableObjectState") {};
|
|
1046
|
-
/**
|
|
1047
|
-
* Wraps a native Cloudflare `DurableObjectState` as a {@link DurableObjectStateService}.
|
|
1048
|
-
*/
|
|
1049
|
-
const fromDurableObjectState = (state) => {
|
|
1050
|
-
const scheduleWaitUntil = makeWaitUntilScheduler("DurableObjectState.waitUntil", (promise) => state.waitUntil(promise));
|
|
1051
|
-
const waitUntil = ((input, options) => Effect.isEffect(input) ? scheduleWaitUntil(input, options, options?.mode ?? "observe") : Effect.sync(() => state.waitUntil(input)));
|
|
1052
|
-
return {
|
|
1053
|
-
raw: state,
|
|
1054
|
-
id: state.id,
|
|
1055
|
-
storage: fromDurableObjectStorage(state.storage),
|
|
1056
|
-
waitUntil,
|
|
1057
|
-
blockConcurrencyWhile: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => runPromiseExitPreservingTypedFailures(context, effect)))), Effect.flatten),
|
|
1058
|
-
blockConcurrencyWhileOrReset: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => Effect.runPromiseWith(context)(effect))))),
|
|
1059
|
-
acceptWebSocket: (ws, tags) => Effect.sync(() => state.acceptWebSocket(ws.raw, tags)),
|
|
1060
|
-
getWebSockets: (tag) => Effect.sync(() => state.getWebSockets(tag).map((socket) => fromWebSocket(socket))),
|
|
1061
|
-
setWebSocketAutoResponse: (pair) => Effect.sync(() => state.setWebSocketAutoResponse(pair)),
|
|
1062
|
-
getWebSocketAutoResponse: Effect.sync(() => state.getWebSocketAutoResponse()),
|
|
1063
|
-
getWebSocketAutoResponseTimestamp: (ws) => Effect.sync(() => state.getWebSocketAutoResponseTimestamp(ws.raw)),
|
|
1064
|
-
setHibernatableWebSocketEventTimeout: (timeoutMs) => Effect.sync(() => state.setHibernatableWebSocketEventTimeout(timeoutMs)),
|
|
1065
|
-
getHibernatableWebSocketEventTimeout: Effect.sync(() => state.getHibernatableWebSocketEventTimeout()),
|
|
1066
|
-
getTags: (ws) => Effect.sync(() => state.getTags(ws.raw)),
|
|
1067
|
-
abort: (reason) => Effect.sync(() => state.abort(reason))
|
|
1068
|
-
};
|
|
1069
|
-
};
|
|
1070
|
-
const runPromiseExitPreservingTypedFailures = async (context, effect) => {
|
|
1071
|
-
const exit = await Effect.runPromiseExitWith(context)(effect);
|
|
1072
|
-
if (Exit.isFailure(exit) && (Cause.hasDies(exit.cause) || Cause.hasInterrupts(exit.cause))) throw Cause.squash(exit.cause);
|
|
1073
|
-
return exit;
|
|
1074
|
-
};
|
|
1075
|
-
//#endregion
|
|
1076
680
|
//#region src/CloudflareOtlp.ts
|
|
1077
681
|
/**
|
|
1078
682
|
* OTLP telemetry layers for Cloudflare Workers and Durable Objects.
|
|
@@ -2530,7 +2134,6 @@ var DurableObjectAlarm_exports = /* @__PURE__ */ __exportAll({
|
|
|
2530
2134
|
InvalidRepeatEveryError: () => InvalidRepeatEveryError,
|
|
2531
2135
|
StoredAlarmDecodeError: () => StoredAlarmDecodeError,
|
|
2532
2136
|
define: () => define,
|
|
2533
|
-
process: () => process,
|
|
2534
2137
|
processDue: () => processDue
|
|
2535
2138
|
});
|
|
2536
2139
|
const INIT_TABLE_SQL = `
|
|
@@ -2655,7 +2258,6 @@ const getFailureActionRetryDelay = (action) => typeof action === "string" || act
|
|
|
2655
2258
|
const processDue = (handle, options = {}) => Effect.gen(function* () {
|
|
2656
2259
|
return yield* (yield* DurableObjectAlarm).processDueAlarms(handle, options);
|
|
2657
2260
|
});
|
|
2658
|
-
const process = processDue;
|
|
2659
2261
|
const isAlarmDefinitionConfig = (definition) => typeof definition === "object" && definition !== null && "payload" in definition;
|
|
2660
2262
|
const getAlarmDefinitionSchema = (definition) => isAlarmDefinitionConfig(definition) ? definition.payload : definition;
|
|
2661
2263
|
const getAlarmDefinitionFailureAction = (definition) => {
|
|
@@ -3018,7 +2620,6 @@ var Email_exports = /* @__PURE__ */ __exportAll({
|
|
|
3018
2620
|
Tag: () => Tag$7,
|
|
3019
2621
|
emailErrorCodes: () => emailErrorCodes,
|
|
3020
2622
|
isEmailBinding: () => isEmailBinding,
|
|
3021
|
-
isEmailMessageBuilder: () => isEmailMessageBuilder,
|
|
3022
2623
|
layer: () => layer$6,
|
|
3023
2624
|
make: () => make$6,
|
|
3024
2625
|
makeClient: () => makeClient$6,
|
|
@@ -3109,24 +2710,6 @@ const tryEmailPromise = (binding, operation, evaluate) => Effect.tryPromise({
|
|
|
3109
2710
|
try: evaluate,
|
|
3110
2711
|
catch: (cause) => emailError(binding, operation, cause)
|
|
3111
2712
|
});
|
|
3112
|
-
const builderFields = [
|
|
3113
|
-
"subject",
|
|
3114
|
-
"html",
|
|
3115
|
-
"text",
|
|
3116
|
-
"cc",
|
|
3117
|
-
"bcc",
|
|
3118
|
-
"replyTo",
|
|
3119
|
-
"attachments",
|
|
3120
|
-
"headers"
|
|
3121
|
-
];
|
|
3122
|
-
/**
|
|
3123
|
-
* Distinguishes structured Email Sending messages from raw MIME `EmailMessage`
|
|
3124
|
-
* values, which only carry envelope `from` and `to` addresses.
|
|
3125
|
-
*/
|
|
3126
|
-
const isEmailMessageBuilder = (message) => {
|
|
3127
|
-
if (typeof message !== "object" || message === null) return false;
|
|
3128
|
-
return builderFields.some((field) => Reflect.get(message, field) !== void 0);
|
|
3129
|
-
};
|
|
3130
2713
|
const byteLength = (value) => textEncoder.encode(value).byteLength;
|
|
3131
2714
|
const limitViolation = (path, label, actual, limit) => ({
|
|
3132
2715
|
path,
|
|
@@ -3261,7 +2844,7 @@ const makeClient$6 = (definition, options) => (email) => {
|
|
|
3261
2844
|
return {
|
|
3262
2845
|
definition,
|
|
3263
2846
|
send: Effect.fn("Email.send")(function* (message) {
|
|
3264
|
-
if (validate
|
|
2847
|
+
if (validate) yield* validateSendInput(definition.binding, "send", message);
|
|
3265
2848
|
return yield* tryEmailPromise(definition.binding, "send", () => runtime.send(message));
|
|
3266
2849
|
}),
|
|
3267
2850
|
rawUnsafe: Effect.succeed(email)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-cf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Effect-native primitives for Cloudflare Workers and bindings.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"import": "./dist/HyperdrivePg.mjs",
|
|
28
28
|
"default": "./dist/HyperdrivePg.mjs"
|
|
29
29
|
},
|
|
30
|
+
"./vitest": {
|
|
31
|
+
"types": "./dist/Vitest.d.mts",
|
|
32
|
+
"import": "./dist/Vitest.mjs",
|
|
33
|
+
"default": "./dist/Vitest.mjs"
|
|
34
|
+
},
|
|
30
35
|
"./package.json": "./package.json"
|
|
31
36
|
},
|
|
32
37
|
"publishConfig": {
|
|
@@ -43,7 +48,7 @@
|
|
|
43
48
|
"@cloudflare/containers": "catalog:",
|
|
44
49
|
"@cloudflare/vitest-pool-workers": "catalog:",
|
|
45
50
|
"@cloudflare/workers-types": "catalog:",
|
|
46
|
-
"@effect/platform-node": "4.0.0-beta.105",
|
|
51
|
+
"@effect/platform-node": "^4.0.0-beta.105",
|
|
47
52
|
"@effect/sql-d1": "catalog:",
|
|
48
53
|
"@effect/sql-pg": "catalog:",
|
|
49
54
|
"@effect/sql-sqlite-do": "catalog:",
|
|
@@ -53,13 +58,17 @@
|
|
|
53
58
|
"vitest": "catalog:"
|
|
54
59
|
},
|
|
55
60
|
"peerDependencies": {
|
|
61
|
+
"@cloudflare/vitest-pool-workers": "^0.21.3",
|
|
56
62
|
"@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"
|
|
63
|
+
"@effect/sql-d1": "^4.0.0-beta.105",
|
|
64
|
+
"@effect/sql-pg": "^4.0.0-beta.105",
|
|
65
|
+
"@effect/sql-sqlite-do": "^4.0.0-beta.105",
|
|
66
|
+
"effect": "^4.0.0-beta.105"
|
|
61
67
|
},
|
|
62
68
|
"peerDependenciesMeta": {
|
|
69
|
+
"@cloudflare/vitest-pool-workers": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
63
72
|
"@cloudflare/workers-types": {
|
|
64
73
|
"optional": true
|
|
65
74
|
},
|