@immediately-run/sdk 0.45.3 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hostAttention.cjs +57 -0
- package/dist/hostAttention.cjs.map +1 -0
- package/dist/hostAttention.d.cts +39 -0
- package/dist/hostAttention.d.ts +39 -0
- package/dist/hostAttention.js +31 -0
- package/dist/hostAttention.js.map +1 -0
- package/dist/hostTransport.cjs +55 -0
- package/dist/hostTransport.cjs.map +1 -0
- package/dist/hostTransport.d.cts +12 -0
- package/dist/hostTransport.d.ts +12 -0
- package/dist/hostTransport.js +30 -0
- package/dist/hostTransport.js.map +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/linkSpace.cjs +11 -2
- package/dist/linkSpace.cjs.map +1 -1
- package/dist/linkSpace.d.cts +23 -0
- package/dist/linkSpace.d.ts +23 -0
- package/dist/linkSpace.js +11 -2
- package/dist/linkSpace.js.map +1 -1
- package/dist/llm.cjs +18 -3
- package/dist/llm.cjs.map +1 -1
- package/dist/llm.d.cts +38 -3
- package/dist/llm.d.ts +38 -3
- package/dist/llm.js +14 -2
- package/dist/llm.js.map +1 -1
- package/dist/protocolDeadline.cjs +205 -0
- package/dist/protocolDeadline.cjs.map +1 -0
- package/dist/protocolDeadline.d.cts +146 -0
- package/dist/protocolDeadline.d.ts +146 -0
- package/dist/protocolDeadline.js +168 -0
- package/dist/protocolDeadline.js.map +1 -0
- package/dist/protocolStream.cjs +60 -6
- package/dist/protocolStream.cjs.map +1 -1
- package/dist/protocolStream.d.cts +9 -2
- package/dist/protocolStream.d.ts +9 -2
- package/dist/protocolStream.js +67 -6
- package/dist/protocolStream.js.map +1 -1
- package/dist/pushChannel.cjs +13 -9
- package/dist/pushChannel.cjs.map +1 -1
- package/dist/pushChannel.js +12 -8
- package/dist/pushChannel.js.map +1 -1
- package/dist/sandboxUtils.cjs +74 -24
- package/dist/sandboxUtils.cjs.map +1 -1
- package/dist/sandboxUtils.d.cts +37 -4
- package/dist/sandboxUtils.d.ts +37 -4
- package/dist/sandboxUtils.js +79 -22
- package/dist/sandboxUtils.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var hostAttention_exports = {};
|
|
20
|
+
__export(hostAttention_exports, {
|
|
21
|
+
NO_HOST_ATTENTION: () => NO_HOST_ATTENTION,
|
|
22
|
+
getHostAttention: () => getHostAttention,
|
|
23
|
+
onHostAttentionChange: () => onHostAttentionChange,
|
|
24
|
+
useHostAttention: () => useHostAttention
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(hostAttention_exports);
|
|
27
|
+
var import_pushChannel = require("./pushChannel");
|
|
28
|
+
var import_protocol = require("./generated/protocol");
|
|
29
|
+
const NO_HOST_ATTENTION = { awaiting: false, kind: null, since: null };
|
|
30
|
+
const KINDS = /* @__PURE__ */ new Set(["passkey", "consent", "picker", "confirmation"]);
|
|
31
|
+
const parseHostAttention = (value) => {
|
|
32
|
+
const a = value;
|
|
33
|
+
if (!a || typeof a !== "object" || typeof a.awaiting !== "boolean") return void 0;
|
|
34
|
+
if (!a.awaiting) return NO_HOST_ATTENTION;
|
|
35
|
+
return {
|
|
36
|
+
awaiting: true,
|
|
37
|
+
kind: typeof a.kind === "string" && KINDS.has(a.kind) ? a.kind : null,
|
|
38
|
+
since: typeof a.since === "number" ? a.since : null
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const channel = (0, import_pushChannel.createPushChannel)({
|
|
42
|
+
pushType: import_protocol.HOST_ATTENTION,
|
|
43
|
+
requestType: import_protocol.REQUEST_HOST_ATTENTION,
|
|
44
|
+
initial: NO_HOST_ATTENTION,
|
|
45
|
+
parse: (msg) => parseHostAttention(msg.attention)
|
|
46
|
+
});
|
|
47
|
+
const getHostAttention = () => channel.get();
|
|
48
|
+
const onHostAttentionChange = (listener) => channel.onChange(listener);
|
|
49
|
+
const useHostAttention = () => channel.use();
|
|
50
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
51
|
+
0 && (module.exports = {
|
|
52
|
+
NO_HOST_ATTENTION,
|
|
53
|
+
getHostAttention,
|
|
54
|
+
onHostAttentionChange,
|
|
55
|
+
useHostAttention
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=hostAttention.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hostAttention.ts"],"sourcesContent":["// The host-attention channel (R3-307) — what the host is waiting for, right now.\n//\n// THE GAP THIS CLOSES. R3-298 bounded every host protocol call and classified each as\n// `attended` or `unattended`, but classification is per `(scheme, method)` and\n// attendedness is really a property of a MOMENT: `spaces:mount` is unattended when the\n// grant is already held and attended on first use, because the host raises consent INSIDE\n// the request. A per-method table cannot tell those apart, so R3-298 put anything that MAY\n// prompt on the long (attended) bound — which means the common grant-held path also waits\n// ten minutes before it reports a fault, and a caller can only say \"still waiting on\n// something that may need you\", never \"tap your passkey\".\n//\n// Only the HOST knows a prompt is on screen right now and what it is. So it says so, on a\n// channel every app can read, and two things become possible:\n//\n// 1. A surface can name what it is waiting for. \"Waiting for your passkey…\" instead of a\n// spinner is most of a user's ability to act — especially on the provider-setup\n// wizard's Test-connection step, whose whole purpose is to prove setup worked.\n// 2. The attended bounds become a fact rather than a guess. A may-prompt call runs on the\n// SHORT bound and is suspended only while the host says a person is being asked\n// (`protocolDeadline.ts`, `sandboxUtils.withDeadline`).\n//\n// WHAT IT DELIBERATELY DOES NOT CARRY. No secret value, no secret id, no app key, no\n// capability, no resource name — nothing from which a held grant could be inferred. It is\n// readable by every app at the baseline principal, so it says only that the HOST is busy\n// and with what KIND of prompt. That is information the user is already looking at: a host\n// modal is visible chrome. (The residual it does leave — one app observing that some prompt\n// is up while another app's call is in flight — is the accepted low-bandwidth L0 signalling\n// class of the threat model §7.6, and carries no identifying detail to signal WITH.)\nimport { createPushChannel } from './pushChannel';\nimport { HOST_ATTENTION, REQUEST_HOST_ATTENTION } from './generated/protocol';\n\n/**\n * What kind of host prompt is up.\n *\n * A closed set on purpose: it is the coarsest vocabulary that still lets a surface write a\n * sentence a user can act on, and adding a finer kind would start to describe the specific\n * thing being asked about — which is the disclosure this channel refuses.\n *\n * - `passkey` — a WebAuthn assertion. The user must tap their authenticator.\n * - `consent` — a capability/consent decision (mount, create, share, import, reference).\n * - `picker` — a host-drawn chooser or entry surface (the powerbox, the add-secret modal).\n * - `confirmation` — a notice or confirm the user must dismiss.\n */\nexport type HostAttentionKind = 'passkey' | 'consent' | 'picker' | 'confirmation';\n\n/** Whether the host is waiting on the user right now, and for what. */\nexport interface HostAttention {\n /** `true` while a host prompt is on screen awaiting the user. */\n awaiting: boolean;\n /** The kind of prompt on screen — the innermost one, when they nest (an add-secret modal\n * that reaches the passkey unlock reports `passkey`). `null` when not awaiting. */\n kind: HostAttentionKind | null;\n /** `Date.now()` when the current wait began — the start of the whole continuous span, not\n * of the innermost prompt. `null` when not awaiting. */\n since: number | null;\n}\n\n/** Assumed before the host reports, and the value on a host that never pushes this channel\n * at all: nobody is being asked. Defaulting the OTHER way would suspend every may-prompt\n * deadline forever on an older host, which is the hang this whole line of work removes. */\nexport const NO_HOST_ATTENTION: HostAttention = { awaiting: false, kind: null, since: null };\n\nconst KINDS: ReadonlySet<string> = new Set(['passkey', 'consent', 'picker', 'confirmation']);\n\n/** Tolerant parse: a host that pushes a malformed payload is ignored, not believed. An\n * `awaiting` frame with no valid `kind` still counts as awaiting — the wait is the\n * load-bearing bit and the copy can fall back to a generic sentence. */\nconst parseHostAttention = (value: unknown): HostAttention | undefined => {\n const a = value as Partial<HostAttention> | null | undefined;\n if (!a || typeof a !== 'object' || typeof a.awaiting !== 'boolean') return undefined;\n if (!a.awaiting) return NO_HOST_ATTENTION;\n return {\n awaiting: true,\n kind: typeof a.kind === 'string' && KINDS.has(a.kind) ? (a.kind as HostAttentionKind) : null,\n since: typeof a.since === 'number' ? a.since : null,\n };\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `host-attention` and\n// answers `request-host-attention` (wire format: site-main channelBridge.ts). Read\n// DEFENSIVELY — a host that does not yet push it simply never answers, `initial` stands,\n// and every caller behaves exactly as it did before this channel existed.\nconst channel = createPushChannel<HostAttention>({\n pushType: HOST_ATTENTION,\n requestType: REQUEST_HOST_ATTENTION,\n initial: NO_HOST_ATTENTION,\n parse: (msg) => parseHostAttention(msg.attention),\n});\n\n/** Returns what the host is waiting for right now. Poll for a one-off read. */\nexport const getHostAttention = (): HostAttention => channel.get();\n\n/**\n * Subscribe to host-attention changes. The listener is invoked immediately with the current\n * value, then again on every change. Returns an unsubscribe fn.\n */\nexport const onHostAttentionChange = (listener: (attention: HostAttention) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning what the host is waiting for, re-rendering on change. */\nexport const useHostAttention = (): HostAttention => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BA,yBAAkC;AAClC,sBAAuD;AA+BhD,MAAM,oBAAmC,EAAE,UAAU,OAAO,MAAM,MAAM,OAAO,KAAK;AAE3F,MAAM,QAA6B,oBAAI,IAAI,CAAC,WAAW,WAAW,UAAU,cAAc,CAAC;AAK3F,MAAM,qBAAqB,CAAC,UAA8C;AACxE,QAAM,IAAI;AACV,MAAI,CAAC,KAAK,OAAO,MAAM,YAAY,OAAO,EAAE,aAAa,UAAW,QAAO;AAC3E,MAAI,CAAC,EAAE,SAAU,QAAO;AACxB,SAAO;AAAA,IACL,UAAU;AAAA,IACV,MAAM,OAAO,EAAE,SAAS,YAAY,MAAM,IAAI,EAAE,IAAI,IAAK,EAAE,OAA6B;AAAA,IACxF,OAAO,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AAAA,EACjD;AACF;AAMA,MAAM,cAAU,sCAAiC;AAAA,EAC/C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QAAQ,mBAAmB,IAAI,SAAS;AAClD,CAAC;AAGM,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;AAM1D,MAAM,wBAAwB,CAAC,aACpC,QAAQ,SAAS,QAAQ;AAGpB,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;","names":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What kind of host prompt is up.
|
|
3
|
+
*
|
|
4
|
+
* A closed set on purpose: it is the coarsest vocabulary that still lets a surface write a
|
|
5
|
+
* sentence a user can act on, and adding a finer kind would start to describe the specific
|
|
6
|
+
* thing being asked about — which is the disclosure this channel refuses.
|
|
7
|
+
*
|
|
8
|
+
* - `passkey` — a WebAuthn assertion. The user must tap their authenticator.
|
|
9
|
+
* - `consent` — a capability/consent decision (mount, create, share, import, reference).
|
|
10
|
+
* - `picker` — a host-drawn chooser or entry surface (the powerbox, the add-secret modal).
|
|
11
|
+
* - `confirmation` — a notice or confirm the user must dismiss.
|
|
12
|
+
*/
|
|
13
|
+
type HostAttentionKind = 'passkey' | 'consent' | 'picker' | 'confirmation';
|
|
14
|
+
/** Whether the host is waiting on the user right now, and for what. */
|
|
15
|
+
interface HostAttention {
|
|
16
|
+
/** `true` while a host prompt is on screen awaiting the user. */
|
|
17
|
+
awaiting: boolean;
|
|
18
|
+
/** The kind of prompt on screen — the innermost one, when they nest (an add-secret modal
|
|
19
|
+
* that reaches the passkey unlock reports `passkey`). `null` when not awaiting. */
|
|
20
|
+
kind: HostAttentionKind | null;
|
|
21
|
+
/** `Date.now()` when the current wait began — the start of the whole continuous span, not
|
|
22
|
+
* of the innermost prompt. `null` when not awaiting. */
|
|
23
|
+
since: number | null;
|
|
24
|
+
}
|
|
25
|
+
/** Assumed before the host reports, and the value on a host that never pushes this channel
|
|
26
|
+
* at all: nobody is being asked. Defaulting the OTHER way would suspend every may-prompt
|
|
27
|
+
* deadline forever on an older host, which is the hang this whole line of work removes. */
|
|
28
|
+
declare const NO_HOST_ATTENTION: HostAttention;
|
|
29
|
+
/** Returns what the host is waiting for right now. Poll for a one-off read. */
|
|
30
|
+
declare const getHostAttention: () => HostAttention;
|
|
31
|
+
/**
|
|
32
|
+
* Subscribe to host-attention changes. The listener is invoked immediately with the current
|
|
33
|
+
* value, then again on every change. Returns an unsubscribe fn.
|
|
34
|
+
*/
|
|
35
|
+
declare const onHostAttentionChange: (listener: (attention: HostAttention) => void) => (() => void);
|
|
36
|
+
/** React hook returning what the host is waiting for, re-rendering on change. */
|
|
37
|
+
declare const useHostAttention: () => HostAttention;
|
|
38
|
+
|
|
39
|
+
export { type HostAttention, type HostAttentionKind, NO_HOST_ATTENTION, getHostAttention, onHostAttentionChange, useHostAttention };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What kind of host prompt is up.
|
|
3
|
+
*
|
|
4
|
+
* A closed set on purpose: it is the coarsest vocabulary that still lets a surface write a
|
|
5
|
+
* sentence a user can act on, and adding a finer kind would start to describe the specific
|
|
6
|
+
* thing being asked about — which is the disclosure this channel refuses.
|
|
7
|
+
*
|
|
8
|
+
* - `passkey` — a WebAuthn assertion. The user must tap their authenticator.
|
|
9
|
+
* - `consent` — a capability/consent decision (mount, create, share, import, reference).
|
|
10
|
+
* - `picker` — a host-drawn chooser or entry surface (the powerbox, the add-secret modal).
|
|
11
|
+
* - `confirmation` — a notice or confirm the user must dismiss.
|
|
12
|
+
*/
|
|
13
|
+
type HostAttentionKind = 'passkey' | 'consent' | 'picker' | 'confirmation';
|
|
14
|
+
/** Whether the host is waiting on the user right now, and for what. */
|
|
15
|
+
interface HostAttention {
|
|
16
|
+
/** `true` while a host prompt is on screen awaiting the user. */
|
|
17
|
+
awaiting: boolean;
|
|
18
|
+
/** The kind of prompt on screen — the innermost one, when they nest (an add-secret modal
|
|
19
|
+
* that reaches the passkey unlock reports `passkey`). `null` when not awaiting. */
|
|
20
|
+
kind: HostAttentionKind | null;
|
|
21
|
+
/** `Date.now()` when the current wait began — the start of the whole continuous span, not
|
|
22
|
+
* of the innermost prompt. `null` when not awaiting. */
|
|
23
|
+
since: number | null;
|
|
24
|
+
}
|
|
25
|
+
/** Assumed before the host reports, and the value on a host that never pushes this channel
|
|
26
|
+
* at all: nobody is being asked. Defaulting the OTHER way would suspend every may-prompt
|
|
27
|
+
* deadline forever on an older host, which is the hang this whole line of work removes. */
|
|
28
|
+
declare const NO_HOST_ATTENTION: HostAttention;
|
|
29
|
+
/** Returns what the host is waiting for right now. Poll for a one-off read. */
|
|
30
|
+
declare const getHostAttention: () => HostAttention;
|
|
31
|
+
/**
|
|
32
|
+
* Subscribe to host-attention changes. The listener is invoked immediately with the current
|
|
33
|
+
* value, then again on every change. Returns an unsubscribe fn.
|
|
34
|
+
*/
|
|
35
|
+
declare const onHostAttentionChange: (listener: (attention: HostAttention) => void) => (() => void);
|
|
36
|
+
/** React hook returning what the host is waiting for, re-rendering on change. */
|
|
37
|
+
declare const useHostAttention: () => HostAttention;
|
|
38
|
+
|
|
39
|
+
export { type HostAttention, type HostAttentionKind, NO_HOST_ATTENTION, getHostAttention, onHostAttentionChange, useHostAttention };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import "./chunk-VHAA22YE.js";
|
|
2
|
+
import { createPushChannel } from "./pushChannel";
|
|
3
|
+
import { HOST_ATTENTION, REQUEST_HOST_ATTENTION } from "./generated/protocol";
|
|
4
|
+
const NO_HOST_ATTENTION = { awaiting: false, kind: null, since: null };
|
|
5
|
+
const KINDS = /* @__PURE__ */ new Set(["passkey", "consent", "picker", "confirmation"]);
|
|
6
|
+
const parseHostAttention = (value) => {
|
|
7
|
+
const a = value;
|
|
8
|
+
if (!a || typeof a !== "object" || typeof a.awaiting !== "boolean") return void 0;
|
|
9
|
+
if (!a.awaiting) return NO_HOST_ATTENTION;
|
|
10
|
+
return {
|
|
11
|
+
awaiting: true,
|
|
12
|
+
kind: typeof a.kind === "string" && KINDS.has(a.kind) ? a.kind : null,
|
|
13
|
+
since: typeof a.since === "number" ? a.since : null
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
const channel = createPushChannel({
|
|
17
|
+
pushType: HOST_ATTENTION,
|
|
18
|
+
requestType: REQUEST_HOST_ATTENTION,
|
|
19
|
+
initial: NO_HOST_ATTENTION,
|
|
20
|
+
parse: (msg) => parseHostAttention(msg.attention)
|
|
21
|
+
});
|
|
22
|
+
const getHostAttention = () => channel.get();
|
|
23
|
+
const onHostAttentionChange = (listener) => channel.onChange(listener);
|
|
24
|
+
const useHostAttention = () => channel.use();
|
|
25
|
+
export {
|
|
26
|
+
NO_HOST_ATTENTION,
|
|
27
|
+
getHostAttention,
|
|
28
|
+
onHostAttentionChange,
|
|
29
|
+
useHostAttention
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=hostAttention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hostAttention.ts"],"sourcesContent":["// The host-attention channel (R3-307) — what the host is waiting for, right now.\n//\n// THE GAP THIS CLOSES. R3-298 bounded every host protocol call and classified each as\n// `attended` or `unattended`, but classification is per `(scheme, method)` and\n// attendedness is really a property of a MOMENT: `spaces:mount` is unattended when the\n// grant is already held and attended on first use, because the host raises consent INSIDE\n// the request. A per-method table cannot tell those apart, so R3-298 put anything that MAY\n// prompt on the long (attended) bound — which means the common grant-held path also waits\n// ten minutes before it reports a fault, and a caller can only say \"still waiting on\n// something that may need you\", never \"tap your passkey\".\n//\n// Only the HOST knows a prompt is on screen right now and what it is. So it says so, on a\n// channel every app can read, and two things become possible:\n//\n// 1. A surface can name what it is waiting for. \"Waiting for your passkey…\" instead of a\n// spinner is most of a user's ability to act — especially on the provider-setup\n// wizard's Test-connection step, whose whole purpose is to prove setup worked.\n// 2. The attended bounds become a fact rather than a guess. A may-prompt call runs on the\n// SHORT bound and is suspended only while the host says a person is being asked\n// (`protocolDeadline.ts`, `sandboxUtils.withDeadline`).\n//\n// WHAT IT DELIBERATELY DOES NOT CARRY. No secret value, no secret id, no app key, no\n// capability, no resource name — nothing from which a held grant could be inferred. It is\n// readable by every app at the baseline principal, so it says only that the HOST is busy\n// and with what KIND of prompt. That is information the user is already looking at: a host\n// modal is visible chrome. (The residual it does leave — one app observing that some prompt\n// is up while another app's call is in flight — is the accepted low-bandwidth L0 signalling\n// class of the threat model §7.6, and carries no identifying detail to signal WITH.)\nimport { createPushChannel } from './pushChannel';\nimport { HOST_ATTENTION, REQUEST_HOST_ATTENTION } from './generated/protocol';\n\n/**\n * What kind of host prompt is up.\n *\n * A closed set on purpose: it is the coarsest vocabulary that still lets a surface write a\n * sentence a user can act on, and adding a finer kind would start to describe the specific\n * thing being asked about — which is the disclosure this channel refuses.\n *\n * - `passkey` — a WebAuthn assertion. The user must tap their authenticator.\n * - `consent` — a capability/consent decision (mount, create, share, import, reference).\n * - `picker` — a host-drawn chooser or entry surface (the powerbox, the add-secret modal).\n * - `confirmation` — a notice or confirm the user must dismiss.\n */\nexport type HostAttentionKind = 'passkey' | 'consent' | 'picker' | 'confirmation';\n\n/** Whether the host is waiting on the user right now, and for what. */\nexport interface HostAttention {\n /** `true` while a host prompt is on screen awaiting the user. */\n awaiting: boolean;\n /** The kind of prompt on screen — the innermost one, when they nest (an add-secret modal\n * that reaches the passkey unlock reports `passkey`). `null` when not awaiting. */\n kind: HostAttentionKind | null;\n /** `Date.now()` when the current wait began — the start of the whole continuous span, not\n * of the innermost prompt. `null` when not awaiting. */\n since: number | null;\n}\n\n/** Assumed before the host reports, and the value on a host that never pushes this channel\n * at all: nobody is being asked. Defaulting the OTHER way would suspend every may-prompt\n * deadline forever on an older host, which is the hang this whole line of work removes. */\nexport const NO_HOST_ATTENTION: HostAttention = { awaiting: false, kind: null, since: null };\n\nconst KINDS: ReadonlySet<string> = new Set(['passkey', 'consent', 'picker', 'confirmation']);\n\n/** Tolerant parse: a host that pushes a malformed payload is ignored, not believed. An\n * `awaiting` frame with no valid `kind` still counts as awaiting — the wait is the\n * load-bearing bit and the copy can fall back to a generic sentence. */\nconst parseHostAttention = (value: unknown): HostAttention | undefined => {\n const a = value as Partial<HostAttention> | null | undefined;\n if (!a || typeof a !== 'object' || typeof a.awaiting !== 'boolean') return undefined;\n if (!a.awaiting) return NO_HOST_ATTENTION;\n return {\n awaiting: true,\n kind: typeof a.kind === 'string' && KINDS.has(a.kind) ? (a.kind as HostAttentionKind) : null,\n since: typeof a.since === 'number' ? a.since : null,\n };\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `host-attention` and\n// answers `request-host-attention` (wire format: site-main channelBridge.ts). Read\n// DEFENSIVELY — a host that does not yet push it simply never answers, `initial` stands,\n// and every caller behaves exactly as it did before this channel existed.\nconst channel = createPushChannel<HostAttention>({\n pushType: HOST_ATTENTION,\n requestType: REQUEST_HOST_ATTENTION,\n initial: NO_HOST_ATTENTION,\n parse: (msg) => parseHostAttention(msg.attention),\n});\n\n/** Returns what the host is waiting for right now. Poll for a one-off read. */\nexport const getHostAttention = (): HostAttention => channel.get();\n\n/**\n * Subscribe to host-attention changes. The listener is invoked immediately with the current\n * value, then again on every change. Returns an unsubscribe fn.\n */\nexport const onHostAttentionChange = (listener: (attention: HostAttention) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning what the host is waiting for, re-rendering on change. */\nexport const useHostAttention = (): HostAttention => channel.use();\n"],"mappings":";AA4BA,SAAS,yBAAyB;AAClC,SAAS,gBAAgB,8BAA8B;AA+BhD,MAAM,oBAAmC,EAAE,UAAU,OAAO,MAAM,MAAM,OAAO,KAAK;AAE3F,MAAM,QAA6B,oBAAI,IAAI,CAAC,WAAW,WAAW,UAAU,cAAc,CAAC;AAK3F,MAAM,qBAAqB,CAAC,UAA8C;AACxE,QAAM,IAAI;AACV,MAAI,CAAC,KAAK,OAAO,MAAM,YAAY,OAAO,EAAE,aAAa,UAAW,QAAO;AAC3E,MAAI,CAAC,EAAE,SAAU,QAAO;AACxB,SAAO;AAAA,IACL,UAAU;AAAA,IACV,MAAM,OAAO,EAAE,SAAS,YAAY,MAAM,IAAI,EAAE,IAAI,IAAK,EAAE,OAA6B;AAAA,IACxF,OAAO,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AAAA,EACjD;AACF;AAMA,MAAM,UAAU,kBAAiC;AAAA,EAC/C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AAAA,EACT,OAAO,CAAC,QAAQ,mBAAmB,IAAI,SAAS;AAClD,CAAC;AAGM,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;AAM1D,MAAM,wBAAwB,CAAC,aACpC,QAAQ,SAAS,QAAQ;AAGpB,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var hostTransport_exports = {};
|
|
20
|
+
__export(hostTransport_exports, {
|
|
21
|
+
addListener: () => addListener,
|
|
22
|
+
sendMessage: () => sendMessage,
|
|
23
|
+
transport: () => transport
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(hostTransport_exports);
|
|
26
|
+
var import_hostRuntime = require("./hostRuntime");
|
|
27
|
+
function transport() {
|
|
28
|
+
try {
|
|
29
|
+
const injected = module?.evaluation?.module?.bundler?.messageBus;
|
|
30
|
+
if (injected && typeof injected.sendMessage === "function") return injected;
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
const t = (0, import_hostRuntime.getHostRuntime)()?.transport;
|
|
34
|
+
if (t && typeof t.sendMessage === "function") return t;
|
|
35
|
+
throw new Error("immediately.run: no host transport (neither injected nor __immediatelyRun__)");
|
|
36
|
+
}
|
|
37
|
+
const sendMessage = (type, data = {}) => {
|
|
38
|
+
transport().sendMessage(type, data);
|
|
39
|
+
};
|
|
40
|
+
const addListener = (msgType, handler, event) => {
|
|
41
|
+
const onMessage = event ?? transport().onMessage;
|
|
42
|
+
const disposable = onMessage((msg) => {
|
|
43
|
+
if (msg.type === msgType) {
|
|
44
|
+
handler(msg);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return () => disposable.dispose();
|
|
48
|
+
};
|
|
49
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
50
|
+
0 && (module.exports = {
|
|
51
|
+
addListener,
|
|
52
|
+
sendMessage,
|
|
53
|
+
transport
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=hostTransport.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hostTransport.ts"],"sourcesContent":["// The host transport resolver (SDK_PACKAGING_SPEC §4, expose-transport) — the ONE place\n// that answers \"how do I reach the host from here\".\n//\n// All host comms (sendMessage / protocolRequest / onMessage) go through this resolver so\n// the SDK is transport-agnostic: it works whether it was INJECTED into the bundler's\n// evaluation context (the current path — `module.evaluation.module.bundler.messageBus`) OR\n// fetched from npm as an ordinary dependency, in which case the sandbox runtime hands it\n// the transport via the §4 discovery global (`globalThis.__immediatelyRun__`).\n//\n// Dual-mode (§8): injection wins while it's active, so existing behaviour is byte-for-byte\n// preserved; the global is the fallback the npm-fetched SDK uses. When injection is removed\n// (phase 3), only the global path remains — `bundler.*` stops being API, which is the whole\n// point.\n//\n// WHY THIS IS ITS OWN MODULE (R3-307). It was the bottom half of `sandboxUtils.ts` until\n// the deadline machinery grew a dependency on the host-attention push channel. A push\n// channel needs the transport, and `withDeadline` needs the channel, so leaving both in one\n// module made `sandboxUtils → hostAttention → pushChannel → sandboxUtils` — a cycle, and\n// this package's import graph is CI-enforced acyclic (`check:circular`; a circular SDK\n// import once made the bundler infinite-loop). Splitting the *primitives* out puts\n// `sandboxUtils` at the TOP of the graph instead of in the middle of it. `sandboxUtils`\n// re-exports `sendMessage`/`addListener`, so every existing import site is unchanged and\n// the api-snapshot entry for that module keeps all four of its names.\nimport { getHostRuntime } from './hostRuntime';\n\nexport interface HostTransport {\n sendMessage(type: string, data?: Record<string, any>): void;\n protocolRequest(protocolName: string, method: string, params: Array<any>): Promise<any>;\n onMessage(handler: (msg: any) => void): { dispose(): void };\n}\n\nexport function transport(): HostTransport {\n // Injected bundler messageBus first — the current path, unchanged.\n try {\n // @ts-ignore - `module.evaluation` is injected by the sandbox runtime\n const injected = module?.evaluation?.module?.bundler?.messageBus;\n if (injected && typeof injected.sendMessage === 'function') return injected;\n } catch {\n /* no injection in this realm — fall through to the §4 global */\n }\n // §4 runtime-discovery transport (the npm-fetched SDK path).\n const t = getHostRuntime()?.transport as HostTransport | undefined;\n if (t && typeof t.sendMessage === 'function') return t;\n throw new Error('immediately.run: no host transport (neither injected nor __immediatelyRun__)');\n}\n\nexport const sendMessage = (type: string, data: Record<string, any> = {}) => {\n transport().sendMessage(type, data);\n};\n\nexport const addListener = (\n msgType: string,\n handler: (msg: any) => void,\n event?: any,\n): (() => void) => {\n const onMessage = event ?? transport().onMessage;\n const disposable = onMessage((msg: any) => {\n if (msg.type === msgType) {\n handler(msg);\n }\n });\n return () => disposable.dispose();\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA,yBAA+B;AAQxB,SAAS,YAA2B;AAEzC,MAAI;AAEF,UAAM,WAAW,QAAQ,YAAY,QAAQ,SAAS;AACtD,QAAI,YAAY,OAAO,SAAS,gBAAgB,WAAY,QAAO;AAAA,EACrE,QAAQ;AAAA,EAER;AAEA,QAAM,QAAI,mCAAe,GAAG;AAC5B,MAAI,KAAK,OAAO,EAAE,gBAAgB,WAAY,QAAO;AACrD,QAAM,IAAI,MAAM,8EAA8E;AAChG;AAEO,MAAM,cAAc,CAAC,MAAc,OAA4B,CAAC,MAAM;AAC3E,YAAU,EAAE,YAAY,MAAM,IAAI;AACpC;AAEO,MAAM,cAAc,CACzB,SACA,SACA,UACiB;AACjB,QAAM,YAAY,SAAS,UAAU,EAAE;AACvC,QAAM,aAAa,UAAU,CAAC,QAAa;AACzC,QAAI,IAAI,SAAS,SAAS;AACxB,cAAQ,GAAG;AAAA,IACb;AAAA,EACF,CAAC;AACD,SAAO,MAAM,WAAW,QAAQ;AAClC;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface HostTransport {
|
|
2
|
+
sendMessage(type: string, data?: Record<string, any>): void;
|
|
3
|
+
protocolRequest(protocolName: string, method: string, params: Array<any>): Promise<any>;
|
|
4
|
+
onMessage(handler: (msg: any) => void): {
|
|
5
|
+
dispose(): void;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
declare function transport(): HostTransport;
|
|
9
|
+
declare const sendMessage: (type: string, data?: Record<string, any>) => void;
|
|
10
|
+
declare const addListener: (msgType: string, handler: (msg: any) => void, event?: any) => (() => void);
|
|
11
|
+
|
|
12
|
+
export { type HostTransport, addListener, sendMessage, transport };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface HostTransport {
|
|
2
|
+
sendMessage(type: string, data?: Record<string, any>): void;
|
|
3
|
+
protocolRequest(protocolName: string, method: string, params: Array<any>): Promise<any>;
|
|
4
|
+
onMessage(handler: (msg: any) => void): {
|
|
5
|
+
dispose(): void;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
declare function transport(): HostTransport;
|
|
9
|
+
declare const sendMessage: (type: string, data?: Record<string, any>) => void;
|
|
10
|
+
declare const addListener: (msgType: string, handler: (msg: any) => void, event?: any) => (() => void);
|
|
11
|
+
|
|
12
|
+
export { type HostTransport, addListener, sendMessage, transport };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "./chunk-VHAA22YE.js";
|
|
2
|
+
import { getHostRuntime } from "./hostRuntime";
|
|
3
|
+
function transport() {
|
|
4
|
+
try {
|
|
5
|
+
const injected = module?.evaluation?.module?.bundler?.messageBus;
|
|
6
|
+
if (injected && typeof injected.sendMessage === "function") return injected;
|
|
7
|
+
} catch {
|
|
8
|
+
}
|
|
9
|
+
const t = getHostRuntime()?.transport;
|
|
10
|
+
if (t && typeof t.sendMessage === "function") return t;
|
|
11
|
+
throw new Error("immediately.run: no host transport (neither injected nor __immediatelyRun__)");
|
|
12
|
+
}
|
|
13
|
+
const sendMessage = (type, data = {}) => {
|
|
14
|
+
transport().sendMessage(type, data);
|
|
15
|
+
};
|
|
16
|
+
const addListener = (msgType, handler, event) => {
|
|
17
|
+
const onMessage = event ?? transport().onMessage;
|
|
18
|
+
const disposable = onMessage((msg) => {
|
|
19
|
+
if (msg.type === msgType) {
|
|
20
|
+
handler(msg);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return () => disposable.dispose();
|
|
24
|
+
};
|
|
25
|
+
export {
|
|
26
|
+
addListener,
|
|
27
|
+
sendMessage,
|
|
28
|
+
transport
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=hostTransport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hostTransport.ts"],"sourcesContent":["// The host transport resolver (SDK_PACKAGING_SPEC §4, expose-transport) — the ONE place\n// that answers \"how do I reach the host from here\".\n//\n// All host comms (sendMessage / protocolRequest / onMessage) go through this resolver so\n// the SDK is transport-agnostic: it works whether it was INJECTED into the bundler's\n// evaluation context (the current path — `module.evaluation.module.bundler.messageBus`) OR\n// fetched from npm as an ordinary dependency, in which case the sandbox runtime hands it\n// the transport via the §4 discovery global (`globalThis.__immediatelyRun__`).\n//\n// Dual-mode (§8): injection wins while it's active, so existing behaviour is byte-for-byte\n// preserved; the global is the fallback the npm-fetched SDK uses. When injection is removed\n// (phase 3), only the global path remains — `bundler.*` stops being API, which is the whole\n// point.\n//\n// WHY THIS IS ITS OWN MODULE (R3-307). It was the bottom half of `sandboxUtils.ts` until\n// the deadline machinery grew a dependency on the host-attention push channel. A push\n// channel needs the transport, and `withDeadline` needs the channel, so leaving both in one\n// module made `sandboxUtils → hostAttention → pushChannel → sandboxUtils` — a cycle, and\n// this package's import graph is CI-enforced acyclic (`check:circular`; a circular SDK\n// import once made the bundler infinite-loop). Splitting the *primitives* out puts\n// `sandboxUtils` at the TOP of the graph instead of in the middle of it. `sandboxUtils`\n// re-exports `sendMessage`/`addListener`, so every existing import site is unchanged and\n// the api-snapshot entry for that module keeps all four of its names.\nimport { getHostRuntime } from './hostRuntime';\n\nexport interface HostTransport {\n sendMessage(type: string, data?: Record<string, any>): void;\n protocolRequest(protocolName: string, method: string, params: Array<any>): Promise<any>;\n onMessage(handler: (msg: any) => void): { dispose(): void };\n}\n\nexport function transport(): HostTransport {\n // Injected bundler messageBus first — the current path, unchanged.\n try {\n // @ts-ignore - `module.evaluation` is injected by the sandbox runtime\n const injected = module?.evaluation?.module?.bundler?.messageBus;\n if (injected && typeof injected.sendMessage === 'function') return injected;\n } catch {\n /* no injection in this realm — fall through to the §4 global */\n }\n // §4 runtime-discovery transport (the npm-fetched SDK path).\n const t = getHostRuntime()?.transport as HostTransport | undefined;\n if (t && typeof t.sendMessage === 'function') return t;\n throw new Error('immediately.run: no host transport (neither injected nor __immediatelyRun__)');\n}\n\nexport const sendMessage = (type: string, data: Record<string, any> = {}) => {\n transport().sendMessage(type, data);\n};\n\nexport const addListener = (\n msgType: string,\n handler: (msg: any) => void,\n event?: any,\n): (() => void) => {\n const onMessage = event ?? transport().onMessage;\n const disposable = onMessage((msg: any) => {\n if (msg.type === msgType) {\n handler(msg);\n }\n });\n return () => disposable.dispose();\n};\n"],"mappings":";AAuBA,SAAS,sBAAsB;AAQxB,SAAS,YAA2B;AAEzC,MAAI;AAEF,UAAM,WAAW,QAAQ,YAAY,QAAQ,SAAS;AACtD,QAAI,YAAY,OAAO,SAAS,gBAAgB,WAAY,QAAO;AAAA,EACrE,QAAQ;AAAA,EAER;AAEA,QAAM,IAAI,eAAe,GAAG;AAC5B,MAAI,KAAK,OAAO,EAAE,gBAAgB,WAAY,QAAO;AACrD,QAAM,IAAI,MAAM,8EAA8E;AAChG;AAEO,MAAM,cAAc,CAAC,MAAc,OAA4B,CAAC,MAAM;AAC3E,YAAU,EAAE,YAAY,MAAM,IAAI;AACpC;AAEO,MAAM,cAAc,CACzB,SACA,SACA,UACiB;AACjB,QAAM,YAAY,SAAS,UAAU,EAAE;AACvC,QAAM,aAAa,UAAU,CAAC,QAAa;AACzC,QAAI,IAAI,SAAS,SAAS;AACxB,cAAQ,GAAG;AAAA,IACb;AAAA,EACF,CAAC;AACD,SAAO,MAAM,WAAW,QAAQ;AAClC;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ __reExport(index_exports, require("./theme"), module.exports);
|
|
|
39
39
|
__reExport(index_exports, require("./editorContext"), module.exports);
|
|
40
40
|
__reExport(index_exports, require("./editor"), module.exports);
|
|
41
41
|
__reExport(index_exports, require("./formFactor"), module.exports);
|
|
42
|
+
__reExport(index_exports, require("./hostAttention"), module.exports);
|
|
42
43
|
__reExport(index_exports, require("./region"), module.exports);
|
|
43
44
|
__reExport(index_exports, require("./mounts"), module.exports);
|
|
44
45
|
__reExport(index_exports, require("./contribute"), module.exports);
|
|
@@ -60,6 +61,7 @@ __reExport(index_exports, require("./irMarkers"), module.exports);
|
|
|
60
61
|
__reExport(index_exports, require("./ready"), module.exports);
|
|
61
62
|
__reExport(index_exports, require("./loading"), module.exports);
|
|
62
63
|
__reExport(index_exports, require("./protocolStream"), module.exports);
|
|
64
|
+
__reExport(index_exports, require("./protocolDeadline"), module.exports);
|
|
63
65
|
__reExport(index_exports, require("./sandboxTypes"), module.exports);
|
|
64
66
|
__reExport(index_exports, require("./safeContent"), module.exports);
|
|
65
67
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -81,6 +83,7 @@ __reExport(index_exports, require("./safeContent"), module.exports);
|
|
|
81
83
|
...require("./editorContext"),
|
|
82
84
|
...require("./editor"),
|
|
83
85
|
...require("./formFactor"),
|
|
86
|
+
...require("./hostAttention"),
|
|
84
87
|
...require("./region"),
|
|
85
88
|
...require("./mounts"),
|
|
86
89
|
...require("./contribute"),
|
|
@@ -102,6 +105,7 @@ __reExport(index_exports, require("./safeContent"), module.exports);
|
|
|
102
105
|
...require("./ready"),
|
|
103
106
|
...require("./loading"),
|
|
104
107
|
...require("./protocolStream"),
|
|
108
|
+
...require("./protocolDeadline"),
|
|
105
109
|
...require("./sandboxTypes"),
|
|
106
110
|
...require("./safeContent")
|
|
107
111
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks'\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAQA,yBAA4B;AAC5B,0BAAc,0BATd;AAUA,0BAAc,uCAVd;AAWA,0BAAc,wBAXd;AAYA,0BAAc,oCAZd;AAaA,0BAAc,gCAbd;AAcA,0BAAc,oBAdd;AAiBA,0BAAc,6BAjBd;AAkBA,0BAAc,mBAlBd;AAmBA,0BAAc,oBAnBd;AAoBA,0BAAc,4BApBd;AAqBA,0BAAc,qBArBd;AAsBA,0BAAc,yBAtBd;AAuBA,0BAAc,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks'\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './hostAttention';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './protocolDeadline';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAQA,yBAA4B;AAC5B,0BAAc,0BATd;AAUA,0BAAc,uCAVd;AAWA,0BAAc,wBAXd;AAYA,0BAAc,oCAZd;AAaA,0BAAc,gCAbd;AAcA,0BAAc,oBAdd;AAiBA,0BAAc,6BAjBd;AAkBA,0BAAc,mBAlBd;AAmBA,0BAAc,oBAnBd;AAoBA,0BAAc,4BApBd;AAqBA,0BAAc,qBArBd;AAsBA,0BAAc,yBAtBd;AAuBA,0BAAc,4BAvBd;AAwBA,0BAAc,qBAxBd;AAyBA,0BAAc,qBAzBd;AA0BA,0BAAc,yBA1Bd;AA2BA,0BAAc,sBA3Bd;AA4BA,0BAAc,kBA5Bd;AA6BA,0BAAc,kBA7Bd;AA8BA,0BAAc,uBA9Bd;AA+BA,0BAAc,sBA/Bd;AAgCA,0BAAc,kBAhCd;AAiCA,0BAAc,0BAjCd;AAkCA,0BAAc,kBAlCd;AAmCA,0BAAc,yBAnCd;AAoCA,0BAAc,iBApCd;AAqCA,0BAAc,oBArCd;AAsCA,0BAAc,oBAtCd;AAuCA,0BAAc,qBAvCd;AAwCA,0BAAc,sBAxCd;AAyCA,0BAAc,wBAzCd;AA0CA,0BAAc,oBA1Cd;AA2CA,0BAAc,sBA3Cd;AA4CA,0BAAc,6BA5Cd;AA6CA,0BAAc,+BA7Cd;AA8CA,0BAAc,2BA9Cd;AA+CA,0BAAc,0BA/Cd;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -15,6 +15,7 @@ export { HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme
|
|
|
15
15
|
export { EditorContext, getEditorContext, onEditorContextChange, useEditorContext } from './editorContext.cjs';
|
|
16
16
|
export { EditTarget, EditorOpenError, EditorSessionError, EditorWriteError, RequestEditError, closeFile, createFile, createFolder, deleteEntry, openInEditor, renameEntry, requestEdit, setActiveFile, uploadFile } from './editor.cjs';
|
|
17
17
|
export { FormFactor, FormFactorClass, Orientation, getFormFactor, onFormFactorChange, useFormFactor } from './formFactor.cjs';
|
|
18
|
+
export { HostAttention, HostAttentionKind, NO_HOST_ATTENTION, getHostAttention, onHostAttentionChange, useHostAttention } from './hostAttention.cjs';
|
|
18
19
|
export { getRegion, useRegion } from './region.cjs';
|
|
19
20
|
export { Invite, MountQuery, MountRemoveReason, MountRule, RemovedMount, SandboxMount, SessionMount, SpaceError, acceptInvite, awaitMatchingMount, createSpace, declineInvite, findMount, getAppMountPath, getInvites, getMounts, getSessionMounts, importSettingsFromParent, listMyInvites, listPendingInvites, listSettingsApps, makeContentRef, mount, mountSpace, onInvitesChange, onMountsChange, onSessionMountsChange, openSettings, openSettingsOf, requestMount, requestSpace, resolveContentRef, resolveContentRefs, revokeInvite, unmountSpace, useInvites, useMounts, useSessionMounts, waitForMount } from './mounts.cjs';
|
|
20
21
|
export { ContributeMode, ContributeOptions, ContributionEvent, ContributionResult, contribute } from './contribute.cjs';
|
|
@@ -23,7 +24,7 @@ export { RegionMessage, onRegionMessage, postToRegion, revealRegion, useRegionMe
|
|
|
23
24
|
export { DraggableItem, DroppedItem, ItemDragError, cancelItemDrag, onItemDrop, startItemDrag, useDroppedItem } from './dnd.cjs';
|
|
24
25
|
export { HostFetchInit, HostFetchResponse, HostFetchStreamEvent, HostFetchStreamResult, hostFetch, hostFetchStream } from './netFetch.cjs';
|
|
25
26
|
export { SecretError, SecretGrant, SecretHints, SecretQuery, SecretType, SecretView, getSecrets, onSecretsChange, requestAddSecret, requestSecret, revokeSecret, useSecrets } from './secrets.cjs';
|
|
26
|
-
export { ChatDelta, ChatFeatures, ChatMessage, ChatProviderInfo, ChatRequest, ChatResult, ChatRole, ChatStopReason, ContentPart, ToolDef, chat, describeChat, onChatProviderChange, useChatProvider } from './llm.cjs';
|
|
27
|
+
export { ChatDelta, ChatFeatures, ChatMessage, ChatProviderInfo, ChatProviderState, ChatRequest, ChatResult, ChatRole, ChatStopReason, ContentPart, ToolDef, chat, describeChat, describeChatState, onChatProviderChange, onChatProviderStateChange, useChatProvider, useChatProviderState } from './llm.cjs';
|
|
27
28
|
export { BuildError, ConsoleEntry, ConsoleLevel, Diagnostics, DiagnosticsProvenance, getDiagnostics, onDiagnosticsChange, useDiagnostics } from './diagnostics.cjs';
|
|
28
29
|
export { VcsActionError, VcsBranch, VcsChange, VcsPR, VcsState, getVcsState, onVcsStateChange, refreshDiff, refreshPRs, resetWorkingTree, useVcsState } from './vcs.cjs';
|
|
29
30
|
export { FsChange, getFsChange, onFsChange, useFsChange } from './onFsChange.cjs';
|
|
@@ -36,6 +37,7 @@ export { ForwardedMarker, IR_MARKERS, IrMarkerName, isAllowedMarkerName, isIrMar
|
|
|
36
37
|
export { ReadyState, __resetReady, __setReadyDeps, getReadyState, onReady, reportReady } from './ready.cjs';
|
|
37
38
|
export { LOADING_TIMINGS, LoadingRegion, Skeleton, SkeletonArchetype, SkeletonRow, Spinner } from './loading.cjs';
|
|
38
39
|
export { StreamError, StreamFrame, StreamTransport, consumeStream, protocolStream } from './protocolStream.cjs';
|
|
40
|
+
export { ATTENDED_FIRST_FRAME_MS, ATTENDED_TIMEOUT_MS, Attendance, BoundedCallOptions, CallBounds, DeadlineBound, NETWORK_TIMEOUT_MS, PENDING_NOTICE_MS, PendingAttention, PendingState, ProtocolCancelledError, ProtocolTimeoutError, STREAM_IDLE_TIMEOUT_MS, SuspendableDeadline, UNATTENDED_TIMEOUT_MS, attendanceOf, attendanceReason, boundsFor, createSuspendableDeadline, firstFrameBoundsFor, firstFrameTimeoutFor, timeoutFor } from './protocolDeadline.cjs';
|
|
39
41
|
export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryEntry, MetadataQueryFunction, MetadataQueryRecord, MetadataQueryResult, ModuleExports } from './sandboxTypes.cjs';
|
|
40
42
|
export { SafeContent, SafeContentProps } from './safeContent/SafeContent.cjs';
|
|
41
43
|
export { RenderMdastOptions, SafeContentComponents, renderMdast } from './safeContent/renderMdast.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { HostTheme, getHostTheme, onHostThemeChange, setHostTheme, useHostTheme
|
|
|
15
15
|
export { EditorContext, getEditorContext, onEditorContextChange, useEditorContext } from './editorContext.js';
|
|
16
16
|
export { EditTarget, EditorOpenError, EditorSessionError, EditorWriteError, RequestEditError, closeFile, createFile, createFolder, deleteEntry, openInEditor, renameEntry, requestEdit, setActiveFile, uploadFile } from './editor.js';
|
|
17
17
|
export { FormFactor, FormFactorClass, Orientation, getFormFactor, onFormFactorChange, useFormFactor } from './formFactor.js';
|
|
18
|
+
export { HostAttention, HostAttentionKind, NO_HOST_ATTENTION, getHostAttention, onHostAttentionChange, useHostAttention } from './hostAttention.js';
|
|
18
19
|
export { getRegion, useRegion } from './region.js';
|
|
19
20
|
export { Invite, MountQuery, MountRemoveReason, MountRule, RemovedMount, SandboxMount, SessionMount, SpaceError, acceptInvite, awaitMatchingMount, createSpace, declineInvite, findMount, getAppMountPath, getInvites, getMounts, getSessionMounts, importSettingsFromParent, listMyInvites, listPendingInvites, listSettingsApps, makeContentRef, mount, mountSpace, onInvitesChange, onMountsChange, onSessionMountsChange, openSettings, openSettingsOf, requestMount, requestSpace, resolveContentRef, resolveContentRefs, revokeInvite, unmountSpace, useInvites, useMounts, useSessionMounts, waitForMount } from './mounts.js';
|
|
20
21
|
export { ContributeMode, ContributeOptions, ContributionEvent, ContributionResult, contribute } from './contribute.js';
|
|
@@ -23,7 +24,7 @@ export { RegionMessage, onRegionMessage, postToRegion, revealRegion, useRegionMe
|
|
|
23
24
|
export { DraggableItem, DroppedItem, ItemDragError, cancelItemDrag, onItemDrop, startItemDrag, useDroppedItem } from './dnd.js';
|
|
24
25
|
export { HostFetchInit, HostFetchResponse, HostFetchStreamEvent, HostFetchStreamResult, hostFetch, hostFetchStream } from './netFetch.js';
|
|
25
26
|
export { SecretError, SecretGrant, SecretHints, SecretQuery, SecretType, SecretView, getSecrets, onSecretsChange, requestAddSecret, requestSecret, revokeSecret, useSecrets } from './secrets.js';
|
|
26
|
-
export { ChatDelta, ChatFeatures, ChatMessage, ChatProviderInfo, ChatRequest, ChatResult, ChatRole, ChatStopReason, ContentPart, ToolDef, chat, describeChat, onChatProviderChange, useChatProvider } from './llm.js';
|
|
27
|
+
export { ChatDelta, ChatFeatures, ChatMessage, ChatProviderInfo, ChatProviderState, ChatRequest, ChatResult, ChatRole, ChatStopReason, ContentPart, ToolDef, chat, describeChat, describeChatState, onChatProviderChange, onChatProviderStateChange, useChatProvider, useChatProviderState } from './llm.js';
|
|
27
28
|
export { BuildError, ConsoleEntry, ConsoleLevel, Diagnostics, DiagnosticsProvenance, getDiagnostics, onDiagnosticsChange, useDiagnostics } from './diagnostics.js';
|
|
28
29
|
export { VcsActionError, VcsBranch, VcsChange, VcsPR, VcsState, getVcsState, onVcsStateChange, refreshDiff, refreshPRs, resetWorkingTree, useVcsState } from './vcs.js';
|
|
29
30
|
export { FsChange, getFsChange, onFsChange, useFsChange } from './onFsChange.js';
|
|
@@ -36,6 +37,7 @@ export { ForwardedMarker, IR_MARKERS, IrMarkerName, isAllowedMarkerName, isIrMar
|
|
|
36
37
|
export { ReadyState, __resetReady, __setReadyDeps, getReadyState, onReady, reportReady } from './ready.js';
|
|
37
38
|
export { LOADING_TIMINGS, LoadingRegion, Skeleton, SkeletonArchetype, SkeletonRow, Spinner } from './loading.js';
|
|
38
39
|
export { StreamError, StreamFrame, StreamTransport, consumeStream, protocolStream } from './protocolStream.js';
|
|
40
|
+
export { ATTENDED_FIRST_FRAME_MS, ATTENDED_TIMEOUT_MS, Attendance, BoundedCallOptions, CallBounds, DeadlineBound, NETWORK_TIMEOUT_MS, PENDING_NOTICE_MS, PendingAttention, PendingState, ProtocolCancelledError, ProtocolTimeoutError, STREAM_IDLE_TIMEOUT_MS, SuspendableDeadline, UNATTENDED_TIMEOUT_MS, attendanceOf, attendanceReason, boundsFor, createSuspendableDeadline, firstFrameBoundsFor, firstFrameTimeoutFor, timeoutFor } from './protocolDeadline.js';
|
|
39
41
|
export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryEntry, MetadataQueryFunction, MetadataQueryRecord, MetadataQueryResult, ModuleExports } from './sandboxTypes.js';
|
|
40
42
|
export { SafeContent, SafeContentProps } from './safeContent/SafeContent.js';
|
|
41
43
|
export { RenderMdastOptions, SafeContentComponents, renderMdast } from './safeContent/renderMdast.js';
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export * from "./theme";
|
|
|
16
16
|
export * from "./editorContext";
|
|
17
17
|
export * from "./editor";
|
|
18
18
|
export * from "./formFactor";
|
|
19
|
+
export * from "./hostAttention";
|
|
19
20
|
export * from "./region";
|
|
20
21
|
export * from "./mounts";
|
|
21
22
|
export * from "./contribute";
|
|
@@ -37,6 +38,7 @@ export * from "./irMarkers";
|
|
|
37
38
|
export * from "./ready";
|
|
38
39
|
export * from "./loading";
|
|
39
40
|
export * from "./protocolStream";
|
|
41
|
+
export * from "./protocolDeadline";
|
|
40
42
|
export * from "./sandboxTypes";
|
|
41
43
|
export * from "./safeContent";
|
|
42
44
|
export {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks'\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n"],"mappings":";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAKd,SAAS,mBAAmB;AAC5B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\n// Only the component is public. `stripFrontmatter`/`appMountRelative` are module-level\n// exports so they can be unit-tested directly, NOT public API — the SDK's surface is\n// backwards-compatible forever, so an internal helper exported for a test's convenience is a\n// permanent commitment made for the wrong reason.\nexport { SafeInclude } from './components/SafeInclude';\nexport * from './sourceCache';\nexport * from './components/MDXComponents';\nexport * from './linkSpace';\nexport * from './components/MountImage';\nexport * from './components/Routes';\nexport * from './hooks'\n// R3-276: the supported way for a viewer app to provide its own metadata store,\n// replacing a wholesale re-provision of `TinkerableContext` in app code.\nexport * from './metadataSource';\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './hostAttention';\nexport * from './region';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './dnd';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './llm';\nexport * from './diagnostics';\nexport * from './vcs';\nexport * from './onFsChange';\nexport * from './fs';\nexport * from './debug';\nexport * from './tasks';\nexport * from './launch';\nexport * from './runtime';\nexport * from './irMarkers';\nexport * from './ready';\nexport * from './loading';\nexport * from './protocolStream';\nexport * from './protocolDeadline';\nexport * from './sandboxTypes';\nexport * from './safeContent';\n"],"mappings":";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAKd,SAAS,mBAAmB;AAC5B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
package/dist/linkSpace.cjs
CHANGED
|
@@ -26,7 +26,10 @@ __export(linkSpace_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(linkSpace_exports);
|
|
27
27
|
var import_react = require("react");
|
|
28
28
|
const FS_PREFIX = "$fs:";
|
|
29
|
-
const LinkSpaceContext = (0, import_react.createContext)({
|
|
29
|
+
const LinkSpaceContext = (0, import_react.createContext)({
|
|
30
|
+
corpusRoot: null,
|
|
31
|
+
bundleChrooted: false
|
|
32
|
+
});
|
|
30
33
|
const normalizeAbsolute = (path) => {
|
|
31
34
|
const out = [];
|
|
32
35
|
for (const seg of path.split("/")) {
|
|
@@ -36,16 +39,22 @@ const normalizeAbsolute = (path) => {
|
|
|
36
39
|
}
|
|
37
40
|
return "/" + out.join("/");
|
|
38
41
|
};
|
|
42
|
+
function resolveCorpusAbsolute(path, corpusRoot) {
|
|
43
|
+
const inner = normalizeAbsolute(path);
|
|
44
|
+
if (corpusRoot === null || corpusRoot === "/") return { state: "resolved", path: inner };
|
|
45
|
+
return { state: "resolved", path: normalizeAbsolute(corpusRoot + inner) };
|
|
46
|
+
}
|
|
39
47
|
function resolveLinkTarget(raw, opts = {}) {
|
|
40
48
|
if (raw.startsWith(FS_PREFIX)) {
|
|
41
49
|
const rest = raw.slice(FS_PREFIX.length);
|
|
42
50
|
if (!rest.startsWith("/")) return { state: "invalid" };
|
|
51
|
+
if (opts.bundleChrooted) return resolveCorpusAbsolute(rest, opts.corpusRoot ?? null);
|
|
43
52
|
return { state: "resolved", path: normalizeAbsolute(rest) };
|
|
44
53
|
}
|
|
45
54
|
if (raw.startsWith("/")) {
|
|
46
55
|
const corpusRoot = opts.corpusRoot ?? null;
|
|
47
56
|
if (corpusRoot !== null) {
|
|
48
|
-
return
|
|
57
|
+
return resolveCorpusAbsolute(raw, corpusRoot);
|
|
49
58
|
}
|
|
50
59
|
return { state: "resolved", path: normalizeAbsolute(raw) };
|
|
51
60
|
}
|
package/dist/linkSpace.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/linkSpace.ts"],"sourcesContent":["// Link path spaces (R3-273; REPO_CONTENT_DISPATCH_SPEC §9 decision, 2026-08-17).\n//\n// A document link's target resolves in one of two spaces:\n//\n// - DEFAULT — the enclosing corpus's virtual filesystem. RELATIVE targets resolve\n// against the authoring file (identical in both spaces); ABSOLUTE targets\n// (`/x/y.mdx`) resolve from the corpus root when an enclosing `LinkSpaceContext`\n// declares one, else from the filesystem root. A non-corpus app declares nothing\n// and keeps today's behavior bit-for-bit (its fs root IS its only root).\n//\n// - `$fs:` — the explicit filesystem space: `$fs:/content/x.mdx` resolves from the\n// root of the filesystem the app reads, escaping corpus-relative addressing.\n//\n// `$fs:` changes ADDRESSING, never REACH: resolution is pure path arithmetic and\n// existence is checked against the same in-mount metadata the default space uses —\n// nothing is fetched, and a link can never name what the app cannot already read.\n// A malformed `$fs:` target (anything not mount-absolute — which also catches\n// scheme smuggling like `$fs:javascript:…`) is INVALID and must render as a broken\n// link, never an anchor.\n//\n// Corpus nesting: `LinkSpaceContext` providers nest, and the NEAREST one wins —\n// which is exactly the innermost-enclosing-corpus rule (bundle encapsulation): a\n// document rendered inside a nested corpus resolves against the nested corpus.\n\nimport { createContext } from 'react';\n\nexport const FS_PREFIX = '$fs:';\n\nexport interface LinkSpace {\n /** Absolute filesystem path of the enclosing corpus's root (e.g. `/app/content`),\n * or `null` when the document is not corpus-hosted (default). */\n corpusRoot: string | null;\n}\n\n/** Ambient link space. A corpus-rendering app wraps its document tree in\n * `<LinkSpaceContext value={{ corpusRoot }}>`; nesting a second provider inside a\n * rendered sub-corpus makes the innermost root win. */\nexport const LinkSpaceContext = createContext<LinkSpace>({
|
|
1
|
+
{"version":3,"sources":["../src/linkSpace.ts"],"sourcesContent":["// Link path spaces (R3-273; REPO_CONTENT_DISPATCH_SPEC §9 decision, 2026-08-17).\n//\n// A document link's target resolves in one of two spaces:\n//\n// - DEFAULT — the enclosing corpus's virtual filesystem. RELATIVE targets resolve\n// against the authoring file (identical in both spaces); ABSOLUTE targets\n// (`/x/y.mdx`) resolve from the corpus root when an enclosing `LinkSpaceContext`\n// declares one, else from the filesystem root. A non-corpus app declares nothing\n// and keeps today's behavior bit-for-bit (its fs root IS its only root).\n//\n// - `$fs:` — the explicit filesystem space: `$fs:/content/x.mdx` resolves from the\n// root of the filesystem the app reads, escaping corpus-relative addressing.\n//\n// `$fs:` changes ADDRESSING, never REACH: resolution is pure path arithmetic and\n// existence is checked against the same in-mount metadata the default space uses —\n// nothing is fetched, and a link can never name what the app cannot already read.\n// A malformed `$fs:` target (anything not mount-absolute — which also catches\n// scheme smuggling like `$fs:javascript:…`) is INVALID and must render as a broken\n// link, never an anchor.\n//\n// Corpus nesting: `LinkSpaceContext` providers nest, and the NEAREST one wins —\n// which is exactly the innermost-enclosing-corpus rule (bundle encapsulation): a\n// document rendered inside a nested corpus resolves against the nested corpus.\n\nimport { createContext } from 'react';\n\nexport const FS_PREFIX = '$fs:';\n\nexport interface LinkSpace {\n /** Absolute filesystem path of the enclosing corpus's root (e.g. `/app/content`),\n * or `null` when the document is not corpus-hosted (default). */\n corpusRoot: string | null;\n /**\n * True when the filesystem this document resolves against is **chroot'd to the\n * bundle** — i.e. the port the app holds was scoped to the bundle's subtree, so\n * the mount root and the bundle root are the same directory\n * (`BUNDLE_LAYERS_SPEC §9`; the `T2`/`T4` wrapper, R3-319 / BL-2).\n *\n * Under that grant `$fs:` **collapses to the scoped root**: `$fs:/p` and `/p`\n * name the same byte, because there is no longer any \"mount-absolute\" space\n * outside the bundle for `$fs:` to reach into. Without this flag the resolver\n * would hand back a mount-absolute path that the chroot then re-roots anyway —\n * a link that renders as valid and resolves somewhere the author did not mean.\n *\n * **This is an invariant to CREATE, not one to inherit** (`BUNDLE_LAYERS_SPEC\n * §11`): the shipped resolver reads `{currentFile, corpusRoot}` and nothing\n * else, so `$fs:` is bundle-anchored only if something says so. It lives here,\n * in the resolver, rather than as a rule each caller applies by passing\n * `corpusRoot: '/'` — an invariant the arithmetic carries cannot be forgotten\n * at one call site out of five.\n */\n bundleChrooted?: boolean;\n}\n\n/** Ambient link space. A corpus-rendering app wraps its document tree in\n * `<LinkSpaceContext value={{ corpusRoot }}>`; nesting a second provider inside a\n * rendered sub-corpus makes the innermost root win. */\nexport const LinkSpaceContext = createContext<LinkSpace>({\n corpusRoot: null,\n bundleChrooted: false,\n});\n\n/** Collapse `.`/`..`/empty segments into a clean absolute path. `..` can never\n * climb above the root — a (virtual) root's parent is itself, which is what keeps\n * both the mount space and the corpus space closed under traversal. */\nexport const normalizeAbsolute = (path: string): string => {\n const out: string[] = [];\n for (const seg of path.split('/')) {\n if (seg === '' || seg === '.') continue;\n if (seg === '..') out.pop();\n else out.push(seg);\n }\n return '/' + out.join('/');\n};\n\nexport type ResolvedLinkTarget =\n /** Resolved to an absolute filesystem path (existence NOT checked here). */\n | { state: 'resolved'; path: string }\n /** A relative target with no known authoring file — the caller may route\n * optimistically (it cannot check existence or self-ness generically). */\n | { state: 'unresolvable' }\n /** A malformed `$fs:` target (not mount-absolute; includes scheme smuggling).\n * Callers MUST render this broken/inert — never as an anchor. */\n | { state: 'invalid' };\n\n/** Anchor a corpus-absolute path at `corpusRoot`, clamping the corpus-relative\n * half FIRST so the virtual corpus space stays closed under traversal. Shared by\n * the `/p` branch and — under a bundle chroot — the `$fs:/p` branch, so the two\n * spellings cannot drift into resolving differently. */\nfunction resolveCorpusAbsolute(path: string, corpusRoot: string | null): ResolvedLinkTarget {\n const inner = normalizeAbsolute(path);\n if (corpusRoot === null || corpusRoot === '/') return { state: 'resolved', path: inner };\n return { state: 'resolved', path: normalizeAbsolute(corpusRoot + inner) };\n}\n\n/**\n * Resolve a raw link target (a wikilink target or an in-app href's path half —\n * fragment already split off) to an absolute filesystem path. THE shared resolver:\n * the default `WikiLink`, the markdown `a` override, and safe-content consumers\n * all route through this one function so the two render pipelines cannot drift.\n */\nexport function resolveLinkTarget(\n raw: string,\n opts: {\n currentFile?: string;\n corpusRoot?: string | null;\n /** See `LinkSpace.bundleChrooted`. Under a bundle-chroot'd grant `$fs:`\n * resolves in the corpus space, because they are the same space. */\n bundleChrooted?: boolean;\n } = {},\n): ResolvedLinkTarget {\n if (raw.startsWith(FS_PREFIX)) {\n const rest = raw.slice(FS_PREFIX.length);\n // Must be mount-absolute. This single rule also fails `$fs:javascript:…`,\n // `$fs:https://…`, and every other smuggled scheme closed.\n if (!rest.startsWith('/')) return { state: 'invalid' };\n // Under a bundle chroot the mount root IS the bundle root, so `$fs:` has\n // nowhere outside to name: it takes the corpus-absolute branch below and the\n // two spellings collapse. `normalizeAbsolute` clamps `..` at the root either\n // way, so neither spelling can climb out — the collapse changes WHERE a\n // `$fs:` link points, never whether it can escape.\n if (opts.bundleChrooted) return resolveCorpusAbsolute(rest, opts.corpusRoot ?? null);\n return { state: 'resolved', path: normalizeAbsolute(rest) };\n }\n if (raw.startsWith('/')) {\n const corpusRoot = opts.corpusRoot ?? null;\n if (corpusRoot !== null) {\n // Clamp the corpus-relative half FIRST (the virtual FS is closed — `/../x`\n // stays inside the corpus), THEN anchor it at the corpus root.\n return resolveCorpusAbsolute(raw, corpusRoot);\n }\n return { state: 'resolved', path: normalizeAbsolute(raw) };\n }\n // Relative: against the authoring file's directory — the same in both spaces.\n if (!opts.currentFile) return { state: 'unresolvable' };\n const dir = opts.currentFile.slice(0, opts.currentFile.lastIndexOf('/'));\n return { state: 'resolved', path: normalizeAbsolute(`${dir}/${raw}`) };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA,mBAA8B;AAEvB,MAAM,YAAY;AA+BlB,MAAM,uBAAmB,4BAAyB;AAAA,EACvD,YAAY;AAAA,EACZ,gBAAgB;AAClB,CAAC;AAKM,MAAM,oBAAoB,CAAC,SAAyB;AACzD,QAAM,MAAgB,CAAC;AACvB,aAAW,OAAO,KAAK,MAAM,GAAG,GAAG;AACjC,QAAI,QAAQ,MAAM,QAAQ,IAAK;AAC/B,QAAI,QAAQ,KAAM,KAAI,IAAI;AAAA,QACrB,KAAI,KAAK,GAAG;AAAA,EACnB;AACA,SAAO,MAAM,IAAI,KAAK,GAAG;AAC3B;AAgBA,SAAS,sBAAsB,MAAc,YAA+C;AAC1F,QAAM,QAAQ,kBAAkB,IAAI;AACpC,MAAI,eAAe,QAAQ,eAAe,IAAK,QAAO,EAAE,OAAO,YAAY,MAAM,MAAM;AACvF,SAAO,EAAE,OAAO,YAAY,MAAM,kBAAkB,aAAa,KAAK,EAAE;AAC1E;AAQO,SAAS,kBACd,KACA,OAMI,CAAC,GACe;AACpB,MAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,UAAM,OAAO,IAAI,MAAM,UAAU,MAAM;AAGvC,QAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO,EAAE,OAAO,UAAU;AAMrD,QAAI,KAAK,eAAgB,QAAO,sBAAsB,MAAM,KAAK,cAAc,IAAI;AACnF,WAAO,EAAE,OAAO,YAAY,MAAM,kBAAkB,IAAI,EAAE;AAAA,EAC5D;AACA,MAAI,IAAI,WAAW,GAAG,GAAG;AACvB,UAAM,aAAa,KAAK,cAAc;AACtC,QAAI,eAAe,MAAM;AAGvB,aAAO,sBAAsB,KAAK,UAAU;AAAA,IAC9C;AACA,WAAO,EAAE,OAAO,YAAY,MAAM,kBAAkB,GAAG,EAAE;AAAA,EAC3D;AAEA,MAAI,CAAC,KAAK,YAAa,QAAO,EAAE,OAAO,eAAe;AACtD,QAAM,MAAM,KAAK,YAAY,MAAM,GAAG,KAAK,YAAY,YAAY,GAAG,CAAC;AACvE,SAAO,EAAE,OAAO,YAAY,MAAM,kBAAkB,GAAG,GAAG,IAAI,GAAG,EAAE,EAAE;AACvE;","names":[]}
|
package/dist/linkSpace.d.cts
CHANGED
|
@@ -5,6 +5,26 @@ interface LinkSpace {
|
|
|
5
5
|
/** Absolute filesystem path of the enclosing corpus's root (e.g. `/app/content`),
|
|
6
6
|
* or `null` when the document is not corpus-hosted (default). */
|
|
7
7
|
corpusRoot: string | null;
|
|
8
|
+
/**
|
|
9
|
+
* True when the filesystem this document resolves against is **chroot'd to the
|
|
10
|
+
* bundle** — i.e. the port the app holds was scoped to the bundle's subtree, so
|
|
11
|
+
* the mount root and the bundle root are the same directory
|
|
12
|
+
* (`BUNDLE_LAYERS_SPEC §9`; the `T2`/`T4` wrapper, R3-319 / BL-2).
|
|
13
|
+
*
|
|
14
|
+
* Under that grant `$fs:` **collapses to the scoped root**: `$fs:/p` and `/p`
|
|
15
|
+
* name the same byte, because there is no longer any "mount-absolute" space
|
|
16
|
+
* outside the bundle for `$fs:` to reach into. Without this flag the resolver
|
|
17
|
+
* would hand back a mount-absolute path that the chroot then re-roots anyway —
|
|
18
|
+
* a link that renders as valid and resolves somewhere the author did not mean.
|
|
19
|
+
*
|
|
20
|
+
* **This is an invariant to CREATE, not one to inherit** (`BUNDLE_LAYERS_SPEC
|
|
21
|
+
* §11`): the shipped resolver reads `{currentFile, corpusRoot}` and nothing
|
|
22
|
+
* else, so `$fs:` is bundle-anchored only if something says so. It lives here,
|
|
23
|
+
* in the resolver, rather than as a rule each caller applies by passing
|
|
24
|
+
* `corpusRoot: '/'` — an invariant the arithmetic carries cannot be forgotten
|
|
25
|
+
* at one call site out of five.
|
|
26
|
+
*/
|
|
27
|
+
bundleChrooted?: boolean;
|
|
8
28
|
}
|
|
9
29
|
/** Ambient link space. A corpus-rendering app wraps its document tree in
|
|
10
30
|
* `<LinkSpaceContext value={{ corpusRoot }}>`; nesting a second provider inside a
|
|
@@ -39,6 +59,9 @@ type ResolvedLinkTarget =
|
|
|
39
59
|
declare function resolveLinkTarget(raw: string, opts?: {
|
|
40
60
|
currentFile?: string;
|
|
41
61
|
corpusRoot?: string | null;
|
|
62
|
+
/** See `LinkSpace.bundleChrooted`. Under a bundle-chroot'd grant `$fs:`
|
|
63
|
+
* resolves in the corpus space, because they are the same space. */
|
|
64
|
+
bundleChrooted?: boolean;
|
|
42
65
|
}): ResolvedLinkTarget;
|
|
43
66
|
|
|
44
67
|
export { FS_PREFIX, type LinkSpace, LinkSpaceContext, type ResolvedLinkTarget, normalizeAbsolute, resolveLinkTarget };
|