@mcp-b/do-runtime 0.3.1 → 0.3.2

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 9b747e8: Prevent a transformed await waiting on one actor's input gate from blocking transformed continuations in other actors.
8
+
3
9
  ## 0.3.1
4
10
 
5
11
  ### Patch Changes
package/dist/gate.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { c as tryCurrentSlice } from "./chunks/io-context-D89n6HVM.js";
2
2
  //#region src/gate.ts
3
3
  var continuationContext;
4
- var publications = [];
5
4
  function isThenable(value) {
6
5
  return (typeof value === "object" && value !== null || typeof value === "function") && typeof Reflect.get(value, "then") === "function";
7
6
  }
@@ -12,19 +11,16 @@ function __gate(value) {
12
11
  if (context === void 0) return value;
13
12
  return resumeWithContext(context, Promise.resolve(value));
14
13
  }
15
- /**
16
- * Resolve one transformed await per task, inside a fresh actor slice. Starting
17
- * from a task with an empty microtask queue makes its continuation the only code
18
- * between publishing and clearing the actor identity. A shared queue prevents
19
- * two actors that settle together from overwriting each other's publication.
20
- */
21
- function enqueuePublication(publication) {
22
- publications.push(publication);
23
- if (publications.length === 1) schedulePublication();
24
- }
25
14
  function resumeWithContext(context, promise) {
26
15
  return new Promise((resolve, reject) => {
27
16
  const publish = context.makeTransformReentryCallback((outcome) => {
17
+ if (continuationContext !== void 0) {
18
+ schedulePublication({
19
+ publish: () => publish(outcome),
20
+ reject
21
+ });
22
+ return;
23
+ }
28
24
  const token = {};
29
25
  continuationContext = {
30
26
  context,
@@ -34,12 +30,10 @@ function resumeWithContext(context, promise) {
34
30
  else reject(outcome.exception);
35
31
  queueMicrotask(() => {
36
32
  if (continuationContext?.token === token) continuationContext = void 0;
37
- publications.shift();
38
- if (publications.length > 0) schedulePublication();
39
33
  });
40
34
  });
41
35
  promise.then((value) => {
42
- enqueuePublication({
36
+ schedulePublication({
43
37
  publish: () => publish({
44
38
  ok: true,
45
39
  value
@@ -47,7 +41,7 @@ function resumeWithContext(context, promise) {
47
41
  reject
48
42
  });
49
43
  }, (exception) => {
50
- enqueuePublication({
44
+ schedulePublication({
51
45
  publish: () => publish({
52
46
  ok: false,
53
47
  exception
@@ -57,17 +51,18 @@ function resumeWithContext(context, promise) {
57
51
  });
58
52
  });
59
53
  }
60
- function schedulePublication() {
54
+ /**
55
+ * Resolve one transformed await per task, inside a fresh actor slice. Admission
56
+ * attempts are independent so a blocked actor cannot stall the actor that will
57
+ * unblock it. The task boundary keeps each continuation ambient isolated.
58
+ */
59
+ function schedulePublication(publication) {
61
60
  const channel = new MessageChannel();
62
61
  channel.port1.onmessage = () => {
63
62
  channel.port1.close();
64
63
  channel.port2.close();
65
- const publication = publications[0];
66
- if (publication === void 0) return;
67
64
  publication.publish().catch((exception) => {
68
65
  publication.reject(exception);
69
- publications.shift();
70
- if (publications.length > 0) schedulePublication();
71
66
  });
72
67
  };
73
68
  channel.port2.postMessage(void 0);
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 { 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\n// ponytail: one module-wide queue; shard by actor only if settled-await contention is measured.\nconst publications: Publication[] = [];\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/**\n * Resolve one transformed await per task, inside a fresh actor slice. Starting\n * from a task with an empty microtask queue makes its continuation the only code\n * between publishing and clearing the actor identity. A shared queue prevents\n * two actors that settle together from overwriting each other's publication.\n */\nfunction enqueuePublication(publication: Publication): void {\n publications.push(publication);\n if (publications.length === 1) schedulePublication();\n}\n\nfunction resumeWithContext<T>(context: IoContext, promise: Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const publish = context.makeTransformReentryCallback((outcome: Outcome<T>) => {\n const token = {};\n continuationContext = { context, token };\n if (outcome.ok) resolve(outcome.value);\n else reject(outcome.exception);\n queueMicrotask(() => {\n if (continuationContext?.token === token) continuationContext = undefined;\n publications.shift();\n if (publications.length > 0) schedulePublication();\n });\n });\n void promise.then(\n (value) => {\n enqueuePublication({ publish: () => publish({ ok: true, value }), reject });\n },\n (exception: unknown) => {\n enqueuePublication({ publish: () => publish({ ok: false, exception }), reject });\n },\n );\n });\n}\n\nfunction schedulePublication(): void {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n channel.port1.close();\n channel.port2.close();\n const publication = publications[0];\n if (publication === undefined) return;\n\n void publication.publish().catch((exception: unknown) => {\n publication.reject(exception);\n publications.shift();\n if (publications.length > 0) schedulePublication();\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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"}
1
+ {"version":3,"file":"gate.js","names":[],"sources":["../src/gate.ts"],"sourcesContent":["/* @do-runtime-gated */\n\nimport { 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\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\nfunction resumeWithContext<T>(context: IoContext, promise: Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const publish = context.makeTransformReentryCallback((outcome: Outcome<T>) => {\n if (continuationContext !== undefined) {\n schedulePublication({ publish: () => publish(outcome), reject });\n return;\n }\n const token = {};\n continuationContext = { context, token };\n if (outcome.ok) resolve(outcome.value);\n else reject(outcome.exception);\n queueMicrotask(() => {\n if (continuationContext?.token === token) continuationContext = undefined;\n });\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\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-b/do-runtime",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Cloudflare's Durable Object runtime (workerd), ported to TypeScript: actors with input/output gates, SQLite storage, facets and alarms, running in the browser and in Node.",
5
5
  "keywords": [
6
6
  "actors",