@mcp-b/do-runtime 0.3.4 → 0.3.6
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 +14 -0
- package/README.md +13 -7
- package/dist/chunks/{io-context-BV4kxxAv.js → io-context-RmmjNtwm.js} +76 -38
- package/dist/chunks/io-context-RmmjNtwm.js.map +1 -0
- package/dist/cloudflare-workers.d.ts +1 -0
- package/dist/gate.js +42 -22
- package/dist/gate.js.map +1 -1
- package/dist/index.js +98 -150
- package/dist/index.js.map +1 -1
- package/dist/server/alarm-scheduler.js +0 -1
- package/dist/server/alarm-scheduler.js.map +1 -1
- package/dist/src/api/actor-state.d.ts +11 -67
- package/dist/src/api/export-loopback.d.ts +0 -16
- package/dist/src/api/global-scope.d.ts +1 -1
- package/dist/src/api/worker-loader.d.ts +0 -18
- package/dist/src/gate.d.ts +5 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/io/io-context.d.ts +26 -11
- package/dist/src/io/io-gate.d.ts +1 -1
- package/dist/src/server/actor-container.d.ts +24 -14
- package/dist/vite.js +59 -1
- package/dist/vite.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/io-context-BV4kxxAv.js.map +0 -1
- package/dist/src/api/sync-kv.d.ts +0 -51
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/api/cloudflare-workers.js";
|
package/dist/gate.js
CHANGED
|
@@ -1,54 +1,72 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as tryCurrentContinuation, r as atCheckpointEnd, u as tryCurrentIoContext } from "./chunks/io-context-RmmjNtwm.js";
|
|
2
2
|
//#region src/gate.ts
|
|
3
|
-
var continuationContext;
|
|
4
3
|
var TRANSFORMED_AWAIT = Symbol("@mcp-b/do-runtime/transformed-await");
|
|
4
|
+
/**
|
|
5
|
+
* Own the gap between publishing an await result and its `__resumeAwait` call.
|
|
6
|
+
* This is deliberately separate from the current-continuation ambient: a
|
|
7
|
+
* reservation serializes publishers but must never make its actor look current.
|
|
8
|
+
* See §2.3 and decision 8.
|
|
9
|
+
*/
|
|
10
|
+
var CURRENT_PUBLICATION = Symbol.for("@mcp-b/do-runtime/current-await-publication");
|
|
11
|
+
var warnedUngatedAwaits = /* @__PURE__ */ new Set();
|
|
5
12
|
function isThenable(value) {
|
|
6
13
|
return (typeof value === "object" && value !== null || typeof value === "function") && typeof Reflect.get(value, "then") === "function";
|
|
7
14
|
}
|
|
8
15
|
/** Re-enter the actor that owns this transformed await; fail open outside actors. */
|
|
9
16
|
function __gate(value) {
|
|
10
|
-
const context =
|
|
17
|
+
const context = tryCurrentIoContext();
|
|
11
18
|
if (!isThenable(value) && context === void 0) return value;
|
|
12
19
|
if (context === void 0) return value;
|
|
13
20
|
return resumeWithContext(context, Promise.resolve(value));
|
|
14
21
|
}
|
|
15
22
|
/** Capture an actor await without publishing its context before the continuation runs. */
|
|
16
|
-
function __gateAwait(value) {
|
|
17
|
-
const context =
|
|
18
|
-
if (context === void 0)
|
|
23
|
+
function __gateAwait(value, developmentSource) {
|
|
24
|
+
const context = tryCurrentIoContext();
|
|
25
|
+
if (context === void 0) {
|
|
26
|
+
if (developmentSource !== void 0 && !warnedUngatedAwaits.has(developmentSource)) {
|
|
27
|
+
warnedUngatedAwaits.add(developmentSource);
|
|
28
|
+
console.warn(`do-runtime: transformed await in ${developmentSource} ran without an actor input lock; an earlier await or entry path is not gated`);
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
19
32
|
return resumeAwaitWithContext(context, Promise.resolve(value));
|
|
20
33
|
}
|
|
21
34
|
/** Restore the captured actor at the first instruction after a transformed await. */
|
|
22
35
|
function __resumeAwait(value) {
|
|
23
36
|
if (!isTransformedAwait(value)) return value;
|
|
24
|
-
|
|
37
|
+
clearPublication(value.reservation);
|
|
38
|
+
value.context.restoreContinuation();
|
|
25
39
|
if (value.outcome.ok) return value.outcome.value;
|
|
26
40
|
throw value.outcome.exception;
|
|
27
41
|
}
|
|
28
42
|
function isTransformedAwait(value) {
|
|
29
43
|
return Reflect.get(Object(value), TRANSFORMED_AWAIT) === true;
|
|
30
44
|
}
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
function currentPublication() {
|
|
46
|
+
return Reflect.get(globalThis, CURRENT_PUBLICATION);
|
|
47
|
+
}
|
|
48
|
+
function reservePublication(context) {
|
|
49
|
+
if (tryCurrentContinuation() !== void 0 || currentPublication() !== void 0) return void 0;
|
|
50
|
+
const reservation = { context };
|
|
51
|
+
Reflect.set(globalThis, CURRENT_PUBLICATION, reservation);
|
|
52
|
+
atCheckpointEnd(() => clearPublication(reservation));
|
|
53
|
+
return reservation;
|
|
54
|
+
}
|
|
55
|
+
function clearPublication(reservation) {
|
|
56
|
+
if (currentPublication() === reservation) Reflect.deleteProperty(globalThis, CURRENT_PUBLICATION);
|
|
40
57
|
}
|
|
41
58
|
function publishOutcome(context, promise, finish) {
|
|
42
59
|
return new Promise((resolve, reject) => {
|
|
43
60
|
const publish = context.makeTransformReentryCallback((outcome) => {
|
|
44
|
-
|
|
61
|
+
const reservation = reservePublication(context);
|
|
62
|
+
if (reservation === void 0) {
|
|
45
63
|
schedulePublication({
|
|
46
64
|
publish: () => publish(outcome),
|
|
47
65
|
reject
|
|
48
66
|
});
|
|
49
67
|
return;
|
|
50
68
|
}
|
|
51
|
-
resolve(finish(outcome));
|
|
69
|
+
resolve(finish(outcome, reservation));
|
|
52
70
|
});
|
|
53
71
|
promise.then((value) => {
|
|
54
72
|
schedulePublication({
|
|
@@ -70,15 +88,17 @@ function publishOutcome(context, promise, finish) {
|
|
|
70
88
|
});
|
|
71
89
|
}
|
|
72
90
|
function resumeAwaitWithContext(context, promise) {
|
|
73
|
-
return publishOutcome(context, promise, (outcome) => ({
|
|
91
|
+
return publishOutcome(context, promise, (outcome, reservation) => ({
|
|
74
92
|
[TRANSFORMED_AWAIT]: true,
|
|
75
93
|
context,
|
|
76
|
-
outcome
|
|
94
|
+
outcome,
|
|
95
|
+
reservation
|
|
77
96
|
}));
|
|
78
97
|
}
|
|
79
98
|
function resumeWithContext(context, promise) {
|
|
80
|
-
return publishOutcome(context, promise, (outcome) => {
|
|
81
|
-
|
|
99
|
+
return publishOutcome(context, promise, (outcome, reservation) => {
|
|
100
|
+
clearPublication(reservation);
|
|
101
|
+
context.restoreContinuation();
|
|
82
102
|
if (outcome.ok) return outcome.value;
|
|
83
103
|
throw outcome.exception;
|
|
84
104
|
});
|
package/dist/gate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.js","names":[],"sources":["../src/gate.ts"],"sourcesContent":["/* @do-runtime-gated */\n\nimport { atCheckpointEnd, tryCurrentSlice, type IoContext } from \"./io/io-context\";\n\ntype ContinuationContext = {\n readonly context: IoContext;\n readonly token: object;\n};\n\nlet continuationContext: ContinuationContext | undefined;\n\ntype Publication = {\n readonly publish: () => Promise<void>;\n readonly reject: (exception: unknown) => void;\n};\n\ntype Outcome<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly exception: unknown };\n\nconst TRANSFORMED_AWAIT = Symbol(\"@mcp-b/do-runtime/transformed-await\");\n\ntype TransformedAwait<T> = {\n readonly [TRANSFORMED_AWAIT]: true;\n readonly context: IoContext;\n readonly outcome: Outcome<T>;\n};\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n (typeof value === \"object\" && value !== null) ||\n typeof value === \"function\"\n ) && typeof Reflect.get(value, \"then\") === \"function\";\n}\n\n/** Re-enter the actor that owns this transformed await; fail open outside actors. */\nexport function __gate<T>(value: T): T | Promise<Awaited<T>> {\n const context = tryCurrentSlice() ?? continuationContext?.context;\n if (!isThenable(value) && context === undefined) return value;\n if (context === undefined) return value;\n return resumeWithContext(context, Promise.resolve(value));\n}\n\n/** Capture an actor await without publishing its context before the continuation runs. */\nexport function __gateAwait<T>(value: T): T | Promise<TransformedAwait<Awaited<T>>> {\n const context = tryCurrentSlice() ?? continuationContext?.context;\n if (context === undefined) return value;\n return resumeAwaitWithContext(context, Promise.resolve(value));\n}\n\n/** Restore the captured actor at the first instruction after a transformed await. */\nexport function __resumeAwait<T>(value: T | TransformedAwait<T>): T {\n if (!isTransformedAwait(value)) return value as T;\n\n restoreContinuation(value.context);\n if (value.outcome.ok) return value.outcome.value;\n throw value.outcome.exception;\n}\n\nfunction isTransformedAwait<T>(value: T | TransformedAwait<T>): value is TransformedAwait<T> {\n return Reflect.get(Object(value), TRANSFORMED_AWAIT) === true;\n}\n\nfunction restoreContinuation(context: IoContext): void {\n const token = {};\n continuationContext = { context, token };\n atCheckpointEnd(() => {\n if (continuationContext?.token === token) continuationContext = undefined;\n });\n}\n\nfunction publishOutcome<T, Result>(\n context: IoContext,\n promise: Promise<T>,\n finish: (outcome: Outcome<T>) => Result,\n): Promise<Result> {\n return new Promise<Result>((resolve, reject) => {\n const publish = context.makeTransformReentryCallback((outcome: Outcome<T>) => {\n if (continuationContext !== undefined) {\n schedulePublication({ publish: () => publish(outcome), reject });\n return;\n }\n resolve(finish(outcome));\n });\n void promise.then(\n (value) => {\n schedulePublication({ publish: () => publish({ ok: true, value }), reject });\n },\n (exception: unknown) => {\n schedulePublication({ publish: () => publish({ ok: false, exception }), reject });\n },\n );\n });\n}\n\nfunction resumeAwaitWithContext<T>(\n context: IoContext,\n promise: Promise<T>,\n): Promise<TransformedAwait<T>> {\n return publishOutcome(context, promise, (outcome) => ({\n [TRANSFORMED_AWAIT]: true,\n context,\n outcome,\n }));\n}\n\nfunction resumeWithContext<T>(context: IoContext, promise: Promise<T>): Promise<T> {\n return publishOutcome(context, promise, (outcome) => {\n restoreContinuation(context);\n if (outcome.ok) return outcome.value;\n throw outcome.exception;\n });\n}\n\n/**\n * Resolve one transformed await per task, inside a fresh actor slice. Admission\n * attempts are independent so a blocked actor cannot stall the actor that will\n * unblock it. The task boundary keeps each continuation ambient isolated.\n */\nfunction schedulePublication(publication: Publication): void {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n channel.port1.close();\n channel.port2.close();\n\n void publication.publish().catch((exception: unknown) => {\n publication.reject(exception);\n });\n };\n channel.port2.postMessage(undefined);\n}\n\nfunction iteratorFor<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> | Iterator<T> {\n const subject = Object(iterable);\n const asyncIterator: unknown = Reflect.get(subject, Symbol.asyncIterator);\n if (typeof asyncIterator === \"function\") return Reflect.apply(asyncIterator, iterable, []);\n const iterator: unknown = Reflect.get(subject, Symbol.iterator);\n if (typeof iterator === \"function\") return Reflect.apply(iterator, iterable, []);\n throw new TypeError(\"value is not async iterable or iterable\");\n}\n\nfunction gatedIterator<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> {\n const iterator = iteratorFor(iterable);\n\n function invoke(methodName: \"next\" | \"return\" | \"throw\", args: unknown[]): Promise<IteratorResult<T>> {\n const method: unknown = Reflect.get(iterator, methodName);\n if (typeof method === \"function\") {\n return Promise.resolve(__gate(Reflect.apply(method, iterator, args)));\n }\n if (methodName === \"throw\") return Promise.reject(args[0]);\n return Promise.resolve({ done: true, value: args[0] });\n }\n\n return {\n next: (...args: [] | [unknown]) => invoke(\"next\", args),\n return: (value?: unknown) => invoke(\"return\", [value]),\n throw: (exception?: unknown) => invoke(\"throw\", [exception]),\n };\n}\n\n/** Gate every operation used by `for await`, including early return and throw. */\nexport function __gateAsyncIterable<T, IterableType extends AsyncIterable<T> | Iterable<T>>(\n iterable: IterableType,\n): IterableType;\nexport function __gateAsyncIterable<T>(\n iterable: AsyncIterable<T> | Iterable<T>,\n): AsyncIterable<T> | Iterable<T> {\n const wrapper: AsyncIterable<T> = {\n [Symbol.asyncIterator]: () => gatedIterator(iterable),\n };\n if ((typeof iterable !== \"object\" || iterable === null) && typeof iterable !== \"function\") {\n return wrapper;\n }\n return new Proxy(iterable, {\n get(target, property, receiver): unknown {\n if (property === Symbol.asyncIterator) return wrapper[Symbol.asyncIterator];\n return Reflect.get(target, property, receiver);\n },\n });\n}\n"],"mappings":";;AASA,IAAI;AAWJ,IAAM,oBAAoB,OAAO,qCAAqC;AAQtE,SAAS,WAAW,OAA+C;CACjE,QACG,OAAO,UAAU,YAAY,UAAU,QACxC,OAAO,UAAU,eACd,OAAO,QAAQ,IAAI,OAAO,MAAM,MAAM;AAC7C;;AAGA,SAAgB,OAAU,OAAmC;CAC3D,MAAM,UAAU,gBAAgB,KAAK,qBAAqB;CAC1D,IAAI,CAAC,WAAW,KAAK,KAAK,YAAY,KAAA,GAAW,OAAO;CACxD,IAAI,YAAY,KAAA,GAAW,OAAO;CAClC,OAAO,kBAAkB,SAAS,QAAQ,QAAQ,KAAK,CAAC;AAC1D;;AAGA,SAAgB,YAAe,OAAqD;CAClF,MAAM,UAAU,gBAAgB,KAAK,qBAAqB;CAC1D,IAAI,YAAY,KAAA,GAAW,OAAO;CAClC,OAAO,uBAAuB,SAAS,QAAQ,QAAQ,KAAK,CAAC;AAC/D;;AAGA,SAAgB,cAAiB,OAAmC;CAClE,IAAI,CAAC,mBAAmB,KAAK,GAAG,OAAO;CAEvC,oBAAoB,MAAM,OAAO;CACjC,IAAI,MAAM,QAAQ,IAAI,OAAO,MAAM,QAAQ;CAC3C,MAAM,MAAM,QAAQ;AACtB;AAEA,SAAS,mBAAsB,OAA8D;CAC3F,OAAO,QAAQ,IAAI,OAAO,KAAK,GAAG,iBAAiB,MAAM;AAC3D;AAEA,SAAS,oBAAoB,SAA0B;CACrD,MAAM,QAAQ,CAAC;CACf,sBAAsB;EAAE;EAAS;CAAM;CACvC,sBAAsB;EACpB,IAAI,qBAAqB,UAAU,OAAO,sBAAsB,KAAA;CAClE,CAAC;AACH;AAEA,SAAS,eACP,SACA,SACA,QACiB;CACjB,OAAO,IAAI,SAAiB,SAAS,WAAW;EAC9C,MAAM,UAAU,QAAQ,8BAA8B,YAAwB;GAC5E,IAAI,wBAAwB,KAAA,GAAW;IACrC,oBAAoB;KAAE,eAAe,QAAQ,OAAO;KAAG;IAAO,CAAC;IAC/D;GACF;GACA,QAAQ,OAAO,OAAO,CAAC;EACzB,CAAC;EACD,QAAa,MACV,UAAU;GACT,oBAAoB;IAAE,eAAe,QAAQ;KAAE,IAAI;KAAM;IAAM,CAAC;IAAG;GAAO,CAAC;EAC7E,IACC,cAAuB;GACtB,oBAAoB;IAAE,eAAe,QAAQ;KAAE,IAAI;KAAO;IAAU,CAAC;IAAG;GAAO,CAAC;EAClF,CACF;CACF,CAAC;AACH;AAEA,SAAS,uBACP,SACA,SAC8B;CAC9B,OAAO,eAAe,SAAS,UAAU,aAAa;GACnD,oBAAoB;EACrB;EACA;CACF,EAAE;AACJ;AAEA,SAAS,kBAAqB,SAAoB,SAAiC;CACjF,OAAO,eAAe,SAAS,UAAU,YAAY;EACnD,oBAAoB,OAAO;EAC3B,IAAI,QAAQ,IAAI,OAAO,QAAQ;EAC/B,MAAM,QAAQ;CAChB,CAAC;AACH;;;;;;AAOA,SAAS,oBAAoB,aAAgC;CAC3D,MAAM,UAAU,IAAI,eAAe;CACnC,QAAQ,MAAM,kBAAkB;EAC9B,QAAQ,MAAM,MAAM;EACpB,QAAQ,MAAM,MAAM;EAEpB,YAAiB,QAAQ,CAAC,CAAC,OAAO,cAAuB;GACvD,YAAY,OAAO,SAAS;EAC9B,CAAC;CACH;CACA,QAAQ,MAAM,YAAY,KAAA,CAAS;AACrC;AAEA,SAAS,YAAe,UAA0E;CAChG,MAAM,UAAU,OAAO,QAAQ;CAC/B,MAAM,gBAAyB,QAAQ,IAAI,SAAS,OAAO,aAAa;CACxE,IAAI,OAAO,kBAAkB,YAAY,OAAO,QAAQ,MAAM,eAAe,UAAU,CAAC,CAAC;CACzF,MAAM,WAAoB,QAAQ,IAAI,SAAS,OAAO,QAAQ;CAC9D,IAAI,OAAO,aAAa,YAAY,OAAO,QAAQ,MAAM,UAAU,UAAU,CAAC,CAAC;CAC/E,MAAM,IAAI,UAAU,yCAAyC;AAC/D;AAEA,SAAS,cAAiB,UAA4D;CACpF,MAAM,WAAW,YAAY,QAAQ;CAErC,SAAS,OAAO,YAAyC,MAA6C;EACpG,MAAM,SAAkB,QAAQ,IAAI,UAAU,UAAU;EACxD,IAAI,OAAO,WAAW,YACpB,OAAO,QAAQ,QAAQ,OAAO,QAAQ,MAAM,QAAQ,UAAU,IAAI,CAAC,CAAC;EAEtE,IAAI,eAAe,SAAS,OAAO,QAAQ,OAAO,KAAK,EAAE;EACzD,OAAO,QAAQ,QAAQ;GAAE,MAAM;GAAM,OAAO,KAAK;EAAG,CAAC;CACvD;CAEA,OAAO;EACL,OAAO,GAAG,SAAyB,OAAO,QAAQ,IAAI;EACtD,SAAS,UAAoB,OAAO,UAAU,CAAC,KAAK,CAAC;EACrD,QAAQ,cAAwB,OAAO,SAAS,CAAC,SAAS,CAAC;CAC7D;AACF;AAMA,SAAgB,oBACd,UACgC;CAChC,MAAM,UAA4B,GAC/B,OAAO,sBAAsB,cAAc,QAAQ,EACtD;CACA,KAAK,OAAO,aAAa,YAAY,aAAa,SAAS,OAAO,aAAa,YAC7E,OAAO;CAET,OAAO,IAAI,MAAM,UAAU,EACzB,IAAI,QAAQ,UAAU,UAAmB;EACvC,IAAI,aAAa,OAAO,eAAe,OAAO,QAAQ,OAAO;EAC7D,OAAO,QAAQ,IAAI,QAAQ,UAAU,QAAQ;CAC/C,EACF,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"gate.js","names":[],"sources":["../src/gate.ts"],"sourcesContent":["/* @do-runtime-gated */\n\nimport {\n atCheckpointEnd,\n tryCurrentContinuation,\n tryCurrentIoContext,\n type IoContext,\n} from \"./io/io-context\";\n\ntype Publication = {\n readonly publish: () => Promise<void>;\n readonly reject: (exception: unknown) => void;\n};\n\ntype Outcome<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly exception: unknown };\n\nconst TRANSFORMED_AWAIT = Symbol(\"@mcp-b/do-runtime/transformed-await\");\n/**\n * Own the gap between publishing an await result and its `__resumeAwait` call.\n * This is deliberately separate from the current-continuation ambient: a\n * reservation serializes publishers but must never make its actor look current.\n * See §2.3 and decision 8.\n */\nconst CURRENT_PUBLICATION = Symbol.for(\"@mcp-b/do-runtime/current-await-publication\");\nconst warnedUngatedAwaits = new Set<string>();\n\ntype PublicationReservation = {\n readonly context: IoContext;\n};\n\ntype TransformedAwait<T> = {\n readonly [TRANSFORMED_AWAIT]: true;\n readonly context: IoContext;\n readonly outcome: Outcome<T>;\n readonly reservation: PublicationReservation;\n};\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n (typeof value === \"object\" && value !== null) ||\n typeof value === \"function\"\n ) && typeof Reflect.get(value, \"then\") === \"function\";\n}\n\n/** Re-enter the actor that owns this transformed await; fail open outside actors. */\nexport function __gate<T>(value: T): T | Promise<Awaited<T>> {\n const context = tryCurrentIoContext();\n if (!isThenable(value) && context === undefined) return value;\n if (context === undefined) return value;\n return resumeWithContext(context, Promise.resolve(value));\n}\n\n/** Capture an actor await without publishing its context before the continuation runs. */\nexport function __gateAwait<T>(\n value: T,\n developmentSource?: string,\n): T | Promise<TransformedAwait<Awaited<T>>> {\n const context = tryCurrentIoContext();\n if (context === undefined) {\n if (developmentSource !== undefined && !warnedUngatedAwaits.has(developmentSource)) {\n warnedUngatedAwaits.add(developmentSource);\n console.warn(\n `do-runtime: transformed await in ${developmentSource} ran without an actor input lock; ` +\n \"an earlier await or entry path is not gated\",\n );\n }\n return value;\n }\n return resumeAwaitWithContext(context, Promise.resolve(value));\n}\n\n/** Restore the captured actor at the first instruction after a transformed await. */\nexport function __resumeAwait<T>(value: T | TransformedAwait<T>): T {\n if (!isTransformedAwait(value)) return value as T;\n\n clearPublication(value.reservation);\n value.context.restoreContinuation();\n if (value.outcome.ok) return value.outcome.value;\n throw value.outcome.exception;\n}\n\nfunction isTransformedAwait<T>(value: T | TransformedAwait<T>): value is TransformedAwait<T> {\n return Reflect.get(Object(value), TRANSFORMED_AWAIT) === true;\n}\n\nfunction currentPublication(): PublicationReservation | undefined {\n return Reflect.get(globalThis, CURRENT_PUBLICATION) as PublicationReservation | undefined;\n}\n\nfunction reservePublication(context: IoContext): PublicationReservation | undefined {\n if (tryCurrentContinuation() !== undefined || currentPublication() !== undefined) return undefined;\n const reservation = { context };\n Reflect.set(globalThis, CURRENT_PUBLICATION, reservation);\n atCheckpointEnd(() => clearPublication(reservation));\n return reservation;\n}\n\nfunction clearPublication(reservation: PublicationReservation): void {\n if (currentPublication() === reservation) {\n Reflect.deleteProperty(globalThis, CURRENT_PUBLICATION);\n }\n}\n\nfunction publishOutcome<T, Result>(\n context: IoContext,\n promise: Promise<T>,\n finish: (outcome: Outcome<T>, reservation: PublicationReservation) => Result,\n): Promise<Result> {\n return new Promise<Result>((resolve, reject) => {\n const publish = context.makeTransformReentryCallback((outcome: Outcome<T>) => {\n const reservation = reservePublication(context);\n if (reservation === undefined) {\n schedulePublication({ publish: () => publish(outcome), reject });\n return;\n }\n resolve(finish(outcome, reservation));\n });\n void promise.then(\n (value) => {\n schedulePublication({ publish: () => publish({ ok: true, value }), reject });\n },\n (exception: unknown) => {\n schedulePublication({ publish: () => publish({ ok: false, exception }), reject });\n },\n );\n });\n}\n\nfunction resumeAwaitWithContext<T>(\n context: IoContext,\n promise: Promise<T>,\n): Promise<TransformedAwait<T>> {\n return publishOutcome(context, promise, (outcome, reservation) => ({\n [TRANSFORMED_AWAIT]: true,\n context,\n outcome,\n reservation,\n }));\n}\n\nfunction resumeWithContext<T>(context: IoContext, promise: Promise<T>): Promise<T> {\n return publishOutcome(context, promise, (outcome, reservation) => {\n clearPublication(reservation);\n context.restoreContinuation();\n if (outcome.ok) return outcome.value;\n throw outcome.exception;\n });\n}\n\n/**\n * Resolve one transformed await per task, inside a fresh actor slice. Admission\n * attempts are independent so a blocked actor cannot stall the actor that will\n * unblock it. The task boundary keeps each continuation ambient isolated.\n */\nfunction schedulePublication(publication: Publication): void {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n channel.port1.close();\n channel.port2.close();\n\n void publication.publish().catch((exception: unknown) => {\n publication.reject(exception);\n });\n };\n channel.port2.postMessage(undefined);\n}\n\nfunction iteratorFor<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> | Iterator<T> {\n const subject = Object(iterable);\n const asyncIterator: unknown = Reflect.get(subject, Symbol.asyncIterator);\n if (typeof asyncIterator === \"function\") return Reflect.apply(asyncIterator, iterable, []);\n const iterator: unknown = Reflect.get(subject, Symbol.iterator);\n if (typeof iterator === \"function\") return Reflect.apply(iterator, iterable, []);\n throw new TypeError(\"value is not async iterable or iterable\");\n}\n\nfunction gatedIterator<T>(iterable: AsyncIterable<T> | Iterable<T>): AsyncIterator<T> {\n const iterator = iteratorFor(iterable);\n\n function invoke(methodName: \"next\" | \"return\" | \"throw\", args: unknown[]): Promise<IteratorResult<T>> {\n const method: unknown = Reflect.get(iterator, methodName);\n if (typeof method === \"function\") {\n return Promise.resolve(__gate(Reflect.apply(method, iterator, args)));\n }\n if (methodName === \"throw\") return Promise.reject(args[0]);\n return Promise.resolve({ done: true, value: args[0] });\n }\n\n return {\n next: (...args: [] | [unknown]) => invoke(\"next\", args),\n return: (value?: unknown) => invoke(\"return\", [value]),\n throw: (exception?: unknown) => invoke(\"throw\", [exception]),\n };\n}\n\n/** Gate every operation used by `for await`, including early return and throw. */\nexport function __gateAsyncIterable<T, IterableType extends AsyncIterable<T> | Iterable<T>>(\n iterable: IterableType,\n): IterableType;\nexport function __gateAsyncIterable<T>(\n iterable: AsyncIterable<T> | Iterable<T>,\n): AsyncIterable<T> | Iterable<T> {\n const wrapper: AsyncIterable<T> = {\n [Symbol.asyncIterator]: () => gatedIterator(iterable),\n };\n if ((typeof iterable !== \"object\" || iterable === null) && typeof iterable !== \"function\") {\n return wrapper;\n }\n return new Proxy(iterable, {\n get(target, property, receiver): unknown {\n if (property === Symbol.asyncIterator) return wrapper[Symbol.asyncIterator];\n return Reflect.get(target, property, receiver);\n },\n });\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as hasUserErrorDetail, c as setUserErrorDetail, d as tryCurrentSlice, f as CanceledError, i as captureGateStack, m as OutputGate, n as IoContext, o as isExceptionFromInputGateBroken, p as InputGate, r as atCheckpointEnd, s as requireInputLock, t as BrokenActorError, u as tryCurrentIoContext } from "./chunks/io-context-RmmjNtwm.js";
|
|
2
2
|
import { RpcTarget as RpcTarget$1 } from "./cloudflare-workers.js";
|
|
3
3
|
import { a as getInt64, c as isNull, i as getBlob, o as getText, r as SqliteDatabase, s as hasCurrentSqliteTable } from "./chunks/sqlite-DFg92Tgt.js";
|
|
4
4
|
import { ALARM_RETRY_MAX_TRIES, ALARM_RETRY_START_SECONDS, AlarmScheduler, RETRY_BACKOFF_MAX, RETRY_JITTER_FACTOR, alarmRetryDelayMs } from "./server/alarm-scheduler.js";
|
|
@@ -1366,70 +1366,6 @@ function asRawRow(values) {
|
|
|
1366
1366
|
return values;
|
|
1367
1367
|
}
|
|
1368
1368
|
//#endregion
|
|
1369
|
-
//#region src/api/sync-kv.ts
|
|
1370
|
-
var SyncKvStorage = class {
|
|
1371
|
-
#ctx;
|
|
1372
|
-
#owner;
|
|
1373
|
-
constructor(ctx, owner) {
|
|
1374
|
-
this.#ctx = ctx;
|
|
1375
|
-
this.#owner = owner;
|
|
1376
|
-
}
|
|
1377
|
-
get(key) {
|
|
1378
|
-
requireInputLock(this.#ctx, "kv.get()");
|
|
1379
|
-
const value = this.#owner.getSqliteKv().get(key);
|
|
1380
|
-
if (value === void 0) return void 0;
|
|
1381
|
-
return deserializeValue(key, value);
|
|
1382
|
-
}
|
|
1383
|
-
/**
|
|
1384
|
-
* ← `SyncKvStorage::list`, which reuses `compileListOptions` — "This is public
|
|
1385
|
-
* so that SyncKvStorage can reuse it."
|
|
1386
|
-
*/
|
|
1387
|
-
list(options) {
|
|
1388
|
-
requireInputLock(this.#ctx, "kv.list()");
|
|
1389
|
-
const compiled = compileListOptions(options);
|
|
1390
|
-
if (compiled === void 0) return { [Symbol.iterator]: () => emptyIterator() };
|
|
1391
|
-
const cursor = this.#owner.getSqliteKv().list(compiled.start, compiled.end, compiled.limit, compiled.reverse ? "REVERSE" : "FORWARD");
|
|
1392
|
-
return { [Symbol.iterator]: () => listIterator(cursor) };
|
|
1393
|
-
}
|
|
1394
|
-
put(key, value) {
|
|
1395
|
-
requireInputLock(this.#ctx, "kv.put()");
|
|
1396
|
-
this.#owner.getSqliteKv().put(key, serializeValue(key, value));
|
|
1397
|
-
}
|
|
1398
|
-
delete(key) {
|
|
1399
|
-
requireInputLock(this.#ctx, "kv.delete()");
|
|
1400
|
-
return this.#owner.getSqliteKv().delete(key);
|
|
1401
|
-
}
|
|
1402
|
-
};
|
|
1403
|
-
/** ← `SyncKvStorage::listNext`, whose cancellation branch is the reason it is not a plain loop. */
|
|
1404
|
-
function listIterator(cursor) {
|
|
1405
|
-
const iterator = {
|
|
1406
|
-
[Symbol.iterator]: () => iterator,
|
|
1407
|
-
next: () => {
|
|
1408
|
-
const pair = cursor.next();
|
|
1409
|
-
if (pair !== void 0) return {
|
|
1410
|
-
done: false,
|
|
1411
|
-
value: [pair.key, deserializeValue(pair.key, pair.value)]
|
|
1412
|
-
};
|
|
1413
|
-
if (cursor.wasCanceled()) throw new Error("kv.list() iterator was invalidated because a new call to kv.list() was started. Only one kv.list() iterator can exist at a time.");
|
|
1414
|
-
return {
|
|
1415
|
-
done: true,
|
|
1416
|
-
value: void 0
|
|
1417
|
-
};
|
|
1418
|
-
}
|
|
1419
|
-
};
|
|
1420
|
-
return iterator;
|
|
1421
|
-
}
|
|
1422
|
-
function emptyIterator() {
|
|
1423
|
-
const iterator = {
|
|
1424
|
-
[Symbol.iterator]: () => iterator,
|
|
1425
|
-
next: () => ({
|
|
1426
|
-
done: true,
|
|
1427
|
-
value: void 0
|
|
1428
|
-
})
|
|
1429
|
-
};
|
|
1430
|
-
return iterator;
|
|
1431
|
-
}
|
|
1432
|
-
//#endregion
|
|
1433
1369
|
//#region src/api/actor-state.ts
|
|
1434
1370
|
/**
|
|
1435
1371
|
* ← workerd `src/workerd/api/actor-state.{h,c++}`
|
|
@@ -1441,8 +1377,8 @@ function emptyIterator() {
|
|
|
1441
1377
|
* **`DurableObjectStorage` satisfies workers-types with no cast (§2.4).** That
|
|
1442
1378
|
* was checked rather than asserted, and two shapes here exist only because it
|
|
1443
1379
|
* has to: `sql.Cursor` and `sql.Statement` must be constructible with no
|
|
1444
|
-
* arguments (see `sql.ts`), and `storage.kv` is required
|
|
1445
|
-
*
|
|
1380
|
+
* arguments (see `sql.ts`), and `storage.kv` is required. The narrowings that
|
|
1381
|
+
* remain are all one thing —
|
|
1446
1382
|
* `get<T>` returns the caller's claim about the shape of a value SQLite handed
|
|
1447
1383
|
* back as bytes, which no check can confirm and which upstream states the same
|
|
1448
1384
|
* way, as a `jsg::JsRef<jsg::JsValue>` behind a `JSG_TS_OVERRIDE`'d
|
|
@@ -1452,8 +1388,7 @@ function emptyIterator() {
|
|
|
1452
1388
|
* That is upstream's: a `JSG_REQUIRE` inside a method returning `jsg::Promise`
|
|
1453
1389
|
* throws into the isolate before the promise exists, so `put(k, undefined)`
|
|
1454
1390
|
* throws rather than rejecting. The same goes for a value that will not decode,
|
|
1455
|
-
* because §1.4 makes the SQLite path
|
|
1456
|
-
* run the decoder synchronously.
|
|
1391
|
+
* because §1.4 makes the SQLite path run the decoder before `Promise.resolve`.
|
|
1457
1392
|
*
|
|
1458
1393
|
* **What the input gate does and does not do here.** Every entry point calls
|
|
1459
1394
|
* `requireInputLock` — see its comment in `io/io-context.ts`, which is the one
|
|
@@ -1465,13 +1400,10 @@ function emptyIterator() {
|
|
|
1465
1400
|
* section.
|
|
1466
1401
|
*
|
|
1467
1402
|
* **Decision 2's branch has one reachable site**, and it is not where upstream's
|
|
1468
|
-
* is.
|
|
1469
|
-
* `
|
|
1470
|
-
*
|
|
1471
|
-
*
|
|
1472
|
-
* it, because `DeleteAllResults.backpressure` is still a promise in
|
|
1473
|
-
* `io/actor-cache.ts`. Both helpers are kept under upstream's names so the
|
|
1474
|
-
* question "where did `allowConcurrency` go" is answered by reading them.
|
|
1403
|
+
* is. §1.4 measures that SQLite cache operations are immediate, so their
|
|
1404
|
+
* `kj::OneOf<T, kj::Promise<T>>` branch has nothing to select between.
|
|
1405
|
+
* `transformMaybeBackpressure` keeps the branch because
|
|
1406
|
+
* `DeleteAllResults.backpressure` is still a promise in `io/actor-cache.ts`.
|
|
1475
1407
|
*
|
|
1476
1408
|
* Not ported, because the substrate has no equivalent: Hibernatable WebSockets,
|
|
1477
1409
|
* which is the whole reason `DurableObjectState`'s eight WebSocket methods are
|
|
@@ -1546,7 +1478,7 @@ var VALUE_CODEC_HEADER = new Uint8Array([
|
|
|
1546
1478
|
* The short header keeps the new representation unambiguous while old JSON rows
|
|
1547
1479
|
* remain readable.
|
|
1548
1480
|
*/
|
|
1549
|
-
function serializeValue(
|
|
1481
|
+
function serializeValue(value) {
|
|
1550
1482
|
const body = textEncoder.encode(JSON.stringify(serialize(value)));
|
|
1551
1483
|
const encoded = new Uint8Array(VALUE_CODEC_HEADER.byteLength + body.byteLength);
|
|
1552
1484
|
encoded.set(VALUE_CODEC_HEADER);
|
|
@@ -1573,26 +1505,6 @@ function deserializeValue(key, buffer) {
|
|
|
1573
1505
|
throw new Error(`actor storage deserialization failed: failed to deserialize stored value; key = ${key}; size = ${buffer.byteLength}`, { cause: exception });
|
|
1574
1506
|
}
|
|
1575
1507
|
}
|
|
1576
|
-
/** ← `deserializeMaybeV8Value`. */
|
|
1577
|
-
function deserializeMaybeValue(key, buffer) {
|
|
1578
|
-
return buffer === void 0 ? void 0 : deserializeValue(key, buffer);
|
|
1579
|
-
}
|
|
1580
|
-
/**
|
|
1581
|
-
* ← `transformCacheResult` and `transformCacheResultWithCacheStatus`
|
|
1582
|
-
* (`actor-state.c++:49-101`), with the arm that cannot happen removed.
|
|
1583
|
-
*
|
|
1584
|
-
* Upstream's body is a two-arm switch on `kj::OneOf<T, kj::Promise<T>>`, and the
|
|
1585
|
-
* `allowConcurrency` branch lives in the promise arm. §1.4 measures that a
|
|
1586
|
-
* SQLite-backed actor returns the immediate arm at every call site, so Section 4
|
|
1587
|
-
* collapsed the `OneOf` to `T` and there is no promise left to await — and
|
|
1588
|
-
* therefore no gate decision to make. The name is kept so a reader comparing the
|
|
1589
|
-
* two files finds the answer here rather than inferring an omission. The
|
|
1590
|
-
* `WithCacheStatus` variant differs only in a `cached` flag feeding billing
|
|
1591
|
-
* counters that have no port, so the two collapse to one function.
|
|
1592
|
-
*/
|
|
1593
|
-
function transformCacheResult(value, func) {
|
|
1594
|
-
return Promise.resolve(func(value));
|
|
1595
|
-
}
|
|
1596
1508
|
/**
|
|
1597
1509
|
* ← `transformMaybeBackpressure` (`actor-state.c++:103-119`). THIS is decision
|
|
1598
1510
|
* 2's live site: `DeleteAllResults.backpressure` is still `Promise<void> |
|
|
@@ -1611,8 +1523,8 @@ function transformMaybeBackpressure(ctx, options, maybeBackpressure) {
|
|
|
1611
1523
|
/**
|
|
1612
1524
|
* ← `DurableObjectStorageOperations::compileListOptions`
|
|
1613
1525
|
* (`actor-state.c++:314-417`). Returns undefined if the list operation would
|
|
1614
|
-
* provably return no results.
|
|
1615
|
-
*
|
|
1526
|
+
* provably return no results. `SyncKvStorage` reuses it, exactly as upstream's
|
|
1527
|
+
* comment says it must.
|
|
1616
1528
|
*
|
|
1617
1529
|
* Two translations. `startAfter` gains ONE null character where upstream's
|
|
1618
1530
|
* `kj::String` gains two, because the second of upstream's is the terminator and
|
|
@@ -1671,6 +1583,51 @@ function firstKeyAfterPrefix(prefix) {
|
|
|
1671
1583
|
return head.slice(0, -1) + String.fromCharCode(head.charCodeAt(head.length - 1) + 1);
|
|
1672
1584
|
}
|
|
1673
1585
|
/**
|
|
1586
|
+
* ← workerd `src/workerd/api/sync-kv.{h,c++}`. The synchronous surface lives
|
|
1587
|
+
* beside the asynchronous storage owner because both share the same codec and
|
|
1588
|
+
* list-option compiler over one `SqliteKv`.
|
|
1589
|
+
*/
|
|
1590
|
+
var SyncKvStorage = class {
|
|
1591
|
+
#ctx;
|
|
1592
|
+
#kv;
|
|
1593
|
+
constructor(ctx, kv) {
|
|
1594
|
+
this.#ctx = ctx;
|
|
1595
|
+
this.#kv = kv;
|
|
1596
|
+
}
|
|
1597
|
+
get(key) {
|
|
1598
|
+
requireInputLock(this.#ctx, "kv.get()");
|
|
1599
|
+
const value = this.#kv.get(key);
|
|
1600
|
+
if (value === void 0) return void 0;
|
|
1601
|
+
return deserializeValue(key, value);
|
|
1602
|
+
}
|
|
1603
|
+
list(options) {
|
|
1604
|
+
requireInputLock(this.#ctx, "kv.list()");
|
|
1605
|
+
const compiled = compileListOptions(options);
|
|
1606
|
+
if (compiled === void 0) return [];
|
|
1607
|
+
return listIterator(this.#kv.list(compiled.start, compiled.end, compiled.limit, compiled.reverse ? "REVERSE" : "FORWARD"));
|
|
1608
|
+
}
|
|
1609
|
+
put(key, value) {
|
|
1610
|
+
requireInputLock(this.#ctx, "kv.put()");
|
|
1611
|
+
this.#kv.put(key, serializeValue(value));
|
|
1612
|
+
}
|
|
1613
|
+
delete(key) {
|
|
1614
|
+
requireInputLock(this.#ctx, "kv.delete()");
|
|
1615
|
+
return this.#kv.delete(key);
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
/** ← `SyncKvStorage::listNext`, whose cancellation branch is the reason it is not a plain loop. */
|
|
1619
|
+
function* listIterator(cursor) {
|
|
1620
|
+
for (;;) {
|
|
1621
|
+
const pair = cursor.next();
|
|
1622
|
+
if (pair !== void 0) {
|
|
1623
|
+
yield [pair.key, deserializeValue(pair.key, pair.value)];
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
if (cursor.wasCanceled()) throw new Error("kv.list() iterator was invalidated because a new call to kv.list() was started. Only one kv.list() iterator can exist at a time.");
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
/**
|
|
1674
1631
|
* ← `DurableObjectStorageOperations`. "Common implementation of
|
|
1675
1632
|
* DurableObjectStorage and DurableObjectTransaction. This class is designed to
|
|
1676
1633
|
* be used as a mixin."
|
|
@@ -1680,88 +1637,74 @@ var DurableObjectStorageOperations = class {
|
|
|
1680
1637
|
constructor(ctx) {
|
|
1681
1638
|
this.ctx = ctx;
|
|
1682
1639
|
}
|
|
1683
|
-
/** Whether to skip caching and allow concurrency on all operations. */
|
|
1684
|
-
useDirectIo() {
|
|
1685
|
-
return false;
|
|
1686
|
-
}
|
|
1687
|
-
/**
|
|
1688
|
-
* ← `configureOptions`. Both subclasses answer `useDirectIo()` false, so this
|
|
1689
|
-
* is the identity today; it is upstream's hook and the only place the two
|
|
1690
|
-
* flags are forced on.
|
|
1691
|
-
*/
|
|
1692
|
-
configureOptions(options) {
|
|
1693
|
-
if (!this.useDirectIo()) return options;
|
|
1694
|
-
return {
|
|
1695
|
-
...options,
|
|
1696
|
-
allowConcurrency: true,
|
|
1697
|
-
noCache: true
|
|
1698
|
-
};
|
|
1699
|
-
}
|
|
1700
1640
|
get(keyOrKeys, maybeOptions) {
|
|
1701
1641
|
requireInputLock(this.ctx, OP_GET);
|
|
1702
|
-
const options =
|
|
1642
|
+
const options = { ...maybeOptions };
|
|
1703
1643
|
if (typeof keyOrKeys === "string") return this.#getOne(keyOrKeys, options);
|
|
1704
1644
|
return this.#getMultiple(keyOrKeys, options);
|
|
1705
1645
|
}
|
|
1706
1646
|
getAlarm(maybeOptions) {
|
|
1707
1647
|
requireInputLock(this.ctx, OP_GET_ALARM);
|
|
1708
|
-
const options =
|
|
1648
|
+
const options = {
|
|
1709
1649
|
...maybeOptions,
|
|
1710
1650
|
noCache: false
|
|
1711
|
-
}
|
|
1712
|
-
return
|
|
1651
|
+
};
|
|
1652
|
+
return Promise.resolve(this.getCache(OP_GET_ALARM).getAlarm(options));
|
|
1713
1653
|
}
|
|
1714
1654
|
list(maybeOptions) {
|
|
1715
1655
|
requireInputLock(this.ctx, OP_LIST);
|
|
1716
1656
|
const compiled = compileListOptions(maybeOptions);
|
|
1717
1657
|
if (compiled === void 0) return Promise.resolve(/* @__PURE__ */ new Map());
|
|
1718
|
-
const options =
|
|
1658
|
+
const options = { ...maybeOptions };
|
|
1719
1659
|
const cache = this.getCache(OP_LIST);
|
|
1720
|
-
|
|
1660
|
+
const result = compiled.reverse ? cache.listReverse(compiled.start, compiled.end, compiled.limit, options) : cache.list(compiled.start, compiled.end, compiled.limit, options);
|
|
1661
|
+
return Promise.resolve(listResultsToMap(result));
|
|
1721
1662
|
}
|
|
1722
1663
|
put(keyOrEntries, valueOrOptions, maybeOptions) {
|
|
1723
1664
|
requireInputLock(this.ctx, OP_PUT);
|
|
1724
1665
|
if (typeof keyOrEntries === "string") {
|
|
1725
1666
|
if (valueOrOptions === void 0) throw new TypeError("put() called with undefined value.");
|
|
1726
|
-
return this.#putOne(keyOrEntries, valueOrOptions,
|
|
1667
|
+
return this.#putOne(keyOrEntries, valueOrOptions, { ...maybeOptions });
|
|
1727
1668
|
}
|
|
1728
|
-
return this.#putMultiple(keyOrEntries,
|
|
1669
|
+
return this.#putMultiple(keyOrEntries, { ...valueOrOptions });
|
|
1729
1670
|
}
|
|
1730
1671
|
delete(keyOrKeys, maybeOptions) {
|
|
1731
1672
|
requireInputLock(this.ctx, OP_DELETE);
|
|
1732
|
-
const options =
|
|
1733
|
-
if (typeof keyOrKeys === "string") return
|
|
1734
|
-
return
|
|
1673
|
+
const options = { ...maybeOptions };
|
|
1674
|
+
if (typeof keyOrKeys === "string") return Promise.resolve(this.getCache(OP_DELETE).delete(keyOrKeys, options));
|
|
1675
|
+
return Promise.resolve(this.getCache(OP_DELETE).deleteMultiple(keyOrKeys, options));
|
|
1735
1676
|
}
|
|
1736
1677
|
setAlarm(scheduledTime, maybeOptions) {
|
|
1737
1678
|
requireInputLock(this.ctx, OP_PUT_ALARM);
|
|
1738
1679
|
const when = scheduledTime instanceof Date ? scheduledTime.getTime() : scheduledTime;
|
|
1739
1680
|
if (!(when > 0)) throw new TypeError("setAlarm() cannot be called with an alarm time <= 0");
|
|
1740
1681
|
this.ctx.getActorOrThrow().assertCanSetAlarm();
|
|
1741
|
-
const options =
|
|
1682
|
+
const options = {
|
|
1742
1683
|
...maybeOptions,
|
|
1743
1684
|
noCache: false
|
|
1744
|
-
}
|
|
1685
|
+
};
|
|
1745
1686
|
this.getCache(OP_PUT_ALARM).setAlarm(Math.max(when, this.ctx.now()), options);
|
|
1746
1687
|
return Promise.resolve();
|
|
1747
1688
|
}
|
|
1748
1689
|
deleteAlarm(maybeOptions) {
|
|
1749
1690
|
requireInputLock(this.ctx, OP_DELETE_ALARM);
|
|
1750
|
-
const options =
|
|
1691
|
+
const options = {
|
|
1751
1692
|
...maybeOptions,
|
|
1752
1693
|
noCache: false
|
|
1753
|
-
}
|
|
1694
|
+
};
|
|
1754
1695
|
this.getCache(OP_DELETE_ALARM).setAlarm(null, options);
|
|
1755
1696
|
return Promise.resolve();
|
|
1756
1697
|
}
|
|
1757
1698
|
#getOne(key, options) {
|
|
1758
|
-
|
|
1699
|
+
const value = this.getCache(OP_GET).get(key, options);
|
|
1700
|
+
return Promise.resolve(value === void 0 ? void 0 : deserializeValue(key, value));
|
|
1759
1701
|
}
|
|
1760
1702
|
#getMultiple(keys, options) {
|
|
1761
|
-
|
|
1703
|
+
const result = this.getCache(OP_GET).getMultiple(keys, options);
|
|
1704
|
+
return Promise.resolve(listResultsToMap(result));
|
|
1762
1705
|
}
|
|
1763
1706
|
#putOne(key, value, options) {
|
|
1764
|
-
this.getCache(OP_PUT).put(key, serializeValue(
|
|
1707
|
+
this.getCache(OP_PUT).put(key, serializeValue(value), options);
|
|
1765
1708
|
return Promise.resolve();
|
|
1766
1709
|
}
|
|
1767
1710
|
#putMultiple(entries, options) {
|
|
@@ -1770,7 +1713,7 @@ var DurableObjectStorageOperations = class {
|
|
|
1770
1713
|
if (value === void 0) continue;
|
|
1771
1714
|
pairs.push({
|
|
1772
1715
|
key,
|
|
1773
|
-
value: serializeValue(
|
|
1716
|
+
value: serializeValue(value)
|
|
1774
1717
|
});
|
|
1775
1718
|
}
|
|
1776
1719
|
this.getCache(OP_PUT).putMultiple(pairs, options);
|
|
@@ -1799,10 +1742,6 @@ var DurableObjectStorage = class extends DurableObjectStorageOperations {
|
|
|
1799
1742
|
getSqliteDb() {
|
|
1800
1743
|
return this.#cache.getSqliteDatabase();
|
|
1801
1744
|
}
|
|
1802
|
-
/** ← `DurableObjectStorage::getSqliteKv`. */
|
|
1803
|
-
getSqliteKv() {
|
|
1804
|
-
return this.#cache.getSqliteKv();
|
|
1805
|
-
}
|
|
1806
1745
|
getCache() {
|
|
1807
1746
|
return this.#cache;
|
|
1808
1747
|
}
|
|
@@ -1813,7 +1752,7 @@ var DurableObjectStorage = class extends DurableObjectStorageOperations {
|
|
|
1813
1752
|
}
|
|
1814
1753
|
/** ← `JSG_LAZY_INSTANCE_PROPERTY(kv, getKv)`. */
|
|
1815
1754
|
get kv() {
|
|
1816
|
-
this.#kv ??= new SyncKvStorage(this.ctx, this);
|
|
1755
|
+
this.#kv ??= new SyncKvStorage(this.ctx, this.#cache.getSqliteKv());
|
|
1817
1756
|
return this.#kv;
|
|
1818
1757
|
}
|
|
1819
1758
|
/**
|
|
@@ -1825,7 +1764,7 @@ var DurableObjectStorage = class extends DurableObjectStorageOperations {
|
|
|
1825
1764
|
*/
|
|
1826
1765
|
deleteAll(maybeOptions) {
|
|
1827
1766
|
requireInputLock(this.ctx, "deleteAll()");
|
|
1828
|
-
const options =
|
|
1767
|
+
const options = { ...maybeOptions };
|
|
1829
1768
|
const result = this.#cache.deleteAll(options, { deleteAlarm: true });
|
|
1830
1769
|
return transformMaybeBackpressure(this.ctx, options, result.backpressure);
|
|
1831
1770
|
}
|
|
@@ -2140,7 +2079,7 @@ var DurableObjectState = class {
|
|
|
2140
2079
|
* gated slice.
|
|
2141
2080
|
*/
|
|
2142
2081
|
blockConcurrencyWhile(callback) {
|
|
2143
|
-
return this.#ctx.blockConcurrencyWhile(
|
|
2082
|
+
return this.#ctx.blockConcurrencyWhile(callback);
|
|
2144
2083
|
}
|
|
2145
2084
|
/**
|
|
2146
2085
|
* ← `DurableObjectState::abort`. Reset the object, including breaking the
|
|
@@ -2490,7 +2429,7 @@ function gateReader(ctx, reader) {
|
|
|
2490
2429
|
* "wrap it in awaitIo" would be wrong three ways:
|
|
2491
2430
|
*
|
|
2492
2431
|
* - **Timers** capture the critical section at the ARMING call and re-enter
|
|
2493
|
-
* through `ctx.run(callback, cs)` when they fire. Not `awaitIo`, deliberately
|
|
2432
|
+
* through `ctx.run(callback, { input: cs })` when they fire. Not `awaitIo`, deliberately
|
|
2494
2433
|
* — see `TimeoutManager` in `io/io-context.ts` for upstream's own reason.
|
|
2495
2434
|
* - **`fetch`** is `awaitIo` (`http.c++` has ten of them and zero
|
|
2496
2435
|
* `awaitIoWithInputLock`), preceded by an output-gate wait so nothing departs
|
|
@@ -2996,7 +2935,7 @@ var AcceptedWebSocket = class extends EventTarget {
|
|
|
2996
2935
|
this.dispatchEvent(delivered);
|
|
2997
2936
|
const handler = this[`on${type}`];
|
|
2998
2937
|
handler?.(delivered);
|
|
2999
|
-
}, this.#criticalSection));
|
|
2938
|
+
}, { input: this.#criticalSection }));
|
|
3000
2939
|
}
|
|
3001
2940
|
/**
|
|
3002
2941
|
* ← `WebSocket::send` (`web-socket.c++:~640`), which inserts a
|
|
@@ -5662,6 +5601,15 @@ var ActorContainerImpl = class {
|
|
|
5662
5601
|
hasCurrent() {
|
|
5663
5602
|
return this.#ctx.hasCurrent();
|
|
5664
5603
|
}
|
|
5604
|
+
resolveLoopback(invokeDirect, invokeEntry, caller) {
|
|
5605
|
+
const context = tryCurrentIoContext();
|
|
5606
|
+
if (context === this.#ctx) return invokeDirect();
|
|
5607
|
+
if (context !== void 0) return context.awaitIo(context.waitForOutputLocks().then(invokeEntry));
|
|
5608
|
+
if (caller === void 0) return invokeEntry();
|
|
5609
|
+
if (!caller.hasCurrent()) throw new Error("resolveLoopback() caller has no current input lock");
|
|
5610
|
+
if (caller === this) return invokeDirect();
|
|
5611
|
+
return caller.awaitIo(caller.waitOutputLocks().then(invokeEntry));
|
|
5612
|
+
}
|
|
5665
5613
|
/**
|
|
5666
5614
|
* ← `ActorContainer::start` (`server.c++:2854-2957`) as far as the class
|
|
5667
5615
|
* instance, plus decision 4's boot semantics.
|
|
@@ -5688,7 +5636,7 @@ var ActorContainerImpl = class {
|
|
|
5688
5636
|
throw exception;
|
|
5689
5637
|
}
|
|
5690
5638
|
}
|
|
5691
|
-
entry(target) {
|
|
5639
|
+
entry(target, signal) {
|
|
5692
5640
|
const bound = /* @__PURE__ */ new Map();
|
|
5693
5641
|
return new Proxy(target, { get: (subject, property) => {
|
|
5694
5642
|
const value = Reflect.get(subject, property, subject);
|
|
@@ -5697,7 +5645,7 @@ var ActorContainerImpl = class {
|
|
|
5697
5645
|
if (cached !== void 0) return cached;
|
|
5698
5646
|
const gated = async (...args) => {
|
|
5699
5647
|
this.#ctx.noteGateUse(`entry ${String(property)}()`, captureGateStack());
|
|
5700
|
-
const result = await this.#ctx.run(() => this.#withExternalEntry(() => value.apply(subject, args)));
|
|
5648
|
+
const result = await this.#ctx.run(() => this.#withExternalEntry(() => value.apply(subject, args)), { signal });
|
|
5701
5649
|
await this.#ctx.waitForOutputLocks();
|
|
5702
5650
|
return result;
|
|
5703
5651
|
};
|
|
@@ -5733,8 +5681,8 @@ var ActorContainerImpl = class {
|
|
|
5733
5681
|
return callback;
|
|
5734
5682
|
} });
|
|
5735
5683
|
}
|
|
5736
|
-
run(event) {
|
|
5737
|
-
return this.#ctx.run(() => this.#withExternalEntry(event));
|
|
5684
|
+
run(event, signal) {
|
|
5685
|
+
return this.#ctx.run(() => this.#withExternalEntry(event), { signal });
|
|
5738
5686
|
}
|
|
5739
5687
|
#withExternalEntry(body) {
|
|
5740
5688
|
const previous = this.#currentExternalEntry;
|
|
@@ -5756,7 +5704,7 @@ var ActorContainerImpl = class {
|
|
|
5756
5704
|
*
|
|
5757
5705
|
* "Alarms enter with no lock and no critical section, so an alarm queues behind
|
|
5758
5706
|
* any held lock and takes a fresh top-level lock" (§1.8) — which is exactly
|
|
5759
|
-
* `ctx.run(func)` with no
|
|
5707
|
+
* `ctx.run(func)` with no input option. The retry ladder and the watchdog are
|
|
5760
5708
|
* `server/alarm-scheduler.ts`'s; what is here is one delivery, and the
|
|
5761
5709
|
* serialization of one delivery against the next, which is the property
|
|
5762
5710
|
* `_cf_executingScheduleRowId` upstream depends on.
|
|
@@ -5934,6 +5882,6 @@ function newRpcSession(port, localMain) {
|
|
|
5934
5882
|
return newMessagePortRpcSession(port, localMain);
|
|
5935
5883
|
}
|
|
5936
5884
|
//#endregion
|
|
5937
|
-
export { ACTOR_CLASS_SERIALIZATION_UNIMPLEMENTED_MESSAGE, ALARM_RETRY_MAX_TRIES, ALARM_RETRY_START_SECONDS, ALLOW_EXPERIMENTAL_MESSAGE, ALREADY_ACCEPTED_MESSAGE, AlarmInvocationInfo, AlarmScheduler, BYOB_READER_UNGATABLE_MESSAGE, DEAD_LOAD_CONTEXT_MESSAGE, DEFAULT_ALARM_OUTLET, FACET_ALARM_UNIMPLEMENTED_MESSAGE, FACET_NAME_MAX_LENGTH, FACET_TREE_MAX_DEPTH, FOREIGN_SLICE_MESSAGE, HIBERNATION_UNIMPLEMENTED_MESSAGE, LoopbackDurableObjectClass, NOT_BYTES_MESSAGE, NO_GLOBAL_OUTBOUND_MESSAGE, NO_MODULES_MESSAGE, PITR_UNIMPLEMENTED_MESSAGE, REPLICATION_UNIMPLEMENTED_MESSAGE, RETRY_BACKOFF_MAX, RETRY_JITTER_FACTOR, STREAMING_TAILS_EXPERIMENTAL_MESSAGE, WorkerLoader, WorkerStub, actorScopeBindings, alarmRetryDelayMs, asLoopbackDurableObjectClass, createActorContainer, createDurableObjectNamespace, gateRequestBody, installActorScope, jsModuleInPythonWorkerMessage, moduleFieldCountMessage, moduleNameMessage, newRpcSession, noFacets, notSerializableMessage, pythonModuleInJsWorkerMessage, typeScriptModuleNameMessage };
|
|
5885
|
+
export { ACTOR_CLASS_SERIALIZATION_UNIMPLEMENTED_MESSAGE, ALARM_RETRY_MAX_TRIES, ALARM_RETRY_START_SECONDS, ALLOW_EXPERIMENTAL_MESSAGE, ALREADY_ACCEPTED_MESSAGE, AlarmInvocationInfo, AlarmScheduler, BYOB_READER_UNGATABLE_MESSAGE, BrokenActorError, CanceledError, DEAD_LOAD_CONTEXT_MESSAGE, DEFAULT_ALARM_OUTLET, FACET_ALARM_UNIMPLEMENTED_MESSAGE, FACET_NAME_MAX_LENGTH, FACET_TREE_MAX_DEPTH, FOREIGN_SLICE_MESSAGE, HIBERNATION_UNIMPLEMENTED_MESSAGE, LoopbackDurableObjectClass, NOT_BYTES_MESSAGE, NO_GLOBAL_OUTBOUND_MESSAGE, NO_MODULES_MESSAGE, PITR_UNIMPLEMENTED_MESSAGE, REPLICATION_UNIMPLEMENTED_MESSAGE, RETRY_BACKOFF_MAX, RETRY_JITTER_FACTOR, STREAMING_TAILS_EXPERIMENTAL_MESSAGE, WorkerLoader, WorkerStub, actorScopeBindings, alarmRetryDelayMs, asLoopbackDurableObjectClass, createActorContainer, createDurableObjectNamespace, gateRequestBody, installActorScope, jsModuleInPythonWorkerMessage, moduleFieldCountMessage, moduleNameMessage, newRpcSession, noFacets, notSerializableMessage, pythonModuleInJsWorkerMessage, typeScriptModuleNameMessage };
|
|
5938
5886
|
|
|
5939
5887
|
//# sourceMappingURL=index.js.map
|