@immediately-run/sdk 0.31.0 → 0.33.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.
Files changed (63) hide show
  1. package/dist/boot.d.cts +2 -2
  2. package/dist/boot.d.ts +2 -2
  3. package/dist/catalog.cjs +6 -3
  4. package/dist/catalog.cjs.map +1 -1
  5. package/dist/catalog.d.cts +3 -2
  6. package/dist/catalog.d.ts +3 -2
  7. package/dist/catalog.js +6 -3
  8. package/dist/catalog.js.map +1 -1
  9. package/dist/components/Include.d.cts +2 -3
  10. package/dist/components/Include.d.ts +2 -3
  11. package/dist/components/MainContent.d.cts +4 -4
  12. package/dist/components/MainContent.d.ts +4 -4
  13. package/dist/components/MountImage.d.cts +2 -2
  14. package/dist/components/MountImage.d.ts +2 -2
  15. package/dist/components/Routes.d.cts +2 -2
  16. package/dist/components/Routes.d.ts +2 -2
  17. package/dist/components/defaults.d.cts +2 -2
  18. package/dist/components/defaults.d.ts +2 -2
  19. package/dist/components/errors.d.cts +2 -2
  20. package/dist/components/errors.d.ts +2 -2
  21. package/dist/index.d.cts +1 -2
  22. package/dist/index.d.ts +1 -2
  23. package/dist/llm.cjs +6 -1
  24. package/dist/llm.cjs.map +1 -1
  25. package/dist/llm.d.cts +6 -0
  26. package/dist/llm.d.ts +6 -0
  27. package/dist/llm.js +6 -1
  28. package/dist/llm.js.map +1 -1
  29. package/dist/loading.d.cts +5 -5
  30. package/dist/loading.d.ts +5 -5
  31. package/dist/moduleCache.d.cts +1 -2
  32. package/dist/moduleCache.d.ts +1 -2
  33. package/dist/protocolStream.cjs +20 -4
  34. package/dist/protocolStream.cjs.map +1 -1
  35. package/dist/protocolStream.d.cts +15 -2
  36. package/dist/protocolStream.d.ts +15 -2
  37. package/dist/protocolStream.js +20 -4
  38. package/dist/protocolStream.js.map +1 -1
  39. package/dist/safeContent/SafeContent.cjs.map +1 -1
  40. package/dist/safeContent/SafeContent.js.map +1 -1
  41. package/dist/safeContent/index.cjs.map +1 -1
  42. package/dist/safeContent/index.d.cts +1 -1
  43. package/dist/safeContent/index.d.ts +1 -1
  44. package/dist/safeContent/index.js.map +1 -1
  45. package/dist/safeContent/mdastDeps.cjs +10697 -0
  46. package/dist/safeContent/mdastDeps.js +10680 -0
  47. package/dist/safeContent/parseSafeMdast.cjs +17 -15
  48. package/dist/safeContent/parseSafeMdast.cjs.map +1 -1
  49. package/dist/safeContent/parseSafeMdast.d.cts +16 -2
  50. package/dist/safeContent/parseSafeMdast.d.ts +16 -2
  51. package/dist/safeContent/parseSafeMdast.js +21 -15
  52. package/dist/safeContent/parseSafeMdast.js.map +1 -1
  53. package/dist/safeContent/renderMdast.cjs +5 -1
  54. package/dist/safeContent/renderMdast.cjs.map +1 -1
  55. package/dist/safeContent/renderMdast.js +5 -1
  56. package/dist/safeContent/renderMdast.js.map +1 -1
  57. package/dist/version.cjs +1 -1
  58. package/dist/version.cjs.map +1 -1
  59. package/dist/version.d.cts +1 -1
  60. package/dist/version.d.ts +1 -1
  61. package/dist/version.js +1 -1
  62. package/dist/version.js.map +1 -1
  63. package/package.json +9 -7
package/dist/loading.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode, CSSProperties } from 'react';
3
3
 
4
4
  /** Loading timing constants, matching the host (LOADING_UX_SPEC §3, the 2026-06-22
@@ -18,14 +18,14 @@ declare function SkeletonRow({ width, height, style, }: {
18
18
  width?: number | string;
19
19
  height?: number | string;
20
20
  style?: CSSProperties;
21
- }): react_jsx_runtime.JSX.Element;
21
+ }): react.JSX.Element;
22
22
  /** A shaped, in-app skeleton matching the host archetypes — for an app's own lazy
23
23
  * region (e.g. `<Suspense fallback={<Skeleton archetype="panel.list" />}>`).
24
24
  * Decorative (`aria-hidden`); pair it with `aria-busy` on the region it stands in. */
25
25
  declare function Skeleton({ archetype, style, }: {
26
26
  archetype?: SkeletonArchetype;
27
27
  style?: CSSProperties;
28
- }): react_jsx_runtime.JSX.Element;
28
+ }): react.JSX.Element;
29
29
  /** An indeterminate spinner for waits where a shaped skeleton doesn't fit (a pending
30
30
  * button, a small inline fetch). Wired to the host's ~150 ms-before-spin rule: it
31
31
  * renders nothing until the threshold, so a fast wait shows no flash. Reduced motion
@@ -34,7 +34,7 @@ declare function Spinner({ size, thresholdMs, label, }: {
34
34
  size?: number;
35
35
  thresholdMs?: number;
36
36
  label?: string;
37
- }): react_jsx_runtime.JSX.Element | null;
37
+ }): react.JSX.Element | null;
38
38
  /** Wrap an in-app region whose content is still loading: shows a centered spinner
39
39
  * (past the 150 ms floor) with `aria-busy`, then reveals `children`. For a shaped
40
40
  * wait, pass a `<Skeleton>` as `fallback` instead. App a11y only — not host chrome. */
@@ -43,6 +43,6 @@ declare function LoadingRegion({ loading, fallback, label, children, }: {
43
43
  fallback?: ReactNode;
44
44
  label?: string;
45
45
  children?: ReactNode;
46
- }): react_jsx_runtime.JSX.Element;
46
+ }): react.JSX.Element;
47
47
 
48
48
  export { LOADING_TIMINGS, LoadingRegion, Skeleton, type SkeletonArchetype, SkeletonRow, Spinner };
@@ -1,4 +1,3 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import * as react from 'react';
3
2
  import { ReactNode } from 'react';
4
3
  import { EvaluationContext } from './sandboxTypes.cjs';
@@ -15,6 +14,6 @@ declare const ModuleCacheContext: react.Context<ModuleCache | null>;
15
14
  declare const ModuleCacheContextProvider: ({ children, moduleCache }: {
16
15
  children: ReactNode;
17
16
  moduleCache: ModuleCache;
18
- }) => react_jsx_runtime.JSX.Element;
17
+ }) => react.JSX.Element;
19
18
 
20
19
  export { ModuleCache, ModuleCacheContext, ModuleCacheContextProvider };
@@ -1,4 +1,3 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import * as react from 'react';
3
2
  import { ReactNode } from 'react';
4
3
  import { EvaluationContext } from './sandboxTypes.js';
@@ -15,6 +14,6 @@ declare const ModuleCacheContext: react.Context<ModuleCache | null>;
15
14
  declare const ModuleCacheContextProvider: ({ children, moduleCache }: {
16
15
  children: ReactNode;
17
16
  moduleCache: ModuleCache;
18
- }) => react_jsx_runtime.JSX.Element;
17
+ }) => react.JSX.Element;
19
18
 
20
19
  export { ModuleCache, ModuleCacheContext, ModuleCacheContextProvider };
@@ -36,9 +36,11 @@ const nextMsgId = () => {
36
36
  streamCounter = (streamCounter + 1) % Number.MAX_SAFE_INTEGER;
37
37
  return streamCounter;
38
38
  };
39
- async function* consumeStream(transport, type, method, params, msgId = nextMsgId()) {
39
+ async function* consumeStream(transport, type, method, params, msgId = nextMsgId(), signal) {
40
40
  const queue = [];
41
41
  let wake = null;
42
+ let settled = false;
43
+ let started = false;
42
44
  const push = (frame) => {
43
45
  queue.push(frame);
44
46
  const w = wake;
@@ -49,9 +51,18 @@ async function* consumeStream(transport, type, method, params, msgId = nextMsgId
49
51
  if (msg.msgId !== msgId || !msg.stream) return;
50
52
  push(msg.stream);
51
53
  });
54
+ const onAbort = () => {
55
+ const w = wake;
56
+ wake = null;
57
+ w?.();
58
+ };
59
+ if (signal) signal.addEventListener("abort", onAbort);
52
60
  try {
61
+ if (signal?.aborted) throw new StreamError("aborted", "stream aborted before start");
53
62
  transport.send({ type, method, params, msgId, stream: true });
63
+ started = true;
54
64
  while (true) {
65
+ if (signal?.aborted) throw new StreamError("aborted", "stream aborted");
55
66
  if (queue.length === 0) {
56
67
  await new Promise((resolve) => {
57
68
  wake = resolve;
@@ -62,21 +73,26 @@ async function* consumeStream(transport, type, method, params, msgId = nextMsgId
62
73
  if (frame.kind === "event") {
63
74
  yield frame.value;
64
75
  } else if (frame.kind === "done") {
76
+ settled = true;
65
77
  return frame.value;
66
78
  } else {
79
+ settled = true;
67
80
  throw new StreamError(frame.code, frame.message);
68
81
  }
69
82
  }
70
83
  } finally {
71
84
  unsubscribe();
85
+ if (signal) signal.removeEventListener("abort", onAbort);
86
+ if (started && !settled) transport.cancel?.({ type, msgId, cancel: true });
72
87
  }
73
88
  }
74
89
  const bundlerTransport = {
75
90
  send: (msg) => (0, import_sandboxUtils.sendMessage)(msg.type, msg),
76
- subscribe: (type, handler) => (0, import_sandboxUtils.addListener)(type, (msg) => handler(msg))
91
+ subscribe: (type, handler) => (0, import_sandboxUtils.addListener)(type, (msg) => handler(msg)),
92
+ cancel: (msg) => (0, import_sandboxUtils.sendMessage)(msg.type, msg)
77
93
  };
78
- function protocolStream(protocolName, method, params) {
79
- return consumeStream(bundlerTransport, protocolName, method, params);
94
+ function protocolStream(protocolName, method, params, signal) {
95
+ return consumeStream(bundlerTransport, protocolName, method, params, void 0, signal);
80
96
  }
81
97
  // Annotate the CommonJS export names for ESM import in node:
82
98
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/protocolStream.ts"],"sourcesContent":["// SDK-side consumer for the host streaming transport (UI_AS_APPS_SPEC §5.1).\n//\n// The host `pumpGenerator` emits, per request msgId, a run of `stream.event`\n// frames terminated by one `stream.done` (with the return value) or `stream.error`\n// frame. This reassembles that run into an AsyncGenerator: each `event` is a\n// `yield`, the `done` value is the generator's `return`, an `error` is a `throw`.\n//\n// `consumeStream` takes an injected `StreamTransport` so it's unit-tested with a\n// fake send/subscribe — no bundler. `protocolStream`/`contribute` below wire it to\n// the real sandbox messageBus via sandboxUtils.\nimport { addListener, sendMessage } from './sandboxUtils';\n\n/** One frame of a host stream: an `event` value, the terminal `done` value, or an `error`. */\nexport type StreamFrame =\n | { kind: 'event'; value: unknown }\n | { kind: 'done'; value: unknown }\n | { kind: 'error'; code: string; message: string };\n\n/** The send/subscribe transport {@link consumeStream} drives (injected so it can be faked in tests). */\nexport interface StreamTransport {\n // Fire the request that starts the stream. The host replies with frames tagged\n // by the same `msgId`.\n send: (msg: { type: string; method: string; params: unknown[]; msgId: number; stream: true }) => void;\n // Subscribe to inbound frames for `type`; returns an unsubscribe.\n subscribe: (\n type: string,\n handler: (msg: { msgId?: number; stream?: StreamFrame }) => void\n ) => () => void;\n}\n\n/** Thrown when a stream ends in an `error` frame; carries the host's `code`. */\nexport class StreamError extends Error {\n code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = 'StreamError';\n this.code = code;\n }\n}\n\nlet streamCounter = 0;\nconst nextMsgId = (): number => {\n // Distinct from the bundler's own protocolRequest counter space is unnecessary —\n // frames are filtered by (type, msgId, stream) so a collision with a one-shot\n // reply (which has `result`, not `stream`) can't be misread.\n streamCounter = (streamCounter + 1) % Number.MAX_SAFE_INTEGER;\n return streamCounter;\n};\n\n/**\n * Drive one streamed request to completion over an injected transport.\n *\n * Yields each event value; returns the `done` value; throws `StreamError` on an\n * error frame. Always unsubscribes (via the generator's `finally`) so an early\n * `break` in the consumer doesn't leak the listener.\n */\nexport async function* consumeStream<T = unknown, R = unknown>(\n transport: StreamTransport,\n type: string,\n method: string,\n params: unknown[],\n msgId: number = nextMsgId()\n): AsyncGenerator<T, R, void> {\n const queue: StreamFrame[] = [];\n let wake: (() => void) | null = null;\n const push = (frame: StreamFrame) => {\n queue.push(frame);\n const w = wake;\n wake = null;\n w?.();\n };\n\n const unsubscribe = transport.subscribe(type, (msg) => {\n if (msg.msgId !== msgId || !msg.stream) return;\n push(msg.stream);\n });\n\n try {\n transport.send({ type, method, params, msgId, stream: true });\n while (true) {\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n continue;\n }\n const frame = queue.shift() as StreamFrame;\n if (frame.kind === 'event') {\n yield frame.value as T;\n } else if (frame.kind === 'done') {\n return frame.value as R;\n } else {\n throw new StreamError(frame.code, frame.message);\n }\n }\n } finally {\n unsubscribe();\n }\n}\n\n// The real sandbox transport, built from the bundler messageBus helpers.\nconst bundlerTransport: StreamTransport = {\n send: (msg) => sendMessage(msg.type, msg as unknown as Record<string, unknown>),\n subscribe: (type, handler) =>\n addListener(type, (msg) => handler(msg as { msgId?: number; stream?: StreamFrame })),\n};\n\n/**\n * Consume an elevated streaming protocol method from app code.\n *\n * `for await (const ev of protocolStream('protocol-contribute', 'run', [opts])) …`\n */\nexport function protocolStream<T = unknown, R = unknown>(\n protocolName: string,\n method: string,\n params: unknown[]\n): AsyncGenerator<T, R, void> {\n return consumeStream<T, R>(bundlerTransport, protocolName, method, params);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,0BAAyC;AAqBlC,MAAM,oBAAoB,MAAM;AAAA,EAErC,YAAY,MAAc,SAAiB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAI,gBAAgB;AACpB,MAAM,YAAY,MAAc;AAI9B,mBAAiB,gBAAgB,KAAK,OAAO;AAC7C,SAAO;AACT;AASA,gBAAuB,cACrB,WACA,MACA,QACA,QACA,QAAgB,UAAU,GACE;AAC5B,QAAM,QAAuB,CAAC;AAC9B,MAAI,OAA4B;AAChC,QAAM,OAAO,CAAC,UAAuB;AACnC,UAAM,KAAK,KAAK;AAChB,UAAM,IAAI;AACV,WAAO;AACP,QAAI;AAAA,EACN;AAEA,QAAM,cAAc,UAAU,UAAU,MAAM,CAAC,QAAQ;AACrD,QAAI,IAAI,UAAU,SAAS,CAAC,IAAI,OAAQ;AACxC,SAAK,IAAI,MAAM;AAAA,EACjB,CAAC;AAED,MAAI;AACF,cAAU,KAAK,EAAE,MAAM,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAC5D,WAAO,MAAM;AACX,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,IAAI,QAAc,CAAC,YAAY;AACnC,iBAAO;AAAA,QACT,CAAC;AACD;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,MAAM;AAC1B,UAAI,MAAM,SAAS,SAAS;AAC1B,cAAM,MAAM;AAAA,MACd,WAAW,MAAM,SAAS,QAAQ;AAChC,eAAO,MAAM;AAAA,MACf,OAAO;AACL,cAAM,IAAI,YAAY,MAAM,MAAM,MAAM,OAAO;AAAA,MACjD;AAAA,IACF;AAAA,EACF,UAAE;AACA,gBAAY;AAAA,EACd;AACF;AAGA,MAAM,mBAAoC;AAAA,EACxC,MAAM,CAAC,YAAQ,iCAAY,IAAI,MAAM,GAAyC;AAAA,EAC9E,WAAW,CAAC,MAAM,gBAChB,iCAAY,MAAM,CAAC,QAAQ,QAAQ,GAA+C,CAAC;AACvF;AAOO,SAAS,eACd,cACA,QACA,QAC4B;AAC5B,SAAO,cAAoB,kBAAkB,cAAc,QAAQ,MAAM;AAC3E;","names":[]}
1
+ {"version":3,"sources":["../src/protocolStream.ts"],"sourcesContent":["// SDK-side consumer for the host streaming transport (UI_AS_APPS_SPEC §5.1).\n//\n// The host `pumpGenerator` emits, per request msgId, a run of `stream.event`\n// frames terminated by one `stream.done` (with the return value) or `stream.error`\n// frame. This reassembles that run into an AsyncGenerator: each `event` is a\n// `yield`, the `done` value is the generator's `return`, an `error` is a `throw`.\n//\n// `consumeStream` takes an injected `StreamTransport` so it's unit-tested with a\n// fake send/subscribe — no bundler. `protocolStream`/`contribute` below wire it to\n// the real sandbox messageBus via sandboxUtils.\nimport { addListener, sendMessage } from './sandboxUtils';\n\n/** One frame of a host stream: an `event` value, the terminal `done` value, or an `error`. */\nexport type StreamFrame =\n | { kind: 'event'; value: unknown }\n | { kind: 'done'; value: unknown }\n | { kind: 'error'; code: string; message: string };\n\n/** The send/subscribe transport {@link consumeStream} drives (injected so it can be faked in tests). */\nexport interface StreamTransport {\n // Fire the request that starts the stream. The host replies with frames tagged\n // by the same `msgId`.\n send: (msg: { type: string; method: string; params: unknown[]; msgId: number; stream: true }) => void;\n // Subscribe to inbound frames for `type`; returns an unsubscribe.\n subscribe: (\n type: string,\n handler: (msg: { msgId?: number; stream?: StreamFrame }) => void\n ) => () => void;\n // Tell the host to STOP the stream early — abort the in-flight generation (and,\n // for `llm:chat`, the upstream provider fetch so it stops BILLING). Sent when the\n // consumer bails before a terminal frame: an early `break`/`return` out of the\n // `for await`, or an `AbortSignal` firing. Carries the same `(type, msgId)` the\n // host tagged its frames with, so the host aborts the matching generator\n // (LLM_AND_AGENTS_SPEC §3.3 \"abort the in-flight LLM request\"). Optional — a\n // transport predating the cancel frame simply omits it and the old behavior\n // (host runs to completion) stands.\n cancel?: (msg: { type: string; msgId: number; cancel: true }) => void;\n}\n\n/** Thrown when a stream ends in an `error` frame; carries the host's `code`. */\nexport class StreamError extends Error {\n code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = 'StreamError';\n this.code = code;\n }\n}\n\nlet streamCounter = 0;\nconst nextMsgId = (): number => {\n // Distinct from the bundler's own protocolRequest counter space is unnecessary —\n // frames are filtered by (type, msgId, stream) so a collision with a one-shot\n // reply (which has `result`, not `stream`) can't be misread.\n streamCounter = (streamCounter + 1) % Number.MAX_SAFE_INTEGER;\n return streamCounter;\n};\n\n/**\n * Drive one streamed request to completion over an injected transport.\n *\n * Yields each event value; returns the `done` value; throws `StreamError` on an\n * error frame. Always unsubscribes (via the generator's `finally`) so an early\n * `break` in the consumer doesn't leak the listener.\n *\n * `signal` wires a caller {@link AbortSignal} to mid-stream cancellation: when it\n * fires (or the consumer `break`s before a terminal frame), the `finally` sends a\n * `cancel` frame back over `transport.cancel` so the HOST stops generating — without\n * it, aborting only stops the app-side iterator while the upstream provider keeps\n * streaming and BILLING (LLM_AND_AGENTS_SPEC §3.3, R3-224 / adversarial F2).\n */\nexport async function* consumeStream<T = unknown, R = unknown>(\n transport: StreamTransport,\n type: string,\n method: string,\n params: unknown[],\n msgId: number = nextMsgId(),\n signal?: AbortSignal\n): AsyncGenerator<T, R, void> {\n const queue: StreamFrame[] = [];\n let wake: (() => void) | null = null;\n // True once a terminal (`done`/`error`) frame arrived — so the `finally` knows the\n // host already stopped and must NOT send a redundant cancel. Left false when the\n // consumer bails early or the signal aborts (the two cases that DO need a cancel).\n let settled = false;\n // True once the request frame went out. A cancel is only meaningful for a stream\n // the host actually started — an abort BEFORE `send` sends nothing to cancel.\n let started = false;\n const push = (frame: StreamFrame) => {\n queue.push(frame);\n const w = wake;\n wake = null;\n w?.();\n };\n\n const unsubscribe = transport.subscribe(type, (msg) => {\n if (msg.msgId !== msgId || !msg.stream) return;\n push(msg.stream);\n });\n\n // An abort wakes the pull loop out of its idle `await`; the loop then throws.\n const onAbort = () => {\n const w = wake;\n wake = null;\n w?.();\n };\n if (signal) signal.addEventListener('abort', onAbort);\n\n try {\n if (signal?.aborted) throw new StreamError('aborted', 'stream aborted before start');\n transport.send({ type, method, params, msgId, stream: true });\n started = true;\n while (true) {\n if (signal?.aborted) throw new StreamError('aborted', 'stream aborted');\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n continue;\n }\n const frame = queue.shift() as StreamFrame;\n if (frame.kind === 'event') {\n yield frame.value as T;\n } else if (frame.kind === 'done') {\n settled = true;\n return frame.value as R;\n } else {\n settled = true;\n throw new StreamError(frame.code, frame.message);\n }\n }\n } finally {\n unsubscribe();\n if (signal) signal.removeEventListener('abort', onAbort);\n // Consumer stopped pulling before a terminal frame (early break/return, or the\n // signal aborted): tell the host to stop the in-flight generation + billing.\n if (started && !settled) transport.cancel?.({ type, msgId, cancel: true });\n }\n}\n\n// The real sandbox transport, built from the bundler messageBus helpers. `cancel`\n// rides the same messageBus as `send` — a `{type, msgId, cancel:true}` frame the\n// host dispatcher routes to the in-flight generator's AbortController.\nconst bundlerTransport: StreamTransport = {\n send: (msg) => sendMessage(msg.type, msg as unknown as Record<string, unknown>),\n subscribe: (type, handler) =>\n addListener(type, (msg) => handler(msg as { msgId?: number; stream?: StreamFrame })),\n cancel: (msg) => sendMessage(msg.type, msg as unknown as Record<string, unknown>),\n};\n\n/**\n * Consume an elevated streaming protocol method from app code.\n *\n * `for await (const ev of protocolStream('protocol-contribute', 'run', [opts])) …`\n *\n * Pass `signal` to abort the stream (and the host's in-flight work) mid-flight.\n */\nexport function protocolStream<T = unknown, R = unknown>(\n protocolName: string,\n method: string,\n params: unknown[],\n signal?: AbortSignal\n): AsyncGenerator<T, R, void> {\n return consumeStream<T, R>(bundlerTransport, protocolName, method, params, undefined, signal);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,0BAAyC;AA8BlC,MAAM,oBAAoB,MAAM;AAAA,EAErC,YAAY,MAAc,SAAiB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAI,gBAAgB;AACpB,MAAM,YAAY,MAAc;AAI9B,mBAAiB,gBAAgB,KAAK,OAAO;AAC7C,SAAO;AACT;AAeA,gBAAuB,cACrB,WACA,MACA,QACA,QACA,QAAgB,UAAU,GAC1B,QAC4B;AAC5B,QAAM,QAAuB,CAAC;AAC9B,MAAI,OAA4B;AAIhC,MAAI,UAAU;AAGd,MAAI,UAAU;AACd,QAAM,OAAO,CAAC,UAAuB;AACnC,UAAM,KAAK,KAAK;AAChB,UAAM,IAAI;AACV,WAAO;AACP,QAAI;AAAA,EACN;AAEA,QAAM,cAAc,UAAU,UAAU,MAAM,CAAC,QAAQ;AACrD,QAAI,IAAI,UAAU,SAAS,CAAC,IAAI,OAAQ;AACxC,SAAK,IAAI,MAAM;AAAA,EACjB,CAAC;AAGD,QAAM,UAAU,MAAM;AACpB,UAAM,IAAI;AACV,WAAO;AACP,QAAI;AAAA,EACN;AACA,MAAI,OAAQ,QAAO,iBAAiB,SAAS,OAAO;AAEpD,MAAI;AACF,QAAI,QAAQ,QAAS,OAAM,IAAI,YAAY,WAAW,6BAA6B;AACnF,cAAU,KAAK,EAAE,MAAM,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAC5D,cAAU;AACV,WAAO,MAAM;AACX,UAAI,QAAQ,QAAS,OAAM,IAAI,YAAY,WAAW,gBAAgB;AACtE,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,IAAI,QAAc,CAAC,YAAY;AACnC,iBAAO;AAAA,QACT,CAAC;AACD;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,MAAM;AAC1B,UAAI,MAAM,SAAS,SAAS;AAC1B,cAAM,MAAM;AAAA,MACd,WAAW,MAAM,SAAS,QAAQ;AAChC,kBAAU;AACV,eAAO,MAAM;AAAA,MACf,OAAO;AACL,kBAAU;AACV,cAAM,IAAI,YAAY,MAAM,MAAM,MAAM,OAAO;AAAA,MACjD;AAAA,IACF;AAAA,EACF,UAAE;AACA,gBAAY;AACZ,QAAI,OAAQ,QAAO,oBAAoB,SAAS,OAAO;AAGvD,QAAI,WAAW,CAAC,QAAS,WAAU,SAAS,EAAE,MAAM,OAAO,QAAQ,KAAK,CAAC;AAAA,EAC3E;AACF;AAKA,MAAM,mBAAoC;AAAA,EACxC,MAAM,CAAC,YAAQ,iCAAY,IAAI,MAAM,GAAyC;AAAA,EAC9E,WAAW,CAAC,MAAM,gBAChB,iCAAY,MAAM,CAAC,QAAQ,QAAQ,GAA+C,CAAC;AAAA,EACrF,QAAQ,CAAC,YAAQ,iCAAY,IAAI,MAAM,GAAyC;AAClF;AASO,SAAS,eACd,cACA,QACA,QACA,QAC4B;AAC5B,SAAO,cAAoB,kBAAkB,cAAc,QAAQ,QAAQ,QAAW,MAAM;AAC9F;","names":[]}
@@ -23,6 +23,11 @@ interface StreamTransport {
23
23
  msgId?: number;
24
24
  stream?: StreamFrame;
25
25
  }) => void) => () => void;
26
+ cancel?: (msg: {
27
+ type: string;
28
+ msgId: number;
29
+ cancel: true;
30
+ }) => void;
26
31
  }
27
32
  /** Thrown when a stream ends in an `error` frame; carries the host's `code`. */
28
33
  declare class StreamError extends Error {
@@ -35,13 +40,21 @@ declare class StreamError extends Error {
35
40
  * Yields each event value; returns the `done` value; throws `StreamError` on an
36
41
  * error frame. Always unsubscribes (via the generator's `finally`) so an early
37
42
  * `break` in the consumer doesn't leak the listener.
43
+ *
44
+ * `signal` wires a caller {@link AbortSignal} to mid-stream cancellation: when it
45
+ * fires (or the consumer `break`s before a terminal frame), the `finally` sends a
46
+ * `cancel` frame back over `transport.cancel` so the HOST stops generating — without
47
+ * it, aborting only stops the app-side iterator while the upstream provider keeps
48
+ * streaming and BILLING (LLM_AND_AGENTS_SPEC §3.3, R3-224 / adversarial F2).
38
49
  */
39
- declare function consumeStream<T = unknown, R = unknown>(transport: StreamTransport, type: string, method: string, params: unknown[], msgId?: number): AsyncGenerator<T, R, void>;
50
+ declare function consumeStream<T = unknown, R = unknown>(transport: StreamTransport, type: string, method: string, params: unknown[], msgId?: number, signal?: AbortSignal): AsyncGenerator<T, R, void>;
40
51
  /**
41
52
  * Consume an elevated streaming protocol method from app code.
42
53
  *
43
54
  * `for await (const ev of protocolStream('protocol-contribute', 'run', [opts])) …`
55
+ *
56
+ * Pass `signal` to abort the stream (and the host's in-flight work) mid-flight.
44
57
  */
45
- declare function protocolStream<T = unknown, R = unknown>(protocolName: string, method: string, params: unknown[]): AsyncGenerator<T, R, void>;
58
+ declare function protocolStream<T = unknown, R = unknown>(protocolName: string, method: string, params: unknown[], signal?: AbortSignal): AsyncGenerator<T, R, void>;
46
59
 
47
60
  export { StreamError, type StreamFrame, type StreamTransport, consumeStream, protocolStream };
@@ -23,6 +23,11 @@ interface StreamTransport {
23
23
  msgId?: number;
24
24
  stream?: StreamFrame;
25
25
  }) => void) => () => void;
26
+ cancel?: (msg: {
27
+ type: string;
28
+ msgId: number;
29
+ cancel: true;
30
+ }) => void;
26
31
  }
27
32
  /** Thrown when a stream ends in an `error` frame; carries the host's `code`. */
28
33
  declare class StreamError extends Error {
@@ -35,13 +40,21 @@ declare class StreamError extends Error {
35
40
  * Yields each event value; returns the `done` value; throws `StreamError` on an
36
41
  * error frame. Always unsubscribes (via the generator's `finally`) so an early
37
42
  * `break` in the consumer doesn't leak the listener.
43
+ *
44
+ * `signal` wires a caller {@link AbortSignal} to mid-stream cancellation: when it
45
+ * fires (or the consumer `break`s before a terminal frame), the `finally` sends a
46
+ * `cancel` frame back over `transport.cancel` so the HOST stops generating — without
47
+ * it, aborting only stops the app-side iterator while the upstream provider keeps
48
+ * streaming and BILLING (LLM_AND_AGENTS_SPEC §3.3, R3-224 / adversarial F2).
38
49
  */
39
- declare function consumeStream<T = unknown, R = unknown>(transport: StreamTransport, type: string, method: string, params: unknown[], msgId?: number): AsyncGenerator<T, R, void>;
50
+ declare function consumeStream<T = unknown, R = unknown>(transport: StreamTransport, type: string, method: string, params: unknown[], msgId?: number, signal?: AbortSignal): AsyncGenerator<T, R, void>;
40
51
  /**
41
52
  * Consume an elevated streaming protocol method from app code.
42
53
  *
43
54
  * `for await (const ev of protocolStream('protocol-contribute', 'run', [opts])) …`
55
+ *
56
+ * Pass `signal` to abort the stream (and the host's in-flight work) mid-flight.
44
57
  */
45
- declare function protocolStream<T = unknown, R = unknown>(protocolName: string, method: string, params: unknown[]): AsyncGenerator<T, R, void>;
58
+ declare function protocolStream<T = unknown, R = unknown>(protocolName: string, method: string, params: unknown[], signal?: AbortSignal): AsyncGenerator<T, R, void>;
46
59
 
47
60
  export { StreamError, type StreamFrame, type StreamTransport, consumeStream, protocolStream };
@@ -11,9 +11,11 @@ const nextMsgId = () => {
11
11
  streamCounter = (streamCounter + 1) % Number.MAX_SAFE_INTEGER;
12
12
  return streamCounter;
13
13
  };
14
- async function* consumeStream(transport, type, method, params, msgId = nextMsgId()) {
14
+ async function* consumeStream(transport, type, method, params, msgId = nextMsgId(), signal) {
15
15
  const queue = [];
16
16
  let wake = null;
17
+ let settled = false;
18
+ let started = false;
17
19
  const push = (frame) => {
18
20
  queue.push(frame);
19
21
  const w = wake;
@@ -24,9 +26,18 @@ async function* consumeStream(transport, type, method, params, msgId = nextMsgId
24
26
  if (msg.msgId !== msgId || !msg.stream) return;
25
27
  push(msg.stream);
26
28
  });
29
+ const onAbort = () => {
30
+ const w = wake;
31
+ wake = null;
32
+ w?.();
33
+ };
34
+ if (signal) signal.addEventListener("abort", onAbort);
27
35
  try {
36
+ if (signal?.aborted) throw new StreamError("aborted", "stream aborted before start");
28
37
  transport.send({ type, method, params, msgId, stream: true });
38
+ started = true;
29
39
  while (true) {
40
+ if (signal?.aborted) throw new StreamError("aborted", "stream aborted");
30
41
  if (queue.length === 0) {
31
42
  await new Promise((resolve) => {
32
43
  wake = resolve;
@@ -37,21 +48,26 @@ async function* consumeStream(transport, type, method, params, msgId = nextMsgId
37
48
  if (frame.kind === "event") {
38
49
  yield frame.value;
39
50
  } else if (frame.kind === "done") {
51
+ settled = true;
40
52
  return frame.value;
41
53
  } else {
54
+ settled = true;
42
55
  throw new StreamError(frame.code, frame.message);
43
56
  }
44
57
  }
45
58
  } finally {
46
59
  unsubscribe();
60
+ if (signal) signal.removeEventListener("abort", onAbort);
61
+ if (started && !settled) transport.cancel?.({ type, msgId, cancel: true });
47
62
  }
48
63
  }
49
64
  const bundlerTransport = {
50
65
  send: (msg) => sendMessage(msg.type, msg),
51
- subscribe: (type, handler) => addListener(type, (msg) => handler(msg))
66
+ subscribe: (type, handler) => addListener(type, (msg) => handler(msg)),
67
+ cancel: (msg) => sendMessage(msg.type, msg)
52
68
  };
53
- function protocolStream(protocolName, method, params) {
54
- return consumeStream(bundlerTransport, protocolName, method, params);
69
+ function protocolStream(protocolName, method, params, signal) {
70
+ return consumeStream(bundlerTransport, protocolName, method, params, void 0, signal);
55
71
  }
56
72
  export {
57
73
  StreamError,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/protocolStream.ts"],"sourcesContent":["// SDK-side consumer for the host streaming transport (UI_AS_APPS_SPEC §5.1).\n//\n// The host `pumpGenerator` emits, per request msgId, a run of `stream.event`\n// frames terminated by one `stream.done` (with the return value) or `stream.error`\n// frame. This reassembles that run into an AsyncGenerator: each `event` is a\n// `yield`, the `done` value is the generator's `return`, an `error` is a `throw`.\n//\n// `consumeStream` takes an injected `StreamTransport` so it's unit-tested with a\n// fake send/subscribe — no bundler. `protocolStream`/`contribute` below wire it to\n// the real sandbox messageBus via sandboxUtils.\nimport { addListener, sendMessage } from './sandboxUtils';\n\n/** One frame of a host stream: an `event` value, the terminal `done` value, or an `error`. */\nexport type StreamFrame =\n | { kind: 'event'; value: unknown }\n | { kind: 'done'; value: unknown }\n | { kind: 'error'; code: string; message: string };\n\n/** The send/subscribe transport {@link consumeStream} drives (injected so it can be faked in tests). */\nexport interface StreamTransport {\n // Fire the request that starts the stream. The host replies with frames tagged\n // by the same `msgId`.\n send: (msg: { type: string; method: string; params: unknown[]; msgId: number; stream: true }) => void;\n // Subscribe to inbound frames for `type`; returns an unsubscribe.\n subscribe: (\n type: string,\n handler: (msg: { msgId?: number; stream?: StreamFrame }) => void\n ) => () => void;\n}\n\n/** Thrown when a stream ends in an `error` frame; carries the host's `code`. */\nexport class StreamError extends Error {\n code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = 'StreamError';\n this.code = code;\n }\n}\n\nlet streamCounter = 0;\nconst nextMsgId = (): number => {\n // Distinct from the bundler's own protocolRequest counter space is unnecessary —\n // frames are filtered by (type, msgId, stream) so a collision with a one-shot\n // reply (which has `result`, not `stream`) can't be misread.\n streamCounter = (streamCounter + 1) % Number.MAX_SAFE_INTEGER;\n return streamCounter;\n};\n\n/**\n * Drive one streamed request to completion over an injected transport.\n *\n * Yields each event value; returns the `done` value; throws `StreamError` on an\n * error frame. Always unsubscribes (via the generator's `finally`) so an early\n * `break` in the consumer doesn't leak the listener.\n */\nexport async function* consumeStream<T = unknown, R = unknown>(\n transport: StreamTransport,\n type: string,\n method: string,\n params: unknown[],\n msgId: number = nextMsgId()\n): AsyncGenerator<T, R, void> {\n const queue: StreamFrame[] = [];\n let wake: (() => void) | null = null;\n const push = (frame: StreamFrame) => {\n queue.push(frame);\n const w = wake;\n wake = null;\n w?.();\n };\n\n const unsubscribe = transport.subscribe(type, (msg) => {\n if (msg.msgId !== msgId || !msg.stream) return;\n push(msg.stream);\n });\n\n try {\n transport.send({ type, method, params, msgId, stream: true });\n while (true) {\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n continue;\n }\n const frame = queue.shift() as StreamFrame;\n if (frame.kind === 'event') {\n yield frame.value as T;\n } else if (frame.kind === 'done') {\n return frame.value as R;\n } else {\n throw new StreamError(frame.code, frame.message);\n }\n }\n } finally {\n unsubscribe();\n }\n}\n\n// The real sandbox transport, built from the bundler messageBus helpers.\nconst bundlerTransport: StreamTransport = {\n send: (msg) => sendMessage(msg.type, msg as unknown as Record<string, unknown>),\n subscribe: (type, handler) =>\n addListener(type, (msg) => handler(msg as { msgId?: number; stream?: StreamFrame })),\n};\n\n/**\n * Consume an elevated streaming protocol method from app code.\n *\n * `for await (const ev of protocolStream('protocol-contribute', 'run', [opts])) …`\n */\nexport function protocolStream<T = unknown, R = unknown>(\n protocolName: string,\n method: string,\n params: unknown[]\n): AsyncGenerator<T, R, void> {\n return consumeStream<T, R>(bundlerTransport, protocolName, method, params);\n}\n"],"mappings":"AAUA,SAAS,aAAa,mBAAmB;AAqBlC,MAAM,oBAAoB,MAAM;AAAA,EAErC,YAAY,MAAc,SAAiB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAI,gBAAgB;AACpB,MAAM,YAAY,MAAc;AAI9B,mBAAiB,gBAAgB,KAAK,OAAO;AAC7C,SAAO;AACT;AASA,gBAAuB,cACrB,WACA,MACA,QACA,QACA,QAAgB,UAAU,GACE;AAC5B,QAAM,QAAuB,CAAC;AAC9B,MAAI,OAA4B;AAChC,QAAM,OAAO,CAAC,UAAuB;AACnC,UAAM,KAAK,KAAK;AAChB,UAAM,IAAI;AACV,WAAO;AACP,QAAI;AAAA,EACN;AAEA,QAAM,cAAc,UAAU,UAAU,MAAM,CAAC,QAAQ;AACrD,QAAI,IAAI,UAAU,SAAS,CAAC,IAAI,OAAQ;AACxC,SAAK,IAAI,MAAM;AAAA,EACjB,CAAC;AAED,MAAI;AACF,cAAU,KAAK,EAAE,MAAM,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAC5D,WAAO,MAAM;AACX,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,IAAI,QAAc,CAAC,YAAY;AACnC,iBAAO;AAAA,QACT,CAAC;AACD;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,MAAM;AAC1B,UAAI,MAAM,SAAS,SAAS;AAC1B,cAAM,MAAM;AAAA,MACd,WAAW,MAAM,SAAS,QAAQ;AAChC,eAAO,MAAM;AAAA,MACf,OAAO;AACL,cAAM,IAAI,YAAY,MAAM,MAAM,MAAM,OAAO;AAAA,MACjD;AAAA,IACF;AAAA,EACF,UAAE;AACA,gBAAY;AAAA,EACd;AACF;AAGA,MAAM,mBAAoC;AAAA,EACxC,MAAM,CAAC,QAAQ,YAAY,IAAI,MAAM,GAAyC;AAAA,EAC9E,WAAW,CAAC,MAAM,YAChB,YAAY,MAAM,CAAC,QAAQ,QAAQ,GAA+C,CAAC;AACvF;AAOO,SAAS,eACd,cACA,QACA,QAC4B;AAC5B,SAAO,cAAoB,kBAAkB,cAAc,QAAQ,MAAM;AAC3E;","names":[]}
1
+ {"version":3,"sources":["../src/protocolStream.ts"],"sourcesContent":["// SDK-side consumer for the host streaming transport (UI_AS_APPS_SPEC §5.1).\n//\n// The host `pumpGenerator` emits, per request msgId, a run of `stream.event`\n// frames terminated by one `stream.done` (with the return value) or `stream.error`\n// frame. This reassembles that run into an AsyncGenerator: each `event` is a\n// `yield`, the `done` value is the generator's `return`, an `error` is a `throw`.\n//\n// `consumeStream` takes an injected `StreamTransport` so it's unit-tested with a\n// fake send/subscribe — no bundler. `protocolStream`/`contribute` below wire it to\n// the real sandbox messageBus via sandboxUtils.\nimport { addListener, sendMessage } from './sandboxUtils';\n\n/** One frame of a host stream: an `event` value, the terminal `done` value, or an `error`. */\nexport type StreamFrame =\n | { kind: 'event'; value: unknown }\n | { kind: 'done'; value: unknown }\n | { kind: 'error'; code: string; message: string };\n\n/** The send/subscribe transport {@link consumeStream} drives (injected so it can be faked in tests). */\nexport interface StreamTransport {\n // Fire the request that starts the stream. The host replies with frames tagged\n // by the same `msgId`.\n send: (msg: { type: string; method: string; params: unknown[]; msgId: number; stream: true }) => void;\n // Subscribe to inbound frames for `type`; returns an unsubscribe.\n subscribe: (\n type: string,\n handler: (msg: { msgId?: number; stream?: StreamFrame }) => void\n ) => () => void;\n // Tell the host to STOP the stream early — abort the in-flight generation (and,\n // for `llm:chat`, the upstream provider fetch so it stops BILLING). Sent when the\n // consumer bails before a terminal frame: an early `break`/`return` out of the\n // `for await`, or an `AbortSignal` firing. Carries the same `(type, msgId)` the\n // host tagged its frames with, so the host aborts the matching generator\n // (LLM_AND_AGENTS_SPEC §3.3 \"abort the in-flight LLM request\"). Optional — a\n // transport predating the cancel frame simply omits it and the old behavior\n // (host runs to completion) stands.\n cancel?: (msg: { type: string; msgId: number; cancel: true }) => void;\n}\n\n/** Thrown when a stream ends in an `error` frame; carries the host's `code`. */\nexport class StreamError extends Error {\n code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = 'StreamError';\n this.code = code;\n }\n}\n\nlet streamCounter = 0;\nconst nextMsgId = (): number => {\n // Distinct from the bundler's own protocolRequest counter space is unnecessary —\n // frames are filtered by (type, msgId, stream) so a collision with a one-shot\n // reply (which has `result`, not `stream`) can't be misread.\n streamCounter = (streamCounter + 1) % Number.MAX_SAFE_INTEGER;\n return streamCounter;\n};\n\n/**\n * Drive one streamed request to completion over an injected transport.\n *\n * Yields each event value; returns the `done` value; throws `StreamError` on an\n * error frame. Always unsubscribes (via the generator's `finally`) so an early\n * `break` in the consumer doesn't leak the listener.\n *\n * `signal` wires a caller {@link AbortSignal} to mid-stream cancellation: when it\n * fires (or the consumer `break`s before a terminal frame), the `finally` sends a\n * `cancel` frame back over `transport.cancel` so the HOST stops generating — without\n * it, aborting only stops the app-side iterator while the upstream provider keeps\n * streaming and BILLING (LLM_AND_AGENTS_SPEC §3.3, R3-224 / adversarial F2).\n */\nexport async function* consumeStream<T = unknown, R = unknown>(\n transport: StreamTransport,\n type: string,\n method: string,\n params: unknown[],\n msgId: number = nextMsgId(),\n signal?: AbortSignal\n): AsyncGenerator<T, R, void> {\n const queue: StreamFrame[] = [];\n let wake: (() => void) | null = null;\n // True once a terminal (`done`/`error`) frame arrived — so the `finally` knows the\n // host already stopped and must NOT send a redundant cancel. Left false when the\n // consumer bails early or the signal aborts (the two cases that DO need a cancel).\n let settled = false;\n // True once the request frame went out. A cancel is only meaningful for a stream\n // the host actually started — an abort BEFORE `send` sends nothing to cancel.\n let started = false;\n const push = (frame: StreamFrame) => {\n queue.push(frame);\n const w = wake;\n wake = null;\n w?.();\n };\n\n const unsubscribe = transport.subscribe(type, (msg) => {\n if (msg.msgId !== msgId || !msg.stream) return;\n push(msg.stream);\n });\n\n // An abort wakes the pull loop out of its idle `await`; the loop then throws.\n const onAbort = () => {\n const w = wake;\n wake = null;\n w?.();\n };\n if (signal) signal.addEventListener('abort', onAbort);\n\n try {\n if (signal?.aborted) throw new StreamError('aborted', 'stream aborted before start');\n transport.send({ type, method, params, msgId, stream: true });\n started = true;\n while (true) {\n if (signal?.aborted) throw new StreamError('aborted', 'stream aborted');\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n continue;\n }\n const frame = queue.shift() as StreamFrame;\n if (frame.kind === 'event') {\n yield frame.value as T;\n } else if (frame.kind === 'done') {\n settled = true;\n return frame.value as R;\n } else {\n settled = true;\n throw new StreamError(frame.code, frame.message);\n }\n }\n } finally {\n unsubscribe();\n if (signal) signal.removeEventListener('abort', onAbort);\n // Consumer stopped pulling before a terminal frame (early break/return, or the\n // signal aborted): tell the host to stop the in-flight generation + billing.\n if (started && !settled) transport.cancel?.({ type, msgId, cancel: true });\n }\n}\n\n// The real sandbox transport, built from the bundler messageBus helpers. `cancel`\n// rides the same messageBus as `send` — a `{type, msgId, cancel:true}` frame the\n// host dispatcher routes to the in-flight generator's AbortController.\nconst bundlerTransport: StreamTransport = {\n send: (msg) => sendMessage(msg.type, msg as unknown as Record<string, unknown>),\n subscribe: (type, handler) =>\n addListener(type, (msg) => handler(msg as { msgId?: number; stream?: StreamFrame })),\n cancel: (msg) => sendMessage(msg.type, msg as unknown as Record<string, unknown>),\n};\n\n/**\n * Consume an elevated streaming protocol method from app code.\n *\n * `for await (const ev of protocolStream('protocol-contribute', 'run', [opts])) …`\n *\n * Pass `signal` to abort the stream (and the host's in-flight work) mid-flight.\n */\nexport function protocolStream<T = unknown, R = unknown>(\n protocolName: string,\n method: string,\n params: unknown[],\n signal?: AbortSignal\n): AsyncGenerator<T, R, void> {\n return consumeStream<T, R>(bundlerTransport, protocolName, method, params, undefined, signal);\n}\n"],"mappings":"AAUA,SAAS,aAAa,mBAAmB;AA8BlC,MAAM,oBAAoB,MAAM;AAAA,EAErC,YAAY,MAAc,SAAiB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAI,gBAAgB;AACpB,MAAM,YAAY,MAAc;AAI9B,mBAAiB,gBAAgB,KAAK,OAAO;AAC7C,SAAO;AACT;AAeA,gBAAuB,cACrB,WACA,MACA,QACA,QACA,QAAgB,UAAU,GAC1B,QAC4B;AAC5B,QAAM,QAAuB,CAAC;AAC9B,MAAI,OAA4B;AAIhC,MAAI,UAAU;AAGd,MAAI,UAAU;AACd,QAAM,OAAO,CAAC,UAAuB;AACnC,UAAM,KAAK,KAAK;AAChB,UAAM,IAAI;AACV,WAAO;AACP,QAAI;AAAA,EACN;AAEA,QAAM,cAAc,UAAU,UAAU,MAAM,CAAC,QAAQ;AACrD,QAAI,IAAI,UAAU,SAAS,CAAC,IAAI,OAAQ;AACxC,SAAK,IAAI,MAAM;AAAA,EACjB,CAAC;AAGD,QAAM,UAAU,MAAM;AACpB,UAAM,IAAI;AACV,WAAO;AACP,QAAI;AAAA,EACN;AACA,MAAI,OAAQ,QAAO,iBAAiB,SAAS,OAAO;AAEpD,MAAI;AACF,QAAI,QAAQ,QAAS,OAAM,IAAI,YAAY,WAAW,6BAA6B;AACnF,cAAU,KAAK,EAAE,MAAM,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAC5D,cAAU;AACV,WAAO,MAAM;AACX,UAAI,QAAQ,QAAS,OAAM,IAAI,YAAY,WAAW,gBAAgB;AACtE,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,IAAI,QAAc,CAAC,YAAY;AACnC,iBAAO;AAAA,QACT,CAAC;AACD;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,MAAM;AAC1B,UAAI,MAAM,SAAS,SAAS;AAC1B,cAAM,MAAM;AAAA,MACd,WAAW,MAAM,SAAS,QAAQ;AAChC,kBAAU;AACV,eAAO,MAAM;AAAA,MACf,OAAO;AACL,kBAAU;AACV,cAAM,IAAI,YAAY,MAAM,MAAM,MAAM,OAAO;AAAA,MACjD;AAAA,IACF;AAAA,EACF,UAAE;AACA,gBAAY;AACZ,QAAI,OAAQ,QAAO,oBAAoB,SAAS,OAAO;AAGvD,QAAI,WAAW,CAAC,QAAS,WAAU,SAAS,EAAE,MAAM,OAAO,QAAQ,KAAK,CAAC;AAAA,EAC3E;AACF;AAKA,MAAM,mBAAoC;AAAA,EACxC,MAAM,CAAC,QAAQ,YAAY,IAAI,MAAM,GAAyC;AAAA,EAC9E,WAAW,CAAC,MAAM,YAChB,YAAY,MAAM,CAAC,QAAQ,QAAQ,GAA+C,CAAC;AAAA,EACrF,QAAQ,CAAC,QAAQ,YAAY,IAAI,MAAM,GAAyC;AAClF;AASO,SAAS,eACd,cACA,QACA,QACA,QAC4B;AAC5B,SAAO,cAAoB,kBAAkB,cAAc,QAAQ,QAAQ,QAAW,MAAM;AAC9F;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/safeContent/SafeContent.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { parseSafeMdast } from './parseSafeMdast';\nimport { renderMdast, type RenderMdastOptions } from './renderMdast';\n\n// `<SafeContent>` — the host/SDK-owned safe renderer (TRUST_MODES_SPEC §5.1,\n// AGENT_AUTHORING §10). An interpreter app renders untrusted Markdown/MDX-syntax\n// content — a shared board's body, a multi-writer wiki entry — through THIS component\n// so **no author JavaScript ever executes** while `<Component/>` syntax still reaches\n// the app's own safe components. It is the mandatory terminal for the MDX-from-mount\n// gate: a shared board is a multi-writer (M3) source, and compiled/executable MDX\n// would run board-author code with the app's authority (the WHITEBOARD §8 blast\n// radius this gate bounds).\n//\n// The parse (no-acorn, ESM-only deps) is async, so this renders a small placeholder\n// until the tree is ready, then the pure synchronous `renderMdast`. Parsing is keyed\n// on the source string; a changed source re-parses, and a stale async result is\n// discarded (the ref guard) so a fast source swap can't paint the wrong content.\n\nexport interface SafeContentProps extends RenderMdastOptions {\n /** The untrusted Markdown/MDX-syntax source to render as data. */\n source: string;\n /** Rendered while the async parse is in flight (default: nothing). */\n fallback?: ReactNode;\n}\n\nexport function SafeContent({ source, fallback = null, ...options }: SafeContentProps): ReactNode {\n const [tree, setTree] = useState<Awaited<ReturnType<typeof parseSafeMdast>> | null>(null);\n const runId = useRef(0);\n\n useEffect(() => {\n const id = ++runId.current;\n setTree(null);\n let cancelled = false;\n parseSafeMdast(source)\n .then((parsed) => {\n // Discard a stale result (source changed / unmounted) so we never paint the\n // wrong tree — the render-as-data guarantee also needs the RIGHT data shown.\n if (!cancelled && runId.current === id) setTree(parsed);\n })\n .catch(() => {\n if (!cancelled && runId.current === id) setTree(null);\n });\n return () => {\n cancelled = true;\n };\n }, [source]);\n\n // `renderMdast` is pure; memoise on the tree + the option identities the caller\n // passes. (Callers should memoise `components`/`resolveWikiLink` themselves for a\n // stable identity; changing them re-renders, which is correct.)\n const rendered = useMemo(\n () => (tree ? renderMdast(tree, options) : null),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tree, options.components, options.resolveWikiLink],\n );\n\n return tree ? rendered : fallback;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqE;AACrE,4BAA+B;AAC/B,yBAAqD;AAuB9C,SAAS,YAAY,EAAE,QAAQ,WAAW,MAAM,GAAG,QAAQ,GAAgC;AAChG,QAAM,CAAC,MAAM,OAAO,QAAI,uBAA4D,IAAI;AACxF,QAAM,YAAQ,qBAAO,CAAC;AAEtB,8BAAU,MAAM;AACd,UAAM,KAAK,EAAE,MAAM;AACnB,YAAQ,IAAI;AACZ,QAAI,YAAY;AAChB,8CAAe,MAAM,EAClB,KAAK,CAAC,WAAW;AAGhB,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,MAAM;AAAA,IACxD,CAAC,EACA,MAAM,MAAM;AACX,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,IAAI;AAAA,IACtD,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAKX,QAAM,eAAW;AAAA,IACf,MAAO,WAAO,gCAAY,MAAM,OAAO,IAAI;AAAA;AAAA,IAE3C,CAAC,MAAM,QAAQ,YAAY,QAAQ,eAAe;AAAA,EACpD;AAEA,SAAO,OAAO,WAAW;AAC3B;","names":[]}
1
+ {"version":3,"sources":["../../src/safeContent/SafeContent.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { parseSafeMdast } from './parseSafeMdast';\nimport { renderMdast, type RenderMdastOptions } from './renderMdast';\n\n// R3-213 — sharing the component map: `parseSafeMdast` runs the SAME kernel remark\n// plugins the compiled path uses, so it emits `<Admonition>` / `<WikiLink>` /\n// `<HeadingAnchor>` element nodes. To render them identically to the compiled path (and\n// so pick up the R3-212 fragment resolver + scroll), an interpreter app passes the SAME\n// `DEFAULT_MDX_COMPONENTS` it hands `boot({ mdxComponents })` as this component's\n// `components` — that shared map IS the uniformity (no forked second component set). We\n// deliberately do NOT import DEFAULT_MDX_COMPONENTS here: the safe renderer is a lean,\n// dep-light security primitive (render-as-data, no evaluator, ESM-clean for the e2e\n// bundle), and must not pull the full component library into its module graph.\n\n// `<SafeContent>` — the host/SDK-owned safe renderer (TRUST_MODES_SPEC §5.1,\n// AGENT_AUTHORING §10). An interpreter app renders untrusted Markdown/MDX-syntax\n// content — a shared board's body, a multi-writer wiki entry — through THIS component\n// so **no author JavaScript ever executes** while `<Component/>` syntax still reaches\n// the app's own safe components. It is the mandatory terminal for the MDX-from-mount\n// gate: a shared board is a multi-writer (M3) source, and compiled/executable MDX\n// would run board-author code with the app's authority (the WHITEBOARD §8 blast\n// radius this gate bounds).\n//\n// The parse (no-acorn, ESM-only deps) is async, so this renders a small placeholder\n// until the tree is ready, then the pure synchronous `renderMdast`. Parsing is keyed\n// on the source string; a changed source re-parses, and a stale async result is\n// discarded (the ref guard) so a fast source swap can't paint the wrong content.\n\nexport interface SafeContentProps extends RenderMdastOptions {\n /** The untrusted Markdown/MDX-syntax source to render as data. */\n source: string;\n /** Rendered while the async parse is in flight (default: nothing). */\n fallback?: ReactNode;\n}\n\nexport function SafeContent({ source, fallback = null, ...options }: SafeContentProps): ReactNode {\n const [tree, setTree] = useState<Awaited<ReturnType<typeof parseSafeMdast>> | null>(null);\n const runId = useRef(0);\n\n useEffect(() => {\n const id = ++runId.current;\n setTree(null);\n let cancelled = false;\n parseSafeMdast(source)\n .then((parsed) => {\n // Discard a stale result (source changed / unmounted) so we never paint the\n // wrong tree — the render-as-data guarantee also needs the RIGHT data shown.\n if (!cancelled && runId.current === id) setTree(parsed);\n })\n .catch(() => {\n if (!cancelled && runId.current === id) setTree(null);\n });\n return () => {\n cancelled = true;\n };\n }, [source]);\n\n // `renderMdast` is pure; memoise on the tree + the option identities the caller\n // passes. (Callers should memoise `components`/`resolveWikiLink` themselves for a\n // stable identity; changing them re-renders, which is correct.)\n const rendered = useMemo(\n () => (tree ? renderMdast(tree, options) : null),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tree, options.components, options.resolveWikiLink],\n );\n\n return tree ? rendered : fallback;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqE;AACrE,4BAA+B;AAC/B,yBAAqD;AAiC9C,SAAS,YAAY,EAAE,QAAQ,WAAW,MAAM,GAAG,QAAQ,GAAgC;AAChG,QAAM,CAAC,MAAM,OAAO,QAAI,uBAA4D,IAAI;AACxF,QAAM,YAAQ,qBAAO,CAAC;AAEtB,8BAAU,MAAM;AACd,UAAM,KAAK,EAAE,MAAM;AACnB,YAAQ,IAAI;AACZ,QAAI,YAAY;AAChB,8CAAe,MAAM,EAClB,KAAK,CAAC,WAAW;AAGhB,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,MAAM;AAAA,IACxD,CAAC,EACA,MAAM,MAAM;AACX,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,IAAI;AAAA,IACtD,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAKX,QAAM,eAAW;AAAA,IACf,MAAO,WAAO,gCAAY,MAAM,OAAO,IAAI;AAAA;AAAA,IAE3C,CAAC,MAAM,QAAQ,YAAY,QAAQ,eAAe;AAAA,EACpD;AAEA,SAAO,OAAO,WAAW;AAC3B;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/safeContent/SafeContent.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { parseSafeMdast } from './parseSafeMdast';\nimport { renderMdast, type RenderMdastOptions } from './renderMdast';\n\n// `<SafeContent>` — the host/SDK-owned safe renderer (TRUST_MODES_SPEC §5.1,\n// AGENT_AUTHORING §10). An interpreter app renders untrusted Markdown/MDX-syntax\n// content — a shared board's body, a multi-writer wiki entry — through THIS component\n// so **no author JavaScript ever executes** while `<Component/>` syntax still reaches\n// the app's own safe components. It is the mandatory terminal for the MDX-from-mount\n// gate: a shared board is a multi-writer (M3) source, and compiled/executable MDX\n// would run board-author code with the app's authority (the WHITEBOARD §8 blast\n// radius this gate bounds).\n//\n// The parse (no-acorn, ESM-only deps) is async, so this renders a small placeholder\n// until the tree is ready, then the pure synchronous `renderMdast`. Parsing is keyed\n// on the source string; a changed source re-parses, and a stale async result is\n// discarded (the ref guard) so a fast source swap can't paint the wrong content.\n\nexport interface SafeContentProps extends RenderMdastOptions {\n /** The untrusted Markdown/MDX-syntax source to render as data. */\n source: string;\n /** Rendered while the async parse is in flight (default: nothing). */\n fallback?: ReactNode;\n}\n\nexport function SafeContent({ source, fallback = null, ...options }: SafeContentProps): ReactNode {\n const [tree, setTree] = useState<Awaited<ReturnType<typeof parseSafeMdast>> | null>(null);\n const runId = useRef(0);\n\n useEffect(() => {\n const id = ++runId.current;\n setTree(null);\n let cancelled = false;\n parseSafeMdast(source)\n .then((parsed) => {\n // Discard a stale result (source changed / unmounted) so we never paint the\n // wrong tree — the render-as-data guarantee also needs the RIGHT data shown.\n if (!cancelled && runId.current === id) setTree(parsed);\n })\n .catch(() => {\n if (!cancelled && runId.current === id) setTree(null);\n });\n return () => {\n cancelled = true;\n };\n }, [source]);\n\n // `renderMdast` is pure; memoise on the tree + the option identities the caller\n // passes. (Callers should memoise `components`/`resolveWikiLink` themselves for a\n // stable identity; changing them re-renders, which is correct.)\n const rendered = useMemo(\n () => (tree ? renderMdast(tree, options) : null),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tree, options.components, options.resolveWikiLink],\n );\n\n return tree ? rendered : fallback;\n}\n"],"mappings":"AAAA,SAAS,WAAW,SAAS,QAAQ,gBAAgC;AACrE,SAAS,sBAAsB;AAC/B,SAAS,mBAA4C;AAuB9C,SAAS,YAAY,EAAE,QAAQ,WAAW,MAAM,GAAG,QAAQ,GAAgC;AAChG,QAAM,CAAC,MAAM,OAAO,IAAI,SAA4D,IAAI;AACxF,QAAM,QAAQ,OAAO,CAAC;AAEtB,YAAU,MAAM;AACd,UAAM,KAAK,EAAE,MAAM;AACnB,YAAQ,IAAI;AACZ,QAAI,YAAY;AAChB,mBAAe,MAAM,EAClB,KAAK,CAAC,WAAW;AAGhB,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,MAAM;AAAA,IACxD,CAAC,EACA,MAAM,MAAM;AACX,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,IAAI;AAAA,IACtD,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAKX,QAAM,WAAW;AAAA,IACf,MAAO,OAAO,YAAY,MAAM,OAAO,IAAI;AAAA;AAAA,IAE3C,CAAC,MAAM,QAAQ,YAAY,QAAQ,eAAe;AAAA,EACpD;AAEA,SAAO,OAAO,WAAW;AAC3B;","names":[]}
1
+ {"version":3,"sources":["../../src/safeContent/SafeContent.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { parseSafeMdast } from './parseSafeMdast';\nimport { renderMdast, type RenderMdastOptions } from './renderMdast';\n\n// R3-213 — sharing the component map: `parseSafeMdast` runs the SAME kernel remark\n// plugins the compiled path uses, so it emits `<Admonition>` / `<WikiLink>` /\n// `<HeadingAnchor>` element nodes. To render them identically to the compiled path (and\n// so pick up the R3-212 fragment resolver + scroll), an interpreter app passes the SAME\n// `DEFAULT_MDX_COMPONENTS` it hands `boot({ mdxComponents })` as this component's\n// `components` — that shared map IS the uniformity (no forked second component set). We\n// deliberately do NOT import DEFAULT_MDX_COMPONENTS here: the safe renderer is a lean,\n// dep-light security primitive (render-as-data, no evaluator, ESM-clean for the e2e\n// bundle), and must not pull the full component library into its module graph.\n\n// `<SafeContent>` — the host/SDK-owned safe renderer (TRUST_MODES_SPEC §5.1,\n// AGENT_AUTHORING §10). An interpreter app renders untrusted Markdown/MDX-syntax\n// content — a shared board's body, a multi-writer wiki entry — through THIS component\n// so **no author JavaScript ever executes** while `<Component/>` syntax still reaches\n// the app's own safe components. It is the mandatory terminal for the MDX-from-mount\n// gate: a shared board is a multi-writer (M3) source, and compiled/executable MDX\n// would run board-author code with the app's authority (the WHITEBOARD §8 blast\n// radius this gate bounds).\n//\n// The parse (no-acorn, ESM-only deps) is async, so this renders a small placeholder\n// until the tree is ready, then the pure synchronous `renderMdast`. Parsing is keyed\n// on the source string; a changed source re-parses, and a stale async result is\n// discarded (the ref guard) so a fast source swap can't paint the wrong content.\n\nexport interface SafeContentProps extends RenderMdastOptions {\n /** The untrusted Markdown/MDX-syntax source to render as data. */\n source: string;\n /** Rendered while the async parse is in flight (default: nothing). */\n fallback?: ReactNode;\n}\n\nexport function SafeContent({ source, fallback = null, ...options }: SafeContentProps): ReactNode {\n const [tree, setTree] = useState<Awaited<ReturnType<typeof parseSafeMdast>> | null>(null);\n const runId = useRef(0);\n\n useEffect(() => {\n const id = ++runId.current;\n setTree(null);\n let cancelled = false;\n parseSafeMdast(source)\n .then((parsed) => {\n // Discard a stale result (source changed / unmounted) so we never paint the\n // wrong tree — the render-as-data guarantee also needs the RIGHT data shown.\n if (!cancelled && runId.current === id) setTree(parsed);\n })\n .catch(() => {\n if (!cancelled && runId.current === id) setTree(null);\n });\n return () => {\n cancelled = true;\n };\n }, [source]);\n\n // `renderMdast` is pure; memoise on the tree + the option identities the caller\n // passes. (Callers should memoise `components`/`resolveWikiLink` themselves for a\n // stable identity; changing them re-renders, which is correct.)\n const rendered = useMemo(\n () => (tree ? renderMdast(tree, options) : null),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tree, options.components, options.resolveWikiLink],\n );\n\n return tree ? rendered : fallback;\n}\n"],"mappings":"AAAA,SAAS,WAAW,SAAS,QAAQ,gBAAgC;AACrE,SAAS,sBAAsB;AAC/B,SAAS,mBAA4C;AAiC9C,SAAS,YAAY,EAAE,QAAQ,WAAW,MAAM,GAAG,QAAQ,GAAgC;AAChG,QAAM,CAAC,MAAM,OAAO,IAAI,SAA4D,IAAI;AACxF,QAAM,QAAQ,OAAO,CAAC;AAEtB,YAAU,MAAM;AACd,UAAM,KAAK,EAAE,MAAM;AACnB,YAAQ,IAAI;AACZ,QAAI,YAAY;AAChB,mBAAe,MAAM,EAClB,KAAK,CAAC,WAAW;AAGhB,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,MAAM;AAAA,IACxD,CAAC,EACA,MAAM,MAAM;AACX,UAAI,CAAC,aAAa,MAAM,YAAY,GAAI,SAAQ,IAAI;AAAA,IACtD,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAKX,QAAM,WAAW;AAAA,IACf,MAAO,OAAO,YAAY,MAAM,OAAO,IAAI;AAAA;AAAA,IAE3C,CAAC,MAAM,QAAQ,YAAY,QAAQ,eAAe;AAAA,EACpD;AAEA,SAAO,OAAO,WAAW;AAC3B;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/safeContent/index.ts"],"sourcesContent":["// Safe content rendering — non-executable MDX (TRUST_MODES_SPEC §5.1, AGENT_AUTHORING\n// §10). The host/SDK-owned renderer an INTERPRETER app uses to render untrusted\n// Markdown/MDX-syntax content as data, with **no evaluator anywhere in the pipeline**.\n// This is the mandatory terminal for the MDX-from-mount gate (§10 delta 1) — a shared\n// (multi-writer / M3) board or wiki entry MUST render through here, never compiled MDX.\n//\n// It is a **T2 tool, not a platform gate**: it stops content executing as code; it does\n// not certify anything to the host, and CO-4 data-fencing is still required for anything\n// that *reads* the content (the agent case).\n\nexport { SafeContent } from './SafeContent';\nexport type { SafeContentProps } from './SafeContent';\nexport { renderMdast } from './renderMdast';\nexport type {\n RenderMdastOptions,\n SafeContentComponents,\n} from './renderMdast';\nexport { parseSafeMdast } from './parseSafeMdast';\nexport type { SafeMdastNode, SafeMdxAttribute } from './parseSafeMdast';\nexport { sanitizeUrl } from './sanitizeUrl';\nexport { splitWikiLinks, parseWikiInner } from './wikilink';\nexport type { WikiLinkToken, WikiPart } from './wikilink';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,yBAA4B;AAE5B,yBAA4B;AAK5B,4BAA+B;AAE/B,yBAA4B;AAC5B,sBAA+C;","names":[]}
1
+ {"version":3,"sources":["../../src/safeContent/index.ts"],"sourcesContent":["// Safe content rendering — non-executable MDX (TRUST_MODES_SPEC §5.1, AGENT_AUTHORING\n// §10). The host/SDK-owned renderer an INTERPRETER app uses to render untrusted\n// Markdown/MDX-syntax content as data, with **no evaluator anywhere in the pipeline**.\n// This is the mandatory terminal for the MDX-from-mount gate (§10 delta 1) — a shared\n// (multi-writer / M3) board or wiki entry MUST render through here, never compiled MDX.\n//\n// It is a **T2 tool, not a platform gate**: it stops content executing as code; it does\n// not certify anything to the host, and CO-4 data-fencing is still required for anything\n// that *reads* the content (the agent case).\n\nexport { SafeContent } from './SafeContent';\nexport type { SafeContentProps } from './SafeContent';\nexport { renderMdast } from './renderMdast';\nexport type {\n RenderMdastOptions,\n SafeContentComponents,\n} from './renderMdast';\nexport { parseSafeMdast } from './parseSafeMdast';\nexport type { SafeMdastNode, SafeMdxAttribute, ParseSafeMdastOptions } from './parseSafeMdast';\nexport { sanitizeUrl } from './sanitizeUrl';\nexport { splitWikiLinks, parseWikiInner } from './wikilink';\nexport type { WikiLinkToken, WikiPart } from './wikilink';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,yBAA4B;AAE5B,yBAA4B;AAK5B,4BAA+B;AAE/B,yBAA4B;AAC5B,sBAA+C;","names":[]}
@@ -1,6 +1,6 @@
1
1
  export { SafeContent, SafeContentProps } from './SafeContent.cjs';
2
2
  export { RenderMdastOptions, SafeContentComponents, renderMdast } from './renderMdast.cjs';
3
- export { SafeMdastNode, SafeMdxAttribute, parseSafeMdast } from './parseSafeMdast.cjs';
3
+ export { ParseSafeMdastOptions, SafeMdastNode, SafeMdxAttribute, parseSafeMdast } from './parseSafeMdast.cjs';
4
4
  export { sanitizeUrl } from './sanitizeUrl.cjs';
5
5
  export { WikiLinkToken, WikiPart, parseWikiInner, splitWikiLinks } from './wikilink.cjs';
6
6
  import 'react';
@@ -1,6 +1,6 @@
1
1
  export { SafeContent, SafeContentProps } from './SafeContent.js';
2
2
  export { RenderMdastOptions, SafeContentComponents, renderMdast } from './renderMdast.js';
3
- export { SafeMdastNode, SafeMdxAttribute, parseSafeMdast } from './parseSafeMdast.js';
3
+ export { ParseSafeMdastOptions, SafeMdastNode, SafeMdxAttribute, parseSafeMdast } from './parseSafeMdast.js';
4
4
  export { sanitizeUrl } from './sanitizeUrl.js';
5
5
  export { WikiLinkToken, WikiPart, parseWikiInner, splitWikiLinks } from './wikilink.js';
6
6
  import 'react';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/safeContent/index.ts"],"sourcesContent":["// Safe content rendering — non-executable MDX (TRUST_MODES_SPEC §5.1, AGENT_AUTHORING\n// §10). The host/SDK-owned renderer an INTERPRETER app uses to render untrusted\n// Markdown/MDX-syntax content as data, with **no evaluator anywhere in the pipeline**.\n// This is the mandatory terminal for the MDX-from-mount gate (§10 delta 1) — a shared\n// (multi-writer / M3) board or wiki entry MUST render through here, never compiled MDX.\n//\n// It is a **T2 tool, not a platform gate**: it stops content executing as code; it does\n// not certify anything to the host, and CO-4 data-fencing is still required for anything\n// that *reads* the content (the agent case).\n\nexport { SafeContent } from './SafeContent';\nexport type { SafeContentProps } from './SafeContent';\nexport { renderMdast } from './renderMdast';\nexport type {\n RenderMdastOptions,\n SafeContentComponents,\n} from './renderMdast';\nexport { parseSafeMdast } from './parseSafeMdast';\nexport type { SafeMdastNode, SafeMdxAttribute } from './parseSafeMdast';\nexport { sanitizeUrl } from './sanitizeUrl';\nexport { splitWikiLinks, parseWikiInner } from './wikilink';\nexport type { WikiLinkToken, WikiPart } from './wikilink';\n"],"mappings":"AAUA,SAAS,mBAAmB;AAE5B,SAAS,mBAAmB;AAK5B,SAAS,sBAAsB;AAE/B,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB,sBAAsB;","names":[]}
1
+ {"version":3,"sources":["../../src/safeContent/index.ts"],"sourcesContent":["// Safe content rendering — non-executable MDX (TRUST_MODES_SPEC §5.1, AGENT_AUTHORING\n// §10). The host/SDK-owned renderer an INTERPRETER app uses to render untrusted\n// Markdown/MDX-syntax content as data, with **no evaluator anywhere in the pipeline**.\n// This is the mandatory terminal for the MDX-from-mount gate (§10 delta 1) — a shared\n// (multi-writer / M3) board or wiki entry MUST render through here, never compiled MDX.\n//\n// It is a **T2 tool, not a platform gate**: it stops content executing as code; it does\n// not certify anything to the host, and CO-4 data-fencing is still required for anything\n// that *reads* the content (the agent case).\n\nexport { SafeContent } from './SafeContent';\nexport type { SafeContentProps } from './SafeContent';\nexport { renderMdast } from './renderMdast';\nexport type {\n RenderMdastOptions,\n SafeContentComponents,\n} from './renderMdast';\nexport { parseSafeMdast } from './parseSafeMdast';\nexport type { SafeMdastNode, SafeMdxAttribute, ParseSafeMdastOptions } from './parseSafeMdast';\nexport { sanitizeUrl } from './sanitizeUrl';\nexport { splitWikiLinks, parseWikiInner } from './wikilink';\nexport type { WikiLinkToken, WikiPart } from './wikilink';\n"],"mappings":"AAUA,SAAS,mBAAmB;AAE5B,SAAS,mBAAmB;AAK5B,SAAS,sBAAsB;AAE/B,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB,sBAAsB;","names":[]}