@immediately-run/sdk 0.7.0 → 0.8.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/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/netFetch.cjs +12 -2
- package/dist/netFetch.cjs.map +1 -1
- package/dist/netFetch.d.cts +48 -1
- package/dist/netFetch.d.ts +48 -1
- package/dist/netFetch.js +10 -1
- package/dist/netFetch.js.map +1 -1
- package/dist/secrets.cjs +63 -0
- package/dist/secrets.cjs.map +1 -0
- package/dist/secrets.d.cts +83 -0
- package/dist/secrets.d.ts +83 -0
- package/dist/secrets.js +34 -0
- package/dist/secrets.js.map +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ __reExport(index_exports, require("./contribute"), module.exports);
|
|
|
31
31
|
__reExport(index_exports, require("./catalog"), module.exports);
|
|
32
32
|
__reExport(index_exports, require("./ipc"), module.exports);
|
|
33
33
|
__reExport(index_exports, require("./netFetch"), module.exports);
|
|
34
|
+
__reExport(index_exports, require("./secrets"), module.exports);
|
|
34
35
|
__reExport(index_exports, require("./tasks"), module.exports);
|
|
35
36
|
__reExport(index_exports, require("./runtime"), module.exports);
|
|
36
37
|
__reExport(index_exports, require("./protocolStream"), module.exports);
|
|
@@ -53,6 +54,7 @@ __reExport(index_exports, require("./sandboxTypes"), module.exports);
|
|
|
53
54
|
...require("./catalog"),
|
|
54
55
|
...require("./ipc"),
|
|
55
56
|
...require("./netFetch"),
|
|
57
|
+
...require("./secrets"),
|
|
56
58
|
...require("./tasks"),
|
|
57
59
|
...require("./runtime"),
|
|
58
60
|
...require("./protocolStream"),
|
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';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './netFetch';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAIA,0BAAc,uCAJd;AAKA,0BAAc,oBALd;AAMA,0BAAc,mBANd;AAOA,0BAAc,oBAPd;AAQA,0BAAc,4BARd;AASA,0BAAc,qBATd;AAUA,0BAAc,yBAVd;AAWA,0BAAc,qBAXd;AAYA,0BAAc,yBAZd;AAaA,0BAAc,sBAbd;AAcA,0BAAc,kBAdd;AAeA,0BAAc,uBAfd;AAgBA,0BAAc,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./MDXProvider\";\nexport * from \"./routing\";\nexport * from \"./boot\";\nexport * from './components/Include';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,0BAAd;AACA,0BAAc,sBADd;AAEA,0BAAc,mBAFd;AAGA,0BAAc,iCAHd;AAIA,0BAAc,uCAJd;AAKA,0BAAc,oBALd;AAMA,0BAAc,mBANd;AAOA,0BAAc,oBAPd;AAQA,0BAAc,4BARd;AASA,0BAAc,qBATd;AAUA,0BAAc,yBAVd;AAWA,0BAAc,qBAXd;AAYA,0BAAc,yBAZd;AAaA,0BAAc,sBAbd;AAcA,0BAAc,kBAdd;AAeA,0BAAc,uBAfd;AAgBA,0BAAc,sBAhBd;AAiBA,0BAAc,oBAjBd;AAkBA,0BAAc,sBAlBd;AAmBA,0BAAc,6BAnBd;AAoBA,0BAAc,2BApBd;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -13,7 +13,8 @@ export { GrantRecord, Member, MountQuery, ResolvedUser, Role, SandboxMount, Spac
|
|
|
13
13
|
export { ContributeMode, ContributeOptions, ContributionEvent, ContributionResult, contribute } from './contribute.cjs';
|
|
14
14
|
export { ApiMethod, getCatalog, invoke, invokeStream, onCatalogChange, useCatalog } from './catalog.cjs';
|
|
15
15
|
export { RegionMessage, onRegionMessage, postToRegion, useRegionMessage } from './ipc.cjs';
|
|
16
|
-
export { HostFetchInit, HostFetchResponse, hostFetch } from './netFetch.cjs';
|
|
16
|
+
export { HostFetchInit, HostFetchResponse, HostFetchStreamEvent, HostFetchStreamResult, hostFetch, hostFetchStream } from './netFetch.cjs';
|
|
17
|
+
export { SecretError, SecretGrant, SecretHints, SecretQuery, SecretType, SecretView, getSecrets, onSecretsChange, requestAddSecret, requestSecret, revokeSecret, useSecrets } from './secrets.cjs';
|
|
17
18
|
export { FileCap, TaskInput, cancelTask, capFile, completeTask, getTaskInput, invokeTask, useTaskInput } from './tasks.cjs';
|
|
18
19
|
export { SDK_PROTOCOL_VERSION, SDK_VERSION, SdkHandshake, announceHandshake, sdkHandshake } from './runtime.cjs';
|
|
19
20
|
export { StreamError, StreamFrame, StreamTransport, consumeStream, protocolStream } from './protocolStream.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,8 @@ export { GrantRecord, Member, MountQuery, ResolvedUser, Role, SandboxMount, Spac
|
|
|
13
13
|
export { ContributeMode, ContributeOptions, ContributionEvent, ContributionResult, contribute } from './contribute.js';
|
|
14
14
|
export { ApiMethod, getCatalog, invoke, invokeStream, onCatalogChange, useCatalog } from './catalog.js';
|
|
15
15
|
export { RegionMessage, onRegionMessage, postToRegion, useRegionMessage } from './ipc.js';
|
|
16
|
-
export { HostFetchInit, HostFetchResponse, hostFetch } from './netFetch.js';
|
|
16
|
+
export { HostFetchInit, HostFetchResponse, HostFetchStreamEvent, HostFetchStreamResult, hostFetch, hostFetchStream } from './netFetch.js';
|
|
17
|
+
export { SecretError, SecretGrant, SecretHints, SecretQuery, SecretType, SecretView, getSecrets, onSecretsChange, requestAddSecret, requestSecret, revokeSecret, useSecrets } from './secrets.js';
|
|
17
18
|
export { FileCap, TaskInput, cancelTask, capFile, completeTask, getTaskInput, invokeTask, useTaskInput } from './tasks.js';
|
|
18
19
|
export { SDK_PROTOCOL_VERSION, SDK_VERSION, SdkHandshake, announceHandshake, sdkHandshake } from './runtime.js';
|
|
19
20
|
export { StreamError, StreamFrame, StreamTransport, consumeStream, protocolStream } from './protocolStream.js';
|
package/dist/index.js
CHANGED
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';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './netFetch';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":"AAAA,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';\nexport * from './components/MDXComponents';\nexport * from './hooks'\nexport * from './auth';\nexport * from './theme';\nexport * from './editorContext';\nexport * from './editor';\nexport * from './formFactor';\nexport * from './mounts';\nexport * from './contribute';\nexport * from './catalog';\nexport * from './ipc';\nexport * from './netFetch';\nexport * from './secrets';\nexport * from './tasks';\nexport * from './runtime';\nexport * from './protocolStream';\nexport * from './sandboxTypes';\n"],"mappings":"AAAA,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/netFetch.cjs
CHANGED
|
@@ -18,10 +18,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var netFetch_exports = {};
|
|
20
20
|
__export(netFetch_exports, {
|
|
21
|
-
hostFetch: () => hostFetch
|
|
21
|
+
hostFetch: () => hostFetch,
|
|
22
|
+
hostFetchStream: () => hostFetchStream
|
|
22
23
|
});
|
|
23
24
|
module.exports = __toCommonJS(netFetch_exports);
|
|
24
25
|
var import_sandboxUtils = require("./sandboxUtils");
|
|
26
|
+
var import_protocolStream = require("./protocolStream");
|
|
25
27
|
const hostFetch = async (url, init = {}) => {
|
|
26
28
|
const res = await (0, import_sandboxUtils.protocolRequest)("fetch", "fetch", [
|
|
27
29
|
{ url, method: init.method, headers: init.headers, body: init.body }
|
|
@@ -33,8 +35,16 @@ const hostFetch = async (url, init = {}) => {
|
|
|
33
35
|
}
|
|
34
36
|
return res.data;
|
|
35
37
|
};
|
|
38
|
+
function hostFetchStream(url, init = {}) {
|
|
39
|
+
return (0, import_protocolStream.protocolStream)(
|
|
40
|
+
"protocol-fetch",
|
|
41
|
+
"fetchStream",
|
|
42
|
+
[{ url, method: init.method, headers: init.headers, body: init.body }]
|
|
43
|
+
);
|
|
44
|
+
}
|
|
36
45
|
// Annotate the CommonJS export names for ESM import in node:
|
|
37
46
|
0 && (module.exports = {
|
|
38
|
-
hostFetch
|
|
47
|
+
hostFetch,
|
|
48
|
+
hostFetchStream
|
|
39
49
|
});
|
|
40
50
|
//# sourceMappingURL=netFetch.cjs.map
|
package/dist/netFetch.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/netFetch.ts"],"sourcesContent":["// hostFetch — the app-facing side of the §5.11 parent-fetch proxy. The app calls\n// `hostFetch(url, init)`; the HOST performs the fetch with its real origin, but\n// only after validating `url` against your manifest's\n// `requests.\"net:fetch\".hosts` ∩ the user's consented hosts, blocking SSRF\n// targets, omitting immediately.run credentials, refusing redirects, and bounding\n// the response size. No raw network handle ever crosses the boundary (§8.10) —\n// only the serialized response.\n\nimport { protocolRequest } from './sandboxUtils';\n\nexport interface HostFetchInit {\n method?: string;\n headers?: Record<string, string>;\n /** Request body for non-GET/HEAD methods (string). */\n body?: string;\n}\n\nexport interface HostFetchResponse {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n body: string;\n /** True if the body hit the host's size cap and was truncated. */\n truncated: boolean;\n}\n\n/**\n * Fetch through the host's parent-fetch proxy (§5.11). Requires the `net:fetch`\n * capability with `url`'s origin in your effective allowlist (manifest ∩ the\n * user's consent) — both are arranged at load via the consent screen.\n *\n * A reachable server's reply (including a non-2xx status) RESOLVES — inspect\n * `.status`. A gate/SSRF/transport failure REJECTS with an {@link Error} carrying\n * a machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),\n * `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),\n * `too-large`, or `network`.\n */\nexport const hostFetch = async (\n url: string,\n init: HostFetchInit = {},\n): Promise<HostFetchResponse> => {\n const res = (await protocolRequest('fetch', 'fetch', [\n { url, method: init.method, headers: init.headers, body: init.body },\n ])) as\n | { ok: true; data: HostFetchResponse }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'hostFetch failed') as Error & { code?: string };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n return res.data;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,0BAAgC;
|
|
1
|
+
{"version":3,"sources":["../src/netFetch.ts"],"sourcesContent":["// hostFetch — the app-facing side of the §5.11 parent-fetch proxy. The app calls\n// `hostFetch(url, init)`; the HOST performs the fetch with its real origin, but\n// only after validating `url` against your manifest's\n// `requests.\"net:fetch\".hosts` ∩ the user's consented hosts, blocking SSRF\n// targets, omitting immediately.run credentials, refusing redirects, and bounding\n// the response size. No raw network handle ever crosses the boundary (§8.10) —\n// only the serialized response.\n\nimport { protocolRequest } from './sandboxUtils';\nimport { protocolStream } from './protocolStream';\n\nexport interface HostFetchInit {\n method?: string;\n headers?: Record<string, string>;\n /** Request body for non-GET/HEAD methods (string). */\n body?: string;\n}\n\nexport interface HostFetchResponse {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n body: string;\n /** True if the body hit the host's size cap and was truncated. */\n truncated: boolean;\n}\n\n/**\n * Fetch through the host's parent-fetch proxy (§5.11). Requires the `net:fetch`\n * capability with `url`'s origin in your effective allowlist (manifest ∩ the\n * user's consent) — both are arranged at load via the consent screen.\n *\n * A reachable server's reply (including a non-2xx status) RESOLVES — inspect\n * `.status`. A gate/SSRF/transport failure REJECTS with an {@link Error} carrying\n * a machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),\n * `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),\n * `too-large`, or `network`.\n */\nexport const hostFetch = async (\n url: string,\n init: HostFetchInit = {},\n): Promise<HostFetchResponse> => {\n const res = (await protocolRequest('fetch', 'fetch', [\n { url, method: init.method, headers: init.headers, body: init.body },\n ])) as\n | { ok: true; data: HostFetchResponse }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'hostFetch failed') as Error & { code?: string };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n return res.data;\n};\n\n/** One streamed slice of the response body (a chunk as it arrives from the\n * host). Concatenate `.chunk` across the stream to rebuild the body. */\nexport interface HostFetchStreamEvent {\n chunk: string;\n}\n\n/** The terminal value of a {@link hostFetchStream} run — the response metadata,\n * delivered once after the last body chunk. There is no `body` field: the body\n * arrived as the stream of {@link HostFetchStreamEvent}s. */\nexport interface HostFetchStreamResult {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n /** True if the stream hit the host's cumulative byte cap and was truncated. */\n truncated: boolean;\n /** Total decoded body bytes delivered. */\n bytes: number;\n}\n\n/**\n * Stream a response through the host's parent-fetch proxy (§5.11 streaming;\n * `LLM_AND_AGENTS_SPEC §2.2`) — the streaming counterpart of {@link hostFetch},\n * for SSE / LLM token streaming. Same `net:fetch` gate (manifest ∩ consent),\n * same credential-less rule and per-hop SSRF re-check; the response body is\n * pumped as a sequence of {@link HostFetchStreamEvent} chunks instead of a single\n * buffered reply.\n *\n * ```ts\n * let body = '';\n * for await (const { chunk } of hostFetchStream(url, { method: 'POST', body })) {\n * body += chunk; // e.g. parse SSE / token deltas as they arrive\n * }\n * ```\n *\n * The generator **returns** a {@link HostFetchStreamResult} (status + headers +\n * `truncated`/`bytes`) when the body completes. A gate/SSRF/transport failure —\n * or one of the host's stream bounds — **throws** a `StreamError` (from\n * `./protocolStream`) carrying a\n * machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),\n * `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),\n * `idle-timeout` / `total-timeout` (the host's stream bounds), `byte-cap`, or\n * `network`. The stream is bounded by the host's idle/total timeouts and a\n * cumulative byte cap, so it cannot be used as an unbounded transfer channel.\n *\n * Requires the host to implement the `protocol-fetch` streaming emitter; until\n * that lands a streaming request fails with `not-streamable` and callers should\n * fall back to {@link hostFetch} (`LLM_AND_AGENTS_SPEC §2.2`, roadmap P3-71).\n */\nexport function hostFetchStream(\n url: string,\n init: HostFetchInit = {},\n): AsyncGenerator<HostFetchStreamEvent, HostFetchStreamResult, void> {\n return protocolStream<HostFetchStreamEvent, HostFetchStreamResult>(\n 'protocol-fetch',\n 'fetchStream',\n [{ url, method: init.method, headers: init.headers, body: init.body }],\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,0BAAgC;AAChC,4BAA+B;AA6BxB,MAAM,YAAY,OACvB,KACA,OAAsB,CAAC,MACQ;AAC/B,QAAM,MAAO,UAAM,qCAAgB,SAAS,SAAS;AAAA,IACnD,EAAE,KAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,MAAM,KAAK,KAAK;AAAA,EACrE,CAAC;AAID,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,kBAAkB;AACxD,QAAI,QAAQ,OAAO,UAAU,MAAM,IAAI,OAAO,WAAc;AAC5D,UAAM;AAAA,EACR;AACA,SAAO,IAAI;AACb;AAkDO,SAAS,gBACd,KACA,OAAsB,CAAC,GAC4C;AACnE,aAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC,EAAE,KAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,MAAM,KAAK,KAAK,CAAC;AAAA,EACvE;AACF;","names":[]}
|
package/dist/netFetch.d.cts
CHANGED
|
@@ -24,5 +24,52 @@ interface HostFetchResponse {
|
|
|
24
24
|
* `too-large`, or `network`.
|
|
25
25
|
*/
|
|
26
26
|
declare const hostFetch: (url: string, init?: HostFetchInit) => Promise<HostFetchResponse>;
|
|
27
|
+
/** One streamed slice of the response body (a chunk as it arrives from the
|
|
28
|
+
* host). Concatenate `.chunk` across the stream to rebuild the body. */
|
|
29
|
+
interface HostFetchStreamEvent {
|
|
30
|
+
chunk: string;
|
|
31
|
+
}
|
|
32
|
+
/** The terminal value of a {@link hostFetchStream} run — the response metadata,
|
|
33
|
+
* delivered once after the last body chunk. There is no `body` field: the body
|
|
34
|
+
* arrived as the stream of {@link HostFetchStreamEvent}s. */
|
|
35
|
+
interface HostFetchStreamResult {
|
|
36
|
+
status: number;
|
|
37
|
+
statusText: string;
|
|
38
|
+
headers: Record<string, string>;
|
|
39
|
+
/** True if the stream hit the host's cumulative byte cap and was truncated. */
|
|
40
|
+
truncated: boolean;
|
|
41
|
+
/** Total decoded body bytes delivered. */
|
|
42
|
+
bytes: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Stream a response through the host's parent-fetch proxy (§5.11 streaming;
|
|
46
|
+
* `LLM_AND_AGENTS_SPEC §2.2`) — the streaming counterpart of {@link hostFetch},
|
|
47
|
+
* for SSE / LLM token streaming. Same `net:fetch` gate (manifest ∩ consent),
|
|
48
|
+
* same credential-less rule and per-hop SSRF re-check; the response body is
|
|
49
|
+
* pumped as a sequence of {@link HostFetchStreamEvent} chunks instead of a single
|
|
50
|
+
* buffered reply.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* let body = '';
|
|
54
|
+
* for await (const { chunk } of hostFetchStream(url, { method: 'POST', body })) {
|
|
55
|
+
* body += chunk; // e.g. parse SSE / token deltas as they arrive
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* The generator **returns** a {@link HostFetchStreamResult} (status + headers +
|
|
60
|
+
* `truncated`/`bytes`) when the body completes. A gate/SSRF/transport failure —
|
|
61
|
+
* or one of the host's stream bounds — **throws** a `StreamError` (from
|
|
62
|
+
* `./protocolStream`) carrying a
|
|
63
|
+
* machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),
|
|
64
|
+
* `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),
|
|
65
|
+
* `idle-timeout` / `total-timeout` (the host's stream bounds), `byte-cap`, or
|
|
66
|
+
* `network`. The stream is bounded by the host's idle/total timeouts and a
|
|
67
|
+
* cumulative byte cap, so it cannot be used as an unbounded transfer channel.
|
|
68
|
+
*
|
|
69
|
+
* Requires the host to implement the `protocol-fetch` streaming emitter; until
|
|
70
|
+
* that lands a streaming request fails with `not-streamable` and callers should
|
|
71
|
+
* fall back to {@link hostFetch} (`LLM_AND_AGENTS_SPEC §2.2`, roadmap P3-71).
|
|
72
|
+
*/
|
|
73
|
+
declare function hostFetchStream(url: string, init?: HostFetchInit): AsyncGenerator<HostFetchStreamEvent, HostFetchStreamResult, void>;
|
|
27
74
|
|
|
28
|
-
export { type HostFetchInit, type HostFetchResponse, hostFetch };
|
|
75
|
+
export { type HostFetchInit, type HostFetchResponse, type HostFetchStreamEvent, type HostFetchStreamResult, hostFetch, hostFetchStream };
|
package/dist/netFetch.d.ts
CHANGED
|
@@ -24,5 +24,52 @@ interface HostFetchResponse {
|
|
|
24
24
|
* `too-large`, or `network`.
|
|
25
25
|
*/
|
|
26
26
|
declare const hostFetch: (url: string, init?: HostFetchInit) => Promise<HostFetchResponse>;
|
|
27
|
+
/** One streamed slice of the response body (a chunk as it arrives from the
|
|
28
|
+
* host). Concatenate `.chunk` across the stream to rebuild the body. */
|
|
29
|
+
interface HostFetchStreamEvent {
|
|
30
|
+
chunk: string;
|
|
31
|
+
}
|
|
32
|
+
/** The terminal value of a {@link hostFetchStream} run — the response metadata,
|
|
33
|
+
* delivered once after the last body chunk. There is no `body` field: the body
|
|
34
|
+
* arrived as the stream of {@link HostFetchStreamEvent}s. */
|
|
35
|
+
interface HostFetchStreamResult {
|
|
36
|
+
status: number;
|
|
37
|
+
statusText: string;
|
|
38
|
+
headers: Record<string, string>;
|
|
39
|
+
/** True if the stream hit the host's cumulative byte cap and was truncated. */
|
|
40
|
+
truncated: boolean;
|
|
41
|
+
/** Total decoded body bytes delivered. */
|
|
42
|
+
bytes: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Stream a response through the host's parent-fetch proxy (§5.11 streaming;
|
|
46
|
+
* `LLM_AND_AGENTS_SPEC §2.2`) — the streaming counterpart of {@link hostFetch},
|
|
47
|
+
* for SSE / LLM token streaming. Same `net:fetch` gate (manifest ∩ consent),
|
|
48
|
+
* same credential-less rule and per-hop SSRF re-check; the response body is
|
|
49
|
+
* pumped as a sequence of {@link HostFetchStreamEvent} chunks instead of a single
|
|
50
|
+
* buffered reply.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* let body = '';
|
|
54
|
+
* for await (const { chunk } of hostFetchStream(url, { method: 'POST', body })) {
|
|
55
|
+
* body += chunk; // e.g. parse SSE / token deltas as they arrive
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* The generator **returns** a {@link HostFetchStreamResult} (status + headers +
|
|
60
|
+
* `truncated`/`bytes`) when the body completes. A gate/SSRF/transport failure —
|
|
61
|
+
* or one of the host's stream bounds — **throws** a `StreamError` (from
|
|
62
|
+
* `./protocolStream`) carrying a
|
|
63
|
+
* machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),
|
|
64
|
+
* `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),
|
|
65
|
+
* `idle-timeout` / `total-timeout` (the host's stream bounds), `byte-cap`, or
|
|
66
|
+
* `network`. The stream is bounded by the host's idle/total timeouts and a
|
|
67
|
+
* cumulative byte cap, so it cannot be used as an unbounded transfer channel.
|
|
68
|
+
*
|
|
69
|
+
* Requires the host to implement the `protocol-fetch` streaming emitter; until
|
|
70
|
+
* that lands a streaming request fails with `not-streamable` and callers should
|
|
71
|
+
* fall back to {@link hostFetch} (`LLM_AND_AGENTS_SPEC §2.2`, roadmap P3-71).
|
|
72
|
+
*/
|
|
73
|
+
declare function hostFetchStream(url: string, init?: HostFetchInit): AsyncGenerator<HostFetchStreamEvent, HostFetchStreamResult, void>;
|
|
27
74
|
|
|
28
|
-
export { type HostFetchInit, type HostFetchResponse, hostFetch };
|
|
75
|
+
export { type HostFetchInit, type HostFetchResponse, type HostFetchStreamEvent, type HostFetchStreamResult, hostFetch, hostFetchStream };
|
package/dist/netFetch.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { protocolRequest } from "./sandboxUtils";
|
|
2
|
+
import { protocolStream } from "./protocolStream";
|
|
2
3
|
const hostFetch = async (url, init = {}) => {
|
|
3
4
|
const res = await protocolRequest("fetch", "fetch", [
|
|
4
5
|
{ url, method: init.method, headers: init.headers, body: init.body }
|
|
@@ -10,7 +11,15 @@ const hostFetch = async (url, init = {}) => {
|
|
|
10
11
|
}
|
|
11
12
|
return res.data;
|
|
12
13
|
};
|
|
14
|
+
function hostFetchStream(url, init = {}) {
|
|
15
|
+
return protocolStream(
|
|
16
|
+
"protocol-fetch",
|
|
17
|
+
"fetchStream",
|
|
18
|
+
[{ url, method: init.method, headers: init.headers, body: init.body }]
|
|
19
|
+
);
|
|
20
|
+
}
|
|
13
21
|
export {
|
|
14
|
-
hostFetch
|
|
22
|
+
hostFetch,
|
|
23
|
+
hostFetchStream
|
|
15
24
|
};
|
|
16
25
|
//# sourceMappingURL=netFetch.js.map
|
package/dist/netFetch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/netFetch.ts"],"sourcesContent":["// hostFetch — the app-facing side of the §5.11 parent-fetch proxy. The app calls\n// `hostFetch(url, init)`; the HOST performs the fetch with its real origin, but\n// only after validating `url` against your manifest's\n// `requests.\"net:fetch\".hosts` ∩ the user's consented hosts, blocking SSRF\n// targets, omitting immediately.run credentials, refusing redirects, and bounding\n// the response size. No raw network handle ever crosses the boundary (§8.10) —\n// only the serialized response.\n\nimport { protocolRequest } from './sandboxUtils';\n\nexport interface HostFetchInit {\n method?: string;\n headers?: Record<string, string>;\n /** Request body for non-GET/HEAD methods (string). */\n body?: string;\n}\n\nexport interface HostFetchResponse {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n body: string;\n /** True if the body hit the host's size cap and was truncated. */\n truncated: boolean;\n}\n\n/**\n * Fetch through the host's parent-fetch proxy (§5.11). Requires the `net:fetch`\n * capability with `url`'s origin in your effective allowlist (manifest ∩ the\n * user's consent) — both are arranged at load via the consent screen.\n *\n * A reachable server's reply (including a non-2xx status) RESOLVES — inspect\n * `.status`. A gate/SSRF/transport failure REJECTS with an {@link Error} carrying\n * a machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),\n * `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),\n * `too-large`, or `network`.\n */\nexport const hostFetch = async (\n url: string,\n init: HostFetchInit = {},\n): Promise<HostFetchResponse> => {\n const res = (await protocolRequest('fetch', 'fetch', [\n { url, method: init.method, headers: init.headers, body: init.body },\n ])) as\n | { ok: true; data: HostFetchResponse }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'hostFetch failed') as Error & { code?: string };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n return res.data;\n};\n"],"mappings":"AAQA,SAAS,uBAAuB;
|
|
1
|
+
{"version":3,"sources":["../src/netFetch.ts"],"sourcesContent":["// hostFetch — the app-facing side of the §5.11 parent-fetch proxy. The app calls\n// `hostFetch(url, init)`; the HOST performs the fetch with its real origin, but\n// only after validating `url` against your manifest's\n// `requests.\"net:fetch\".hosts` ∩ the user's consented hosts, blocking SSRF\n// targets, omitting immediately.run credentials, refusing redirects, and bounding\n// the response size. No raw network handle ever crosses the boundary (§8.10) —\n// only the serialized response.\n\nimport { protocolRequest } from './sandboxUtils';\nimport { protocolStream } from './protocolStream';\n\nexport interface HostFetchInit {\n method?: string;\n headers?: Record<string, string>;\n /** Request body for non-GET/HEAD methods (string). */\n body?: string;\n}\n\nexport interface HostFetchResponse {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n body: string;\n /** True if the body hit the host's size cap and was truncated. */\n truncated: boolean;\n}\n\n/**\n * Fetch through the host's parent-fetch proxy (§5.11). Requires the `net:fetch`\n * capability with `url`'s origin in your effective allowlist (manifest ∩ the\n * user's consent) — both are arranged at load via the consent screen.\n *\n * A reachable server's reply (including a non-2xx status) RESOLVES — inspect\n * `.status`. A gate/SSRF/transport failure REJECTS with an {@link Error} carrying\n * a machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),\n * `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),\n * `too-large`, or `network`.\n */\nexport const hostFetch = async (\n url: string,\n init: HostFetchInit = {},\n): Promise<HostFetchResponse> => {\n const res = (await protocolRequest('fetch', 'fetch', [\n { url, method: init.method, headers: init.headers, body: init.body },\n ])) as\n | { ok: true; data: HostFetchResponse }\n | { ok: false; code?: string; message?: string }\n | undefined;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'hostFetch failed') as Error & { code?: string };\n err.code = (res && 'code' in res ? res.code : undefined) ?? 'unknown';\n throw err;\n }\n return res.data;\n};\n\n/** One streamed slice of the response body (a chunk as it arrives from the\n * host). Concatenate `.chunk` across the stream to rebuild the body. */\nexport interface HostFetchStreamEvent {\n chunk: string;\n}\n\n/** The terminal value of a {@link hostFetchStream} run — the response metadata,\n * delivered once after the last body chunk. There is no `body` field: the body\n * arrived as the stream of {@link HostFetchStreamEvent}s. */\nexport interface HostFetchStreamResult {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n /** True if the stream hit the host's cumulative byte cap and was truncated. */\n truncated: boolean;\n /** Total decoded body bytes delivered. */\n bytes: number;\n}\n\n/**\n * Stream a response through the host's parent-fetch proxy (§5.11 streaming;\n * `LLM_AND_AGENTS_SPEC §2.2`) — the streaming counterpart of {@link hostFetch},\n * for SSE / LLM token streaming. Same `net:fetch` gate (manifest ∩ consent),\n * same credential-less rule and per-hop SSRF re-check; the response body is\n * pumped as a sequence of {@link HostFetchStreamEvent} chunks instead of a single\n * buffered reply.\n *\n * ```ts\n * let body = '';\n * for await (const { chunk } of hostFetchStream(url, { method: 'POST', body })) {\n * body += chunk; // e.g. parse SSE / token deltas as they arrive\n * }\n * ```\n *\n * The generator **returns** a {@link HostFetchStreamResult} (status + headers +\n * `truncated`/`bytes`) when the body completes. A gate/SSRF/transport failure —\n * or one of the host's stream bounds — **throws** a `StreamError` (from\n * `./protocolStream`) carrying a\n * machine `.code`: `forbidden` (outside the allowlist), `blocked` (SSRF target),\n * `invalid` (bad url/scheme), `redirect` (the host refuses to follow redirects),\n * `idle-timeout` / `total-timeout` (the host's stream bounds), `byte-cap`, or\n * `network`. The stream is bounded by the host's idle/total timeouts and a\n * cumulative byte cap, so it cannot be used as an unbounded transfer channel.\n *\n * Requires the host to implement the `protocol-fetch` streaming emitter; until\n * that lands a streaming request fails with `not-streamable` and callers should\n * fall back to {@link hostFetch} (`LLM_AND_AGENTS_SPEC §2.2`, roadmap P3-71).\n */\nexport function hostFetchStream(\n url: string,\n init: HostFetchInit = {},\n): AsyncGenerator<HostFetchStreamEvent, HostFetchStreamResult, void> {\n return protocolStream<HostFetchStreamEvent, HostFetchStreamResult>(\n 'protocol-fetch',\n 'fetchStream',\n [{ url, method: init.method, headers: init.headers, body: init.body }],\n );\n}\n"],"mappings":"AAQA,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AA6BxB,MAAM,YAAY,OACvB,KACA,OAAsB,CAAC,MACQ;AAC/B,QAAM,MAAO,MAAM,gBAAgB,SAAS,SAAS;AAAA,IACnD,EAAE,KAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,MAAM,KAAK,KAAK;AAAA,EACrE,CAAC;AAID,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,kBAAkB;AACxD,QAAI,QAAQ,OAAO,UAAU,MAAM,IAAI,OAAO,WAAc;AAC5D,UAAM;AAAA,EACR;AACA,SAAO,IAAI;AACb;AAkDO,SAAS,gBACd,KACA,OAAsB,CAAC,GAC4C;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC,EAAE,KAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,MAAM,KAAK,KAAK,CAAC;AAAA,EACvE;AACF;","names":[]}
|
package/dist/secrets.cjs
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
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 secrets_exports = {};
|
|
20
|
+
__export(secrets_exports, {
|
|
21
|
+
getSecrets: () => getSecrets,
|
|
22
|
+
onSecretsChange: () => onSecretsChange,
|
|
23
|
+
requestAddSecret: () => requestAddSecret,
|
|
24
|
+
requestSecret: () => requestSecret,
|
|
25
|
+
revokeSecret: () => revokeSecret,
|
|
26
|
+
useSecrets: () => useSecrets
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(secrets_exports);
|
|
29
|
+
var import_sandboxUtils = require("./sandboxUtils");
|
|
30
|
+
var import_pushChannel = require("./pushChannel");
|
|
31
|
+
const request = async (method, query = {}) => {
|
|
32
|
+
const res = await (0, import_sandboxUtils.protocolRequest)("secrets", method, [query]);
|
|
33
|
+
if (!res || res.ok !== true) {
|
|
34
|
+
const err = new Error(res?.message ?? "secret request failed");
|
|
35
|
+
err.code = res?.code ?? "unknown";
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
return res.data;
|
|
39
|
+
};
|
|
40
|
+
const requestAddSecret = (hints = {}) => request("add", hints);
|
|
41
|
+
const requestSecret = (query = {}) => request("request", query);
|
|
42
|
+
const revokeSecret = async (id) => {
|
|
43
|
+
await request("revoke", { id });
|
|
44
|
+
};
|
|
45
|
+
const channel = (0, import_pushChannel.createPushChannel)({
|
|
46
|
+
pushType: "secrets-metadata",
|
|
47
|
+
requestType: "request-secrets-metadata",
|
|
48
|
+
initial: [],
|
|
49
|
+
parse: (msg) => Array.isArray(msg.secrets) ? msg.secrets : void 0
|
|
50
|
+
});
|
|
51
|
+
const getSecrets = () => channel.get();
|
|
52
|
+
const onSecretsChange = (listener) => channel.onChange(listener);
|
|
53
|
+
const useSecrets = () => channel.use();
|
|
54
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
55
|
+
0 && (module.exports = {
|
|
56
|
+
getSecrets,
|
|
57
|
+
onSecretsChange,
|
|
58
|
+
requestAddSecret,
|
|
59
|
+
requestSecret,
|
|
60
|
+
revokeSecret,
|
|
61
|
+
useSecrets
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=secrets.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/secrets.ts"],"sourcesContent":["// The host-owned secret store — app-facing surface (SECRETS_SPEC §4/§5).\n//\n// An app can ASK the user to store a secret (`requestAddSecret`), be GRANTED the\n// right to USE a specific secret (`requestSecret`, the powerbox flow), LIST\n// secret METADATA (`getSecrets`/`useSecrets`, never values), and REVOKE one\n// (`revokeSecret`). The secret VALUE never crosses this boundary: it is read\n// host-side, once, at the `net:fetch` injection point (SECRETS_SPEC §6). These\n// functions move only hints, metadata, and grant handles.\n//\n// Resolves LLM_AND_AGENTS_SPEC D2 — the host-mediated BYOK key store. Inert until\n// the host implements `protocol-secrets` + the `secrets-metadata` channel\n// (SECRETS_SPEC §3/§6 host work, roadmap P1.E); the contract is shipped here so\n// apps (e.g. the in-browser coding agent, P3-73) can be written against it.\nimport { protocolRequest } from './sandboxUtils';\nimport { createPushChannel } from './pushChannel';\n\n/** The closed secret-type vocabulary (SECRETS_SPEC §2). `api-key` is always\n * origin-bound; `oauth-refresh` is reserved (no substitution in v1). */\nexport type SecretType = 'api-key' | 'bearer-token' | 'oauth-refresh';\n\n/**\n * The metadata-only projection of a stored secret (SECRETS_SPEC §2/§4) — exactly\n * what `secrets:list` and the powerbox return. **There is no `value` field by\n * design**: the plaintext is never part of any record an app receives.\n */\nexport interface SecretView {\n id: string;\n type: SecretType;\n family?: string;\n description: string;\n /** Required for `type:'api-key'` — the one https origin it may be sent to. */\n boundOrigin?: string;\n /** ISO-8601, or null if never used (drives the §8.15 90-day expiry). */\n lastUsedAt: string | null;\n}\n\n/** Hints for the host's \"add secret\" modal (SECRETS_SPEC §4 `secrets:add`). The\n * app supplies only hints; the user types the value into host chrome. */\nexport interface SecretHints {\n type?: SecretType;\n family?: string;\n /** Pre-fill the bound origin (e.g. `https://api.anthropic.com`). */\n suggestedOrigin?: string;\n description?: string;\n}\n\n/** What `requestSecret()` matches against in the powerbox picker (SECRETS_SPEC §5). */\nexport interface SecretQuery {\n type?: SecretType;\n family?: string;\n}\n\n/**\n * The result of a granted `requestSecret()` — a durable `(appKey, secretId)` use\n * grant plus the secret's metadata. **Never the value.** Hold onto nothing but\n * this; the host substitutes the value into matching `net:fetch` requests.\n */\nexport interface SecretGrant {\n /** Opaque handle for the minted `(appKey, secretId)` grant. */\n grantId: string;\n /** Metadata of the bound secret (no value). */\n secret: SecretView;\n}\n\n/** An error from a secret operation, carrying a machine-readable `code`. */\nexport interface SecretError extends Error {\n code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'invalid-params' | 'unknown';\n}\n\ntype SecretResult =\n | { ok: true; data: unknown }\n | { ok: false; code: string; message: string };\n\n// Issue a `protocol-secrets` request, unwrapping the host's {ok,data} envelope\n// and throwing a typed SecretError on failure (mirrors mounts.ts `request`).\nconst request = async <T = unknown>(\n method: string,\n query: object = {},\n): Promise<T> => {\n const res = (await protocolRequest('secrets', method, [query])) as SecretResult;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'secret request failed') as SecretError;\n err.code = (res?.code as SecretError['code']) ?? 'unknown';\n throw err;\n }\n return res.data as T;\n};\n\n/**\n * Ask the user to store a new secret (SECRETS_SPEC §4 `secrets:add`). Opens a\n * **host-drawn** modal (the value is typed into host chrome, never via the app);\n * resolves with the new secret's {@link SecretView} metadata, or rejects with a\n * {@link SecretError} (`cancelled` if the user dismisses the modal). Requires the\n * `secrets:add` capability.\n */\nexport const requestAddSecret = (hints: SecretHints = {}): Promise<SecretView> =>\n request<SecretView>('add', hints);\n\n/**\n * Ask the user to bind one of their stored secrets to this app (SECRETS_SPEC §5,\n * the powerbox flow — modeled on `requestSpace()`). The host draws a picker of\n * **only the user's matching secrets**; the user picks, declines, or creates one.\n * On success the host records a durable `(appKey, secretId)` grant and resolves\n * with a {@link SecretGrant} (handle + metadata, **never the value**).\n *\n * **No existence oracle (T20/T27):** a decline, an ungranted secret, and a\n * nonexistent secret are indistinguishable — all reject with a {@link SecretError}\n * `cancelled`; the app never sees the list it chose from.\n */\nexport const requestSecret = (query: SecretQuery = {}): Promise<SecretGrant> =>\n request<SecretGrant>('request', query);\n\n/**\n * Delete a stored secret and tombstone every dependent per-app use grant\n * (SECRETS_SPEC §4 `secrets:revoke`, §8.15 cascade). Requires `secrets:revoke`.\n */\nexport const revokeSecret = async (id: string): Promise<void> => {\n await request('revoke', { id });\n};\n\n// The metadata-only `secrets-metadata` channel (Recipe A): the host pushes the\n// current secret metadata on change and replays it on register-frame; gated by\n// `secrets:list`. NEVER carries a value (SECRETS_SPEC §4).\nconst channel = createPushChannel<SecretView[]>({\n pushType: 'secrets-metadata',\n requestType: 'request-secrets-metadata',\n initial: [],\n parse: (msg) => (Array.isArray(msg.secrets) ? (msg.secrets as SecretView[]) : undefined),\n});\n\n/** The metadata of the user's stored secrets (never values), `secrets:list`. Poll\n * for a one-off read; use {@link onSecretsChange}/{@link useSecrets} to react. */\nexport const getSecrets = (): SecretView[] => channel.get();\n\n/** Subscribe to secret-metadata changes (added/revoked). Invoked immediately with\n * the current list, then on every change. Returns an unsubscribe fn. */\nexport const onSecretsChange = (listener: (secrets: SecretView[]) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning the user's secret metadata (never values), re-rendering\n * on change. For the Settings app (SECRETS_SPEC §7). */\nexport const useSecrets = (): SecretView[] => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,0BAAgC;AAChC,yBAAkC;AA6DlC,MAAM,UAAU,OACd,QACA,QAAgB,CAAC,MACF;AACf,QAAM,MAAO,UAAM,qCAAgB,WAAW,QAAQ,CAAC,KAAK,CAAC;AAC7D,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,uBAAuB;AAC7D,QAAI,OAAQ,KAAK,QAAgC;AACjD,UAAM;AAAA,EACR;AACA,SAAO,IAAI;AACb;AASO,MAAM,mBAAmB,CAAC,QAAqB,CAAC,MACrD,QAAoB,OAAO,KAAK;AAa3B,MAAM,gBAAgB,CAAC,QAAqB,CAAC,MAClD,QAAqB,WAAW,KAAK;AAMhC,MAAM,eAAe,OAAO,OAA8B;AAC/D,QAAM,QAAQ,UAAU,EAAE,GAAG,CAAC;AAChC;AAKA,MAAM,cAAU,sCAAgC;AAAA,EAC9C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS,CAAC;AAAA,EACV,OAAO,CAAC,QAAS,MAAM,QAAQ,IAAI,OAAO,IAAK,IAAI,UAA2B;AAChF,CAAC;AAIM,MAAM,aAAa,MAAoB,QAAQ,IAAI;AAInD,MAAM,kBAAkB,CAAC,aAC9B,QAAQ,SAAS,QAAQ;AAIpB,MAAM,aAAa,MAAoB,QAAQ,IAAI;","names":[]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** The closed secret-type vocabulary (SECRETS_SPEC §2). `api-key` is always
|
|
2
|
+
* origin-bound; `oauth-refresh` is reserved (no substitution in v1). */
|
|
3
|
+
type SecretType = 'api-key' | 'bearer-token' | 'oauth-refresh';
|
|
4
|
+
/**
|
|
5
|
+
* The metadata-only projection of a stored secret (SECRETS_SPEC §2/§4) — exactly
|
|
6
|
+
* what `secrets:list` and the powerbox return. **There is no `value` field by
|
|
7
|
+
* design**: the plaintext is never part of any record an app receives.
|
|
8
|
+
*/
|
|
9
|
+
interface SecretView {
|
|
10
|
+
id: string;
|
|
11
|
+
type: SecretType;
|
|
12
|
+
family?: string;
|
|
13
|
+
description: string;
|
|
14
|
+
/** Required for `type:'api-key'` — the one https origin it may be sent to. */
|
|
15
|
+
boundOrigin?: string;
|
|
16
|
+
/** ISO-8601, or null if never used (drives the §8.15 90-day expiry). */
|
|
17
|
+
lastUsedAt: string | null;
|
|
18
|
+
}
|
|
19
|
+
/** Hints for the host's "add secret" modal (SECRETS_SPEC §4 `secrets:add`). The
|
|
20
|
+
* app supplies only hints; the user types the value into host chrome. */
|
|
21
|
+
interface SecretHints {
|
|
22
|
+
type?: SecretType;
|
|
23
|
+
family?: string;
|
|
24
|
+
/** Pre-fill the bound origin (e.g. `https://api.anthropic.com`). */
|
|
25
|
+
suggestedOrigin?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
}
|
|
28
|
+
/** What `requestSecret()` matches against in the powerbox picker (SECRETS_SPEC §5). */
|
|
29
|
+
interface SecretQuery {
|
|
30
|
+
type?: SecretType;
|
|
31
|
+
family?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The result of a granted `requestSecret()` — a durable `(appKey, secretId)` use
|
|
35
|
+
* grant plus the secret's metadata. **Never the value.** Hold onto nothing but
|
|
36
|
+
* this; the host substitutes the value into matching `net:fetch` requests.
|
|
37
|
+
*/
|
|
38
|
+
interface SecretGrant {
|
|
39
|
+
/** Opaque handle for the minted `(appKey, secretId)` grant. */
|
|
40
|
+
grantId: string;
|
|
41
|
+
/** Metadata of the bound secret (no value). */
|
|
42
|
+
secret: SecretView;
|
|
43
|
+
}
|
|
44
|
+
/** An error from a secret operation, carrying a machine-readable `code`. */
|
|
45
|
+
interface SecretError extends Error {
|
|
46
|
+
code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'invalid-params' | 'unknown';
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Ask the user to store a new secret (SECRETS_SPEC §4 `secrets:add`). Opens a
|
|
50
|
+
* **host-drawn** modal (the value is typed into host chrome, never via the app);
|
|
51
|
+
* resolves with the new secret's {@link SecretView} metadata, or rejects with a
|
|
52
|
+
* {@link SecretError} (`cancelled` if the user dismisses the modal). Requires the
|
|
53
|
+
* `secrets:add` capability.
|
|
54
|
+
*/
|
|
55
|
+
declare const requestAddSecret: (hints?: SecretHints) => Promise<SecretView>;
|
|
56
|
+
/**
|
|
57
|
+
* Ask the user to bind one of their stored secrets to this app (SECRETS_SPEC §5,
|
|
58
|
+
* the powerbox flow — modeled on `requestSpace()`). The host draws a picker of
|
|
59
|
+
* **only the user's matching secrets**; the user picks, declines, or creates one.
|
|
60
|
+
* On success the host records a durable `(appKey, secretId)` grant and resolves
|
|
61
|
+
* with a {@link SecretGrant} (handle + metadata, **never the value**).
|
|
62
|
+
*
|
|
63
|
+
* **No existence oracle (T20/T27):** a decline, an ungranted secret, and a
|
|
64
|
+
* nonexistent secret are indistinguishable — all reject with a {@link SecretError}
|
|
65
|
+
* `cancelled`; the app never sees the list it chose from.
|
|
66
|
+
*/
|
|
67
|
+
declare const requestSecret: (query?: SecretQuery) => Promise<SecretGrant>;
|
|
68
|
+
/**
|
|
69
|
+
* Delete a stored secret and tombstone every dependent per-app use grant
|
|
70
|
+
* (SECRETS_SPEC §4 `secrets:revoke`, §8.15 cascade). Requires `secrets:revoke`.
|
|
71
|
+
*/
|
|
72
|
+
declare const revokeSecret: (id: string) => Promise<void>;
|
|
73
|
+
/** The metadata of the user's stored secrets (never values), `secrets:list`. Poll
|
|
74
|
+
* for a one-off read; use {@link onSecretsChange}/{@link useSecrets} to react. */
|
|
75
|
+
declare const getSecrets: () => SecretView[];
|
|
76
|
+
/** Subscribe to secret-metadata changes (added/revoked). Invoked immediately with
|
|
77
|
+
* the current list, then on every change. Returns an unsubscribe fn. */
|
|
78
|
+
declare const onSecretsChange: (listener: (secrets: SecretView[]) => void) => (() => void);
|
|
79
|
+
/** React hook returning the user's secret metadata (never values), re-rendering
|
|
80
|
+
* on change. For the Settings app (SECRETS_SPEC §7). */
|
|
81
|
+
declare const useSecrets: () => SecretView[];
|
|
82
|
+
|
|
83
|
+
export { type SecretError, type SecretGrant, type SecretHints, type SecretQuery, type SecretType, type SecretView, getSecrets, onSecretsChange, requestAddSecret, requestSecret, revokeSecret, useSecrets };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** The closed secret-type vocabulary (SECRETS_SPEC §2). `api-key` is always
|
|
2
|
+
* origin-bound; `oauth-refresh` is reserved (no substitution in v1). */
|
|
3
|
+
type SecretType = 'api-key' | 'bearer-token' | 'oauth-refresh';
|
|
4
|
+
/**
|
|
5
|
+
* The metadata-only projection of a stored secret (SECRETS_SPEC §2/§4) — exactly
|
|
6
|
+
* what `secrets:list` and the powerbox return. **There is no `value` field by
|
|
7
|
+
* design**: the plaintext is never part of any record an app receives.
|
|
8
|
+
*/
|
|
9
|
+
interface SecretView {
|
|
10
|
+
id: string;
|
|
11
|
+
type: SecretType;
|
|
12
|
+
family?: string;
|
|
13
|
+
description: string;
|
|
14
|
+
/** Required for `type:'api-key'` — the one https origin it may be sent to. */
|
|
15
|
+
boundOrigin?: string;
|
|
16
|
+
/** ISO-8601, or null if never used (drives the §8.15 90-day expiry). */
|
|
17
|
+
lastUsedAt: string | null;
|
|
18
|
+
}
|
|
19
|
+
/** Hints for the host's "add secret" modal (SECRETS_SPEC §4 `secrets:add`). The
|
|
20
|
+
* app supplies only hints; the user types the value into host chrome. */
|
|
21
|
+
interface SecretHints {
|
|
22
|
+
type?: SecretType;
|
|
23
|
+
family?: string;
|
|
24
|
+
/** Pre-fill the bound origin (e.g. `https://api.anthropic.com`). */
|
|
25
|
+
suggestedOrigin?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
}
|
|
28
|
+
/** What `requestSecret()` matches against in the powerbox picker (SECRETS_SPEC §5). */
|
|
29
|
+
interface SecretQuery {
|
|
30
|
+
type?: SecretType;
|
|
31
|
+
family?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The result of a granted `requestSecret()` — a durable `(appKey, secretId)` use
|
|
35
|
+
* grant plus the secret's metadata. **Never the value.** Hold onto nothing but
|
|
36
|
+
* this; the host substitutes the value into matching `net:fetch` requests.
|
|
37
|
+
*/
|
|
38
|
+
interface SecretGrant {
|
|
39
|
+
/** Opaque handle for the minted `(appKey, secretId)` grant. */
|
|
40
|
+
grantId: string;
|
|
41
|
+
/** Metadata of the bound secret (no value). */
|
|
42
|
+
secret: SecretView;
|
|
43
|
+
}
|
|
44
|
+
/** An error from a secret operation, carrying a machine-readable `code`. */
|
|
45
|
+
interface SecretError extends Error {
|
|
46
|
+
code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'invalid-params' | 'unknown';
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Ask the user to store a new secret (SECRETS_SPEC §4 `secrets:add`). Opens a
|
|
50
|
+
* **host-drawn** modal (the value is typed into host chrome, never via the app);
|
|
51
|
+
* resolves with the new secret's {@link SecretView} metadata, or rejects with a
|
|
52
|
+
* {@link SecretError} (`cancelled` if the user dismisses the modal). Requires the
|
|
53
|
+
* `secrets:add` capability.
|
|
54
|
+
*/
|
|
55
|
+
declare const requestAddSecret: (hints?: SecretHints) => Promise<SecretView>;
|
|
56
|
+
/**
|
|
57
|
+
* Ask the user to bind one of their stored secrets to this app (SECRETS_SPEC §5,
|
|
58
|
+
* the powerbox flow — modeled on `requestSpace()`). The host draws a picker of
|
|
59
|
+
* **only the user's matching secrets**; the user picks, declines, or creates one.
|
|
60
|
+
* On success the host records a durable `(appKey, secretId)` grant and resolves
|
|
61
|
+
* with a {@link SecretGrant} (handle + metadata, **never the value**).
|
|
62
|
+
*
|
|
63
|
+
* **No existence oracle (T20/T27):** a decline, an ungranted secret, and a
|
|
64
|
+
* nonexistent secret are indistinguishable — all reject with a {@link SecretError}
|
|
65
|
+
* `cancelled`; the app never sees the list it chose from.
|
|
66
|
+
*/
|
|
67
|
+
declare const requestSecret: (query?: SecretQuery) => Promise<SecretGrant>;
|
|
68
|
+
/**
|
|
69
|
+
* Delete a stored secret and tombstone every dependent per-app use grant
|
|
70
|
+
* (SECRETS_SPEC §4 `secrets:revoke`, §8.15 cascade). Requires `secrets:revoke`.
|
|
71
|
+
*/
|
|
72
|
+
declare const revokeSecret: (id: string) => Promise<void>;
|
|
73
|
+
/** The metadata of the user's stored secrets (never values), `secrets:list`. Poll
|
|
74
|
+
* for a one-off read; use {@link onSecretsChange}/{@link useSecrets} to react. */
|
|
75
|
+
declare const getSecrets: () => SecretView[];
|
|
76
|
+
/** Subscribe to secret-metadata changes (added/revoked). Invoked immediately with
|
|
77
|
+
* the current list, then on every change. Returns an unsubscribe fn. */
|
|
78
|
+
declare const onSecretsChange: (listener: (secrets: SecretView[]) => void) => (() => void);
|
|
79
|
+
/** React hook returning the user's secret metadata (never values), re-rendering
|
|
80
|
+
* on change. For the Settings app (SECRETS_SPEC §7). */
|
|
81
|
+
declare const useSecrets: () => SecretView[];
|
|
82
|
+
|
|
83
|
+
export { type SecretError, type SecretGrant, type SecretHints, type SecretQuery, type SecretType, type SecretView, getSecrets, onSecretsChange, requestAddSecret, requestSecret, revokeSecret, useSecrets };
|
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { protocolRequest } from "./sandboxUtils";
|
|
2
|
+
import { createPushChannel } from "./pushChannel";
|
|
3
|
+
const request = async (method, query = {}) => {
|
|
4
|
+
const res = await protocolRequest("secrets", method, [query]);
|
|
5
|
+
if (!res || res.ok !== true) {
|
|
6
|
+
const err = new Error(res?.message ?? "secret request failed");
|
|
7
|
+
err.code = res?.code ?? "unknown";
|
|
8
|
+
throw err;
|
|
9
|
+
}
|
|
10
|
+
return res.data;
|
|
11
|
+
};
|
|
12
|
+
const requestAddSecret = (hints = {}) => request("add", hints);
|
|
13
|
+
const requestSecret = (query = {}) => request("request", query);
|
|
14
|
+
const revokeSecret = async (id) => {
|
|
15
|
+
await request("revoke", { id });
|
|
16
|
+
};
|
|
17
|
+
const channel = createPushChannel({
|
|
18
|
+
pushType: "secrets-metadata",
|
|
19
|
+
requestType: "request-secrets-metadata",
|
|
20
|
+
initial: [],
|
|
21
|
+
parse: (msg) => Array.isArray(msg.secrets) ? msg.secrets : void 0
|
|
22
|
+
});
|
|
23
|
+
const getSecrets = () => channel.get();
|
|
24
|
+
const onSecretsChange = (listener) => channel.onChange(listener);
|
|
25
|
+
const useSecrets = () => channel.use();
|
|
26
|
+
export {
|
|
27
|
+
getSecrets,
|
|
28
|
+
onSecretsChange,
|
|
29
|
+
requestAddSecret,
|
|
30
|
+
requestSecret,
|
|
31
|
+
revokeSecret,
|
|
32
|
+
useSecrets
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/secrets.ts"],"sourcesContent":["// The host-owned secret store — app-facing surface (SECRETS_SPEC §4/§5).\n//\n// An app can ASK the user to store a secret (`requestAddSecret`), be GRANTED the\n// right to USE a specific secret (`requestSecret`, the powerbox flow), LIST\n// secret METADATA (`getSecrets`/`useSecrets`, never values), and REVOKE one\n// (`revokeSecret`). The secret VALUE never crosses this boundary: it is read\n// host-side, once, at the `net:fetch` injection point (SECRETS_SPEC §6). These\n// functions move only hints, metadata, and grant handles.\n//\n// Resolves LLM_AND_AGENTS_SPEC D2 — the host-mediated BYOK key store. Inert until\n// the host implements `protocol-secrets` + the `secrets-metadata` channel\n// (SECRETS_SPEC §3/§6 host work, roadmap P1.E); the contract is shipped here so\n// apps (e.g. the in-browser coding agent, P3-73) can be written against it.\nimport { protocolRequest } from './sandboxUtils';\nimport { createPushChannel } from './pushChannel';\n\n/** The closed secret-type vocabulary (SECRETS_SPEC §2). `api-key` is always\n * origin-bound; `oauth-refresh` is reserved (no substitution in v1). */\nexport type SecretType = 'api-key' | 'bearer-token' | 'oauth-refresh';\n\n/**\n * The metadata-only projection of a stored secret (SECRETS_SPEC §2/§4) — exactly\n * what `secrets:list` and the powerbox return. **There is no `value` field by\n * design**: the plaintext is never part of any record an app receives.\n */\nexport interface SecretView {\n id: string;\n type: SecretType;\n family?: string;\n description: string;\n /** Required for `type:'api-key'` — the one https origin it may be sent to. */\n boundOrigin?: string;\n /** ISO-8601, or null if never used (drives the §8.15 90-day expiry). */\n lastUsedAt: string | null;\n}\n\n/** Hints for the host's \"add secret\" modal (SECRETS_SPEC §4 `secrets:add`). The\n * app supplies only hints; the user types the value into host chrome. */\nexport interface SecretHints {\n type?: SecretType;\n family?: string;\n /** Pre-fill the bound origin (e.g. `https://api.anthropic.com`). */\n suggestedOrigin?: string;\n description?: string;\n}\n\n/** What `requestSecret()` matches against in the powerbox picker (SECRETS_SPEC §5). */\nexport interface SecretQuery {\n type?: SecretType;\n family?: string;\n}\n\n/**\n * The result of a granted `requestSecret()` — a durable `(appKey, secretId)` use\n * grant plus the secret's metadata. **Never the value.** Hold onto nothing but\n * this; the host substitutes the value into matching `net:fetch` requests.\n */\nexport interface SecretGrant {\n /** Opaque handle for the minted `(appKey, secretId)` grant. */\n grantId: string;\n /** Metadata of the bound secret (no value). */\n secret: SecretView;\n}\n\n/** An error from a secret operation, carrying a machine-readable `code`. */\nexport interface SecretError extends Error {\n code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'invalid-params' | 'unknown';\n}\n\ntype SecretResult =\n | { ok: true; data: unknown }\n | { ok: false; code: string; message: string };\n\n// Issue a `protocol-secrets` request, unwrapping the host's {ok,data} envelope\n// and throwing a typed SecretError on failure (mirrors mounts.ts `request`).\nconst request = async <T = unknown>(\n method: string,\n query: object = {},\n): Promise<T> => {\n const res = (await protocolRequest('secrets', method, [query])) as SecretResult;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'secret request failed') as SecretError;\n err.code = (res?.code as SecretError['code']) ?? 'unknown';\n throw err;\n }\n return res.data as T;\n};\n\n/**\n * Ask the user to store a new secret (SECRETS_SPEC §4 `secrets:add`). Opens a\n * **host-drawn** modal (the value is typed into host chrome, never via the app);\n * resolves with the new secret's {@link SecretView} metadata, or rejects with a\n * {@link SecretError} (`cancelled` if the user dismisses the modal). Requires the\n * `secrets:add` capability.\n */\nexport const requestAddSecret = (hints: SecretHints = {}): Promise<SecretView> =>\n request<SecretView>('add', hints);\n\n/**\n * Ask the user to bind one of their stored secrets to this app (SECRETS_SPEC §5,\n * the powerbox flow — modeled on `requestSpace()`). The host draws a picker of\n * **only the user's matching secrets**; the user picks, declines, or creates one.\n * On success the host records a durable `(appKey, secretId)` grant and resolves\n * with a {@link SecretGrant} (handle + metadata, **never the value**).\n *\n * **No existence oracle (T20/T27):** a decline, an ungranted secret, and a\n * nonexistent secret are indistinguishable — all reject with a {@link SecretError}\n * `cancelled`; the app never sees the list it chose from.\n */\nexport const requestSecret = (query: SecretQuery = {}): Promise<SecretGrant> =>\n request<SecretGrant>('request', query);\n\n/**\n * Delete a stored secret and tombstone every dependent per-app use grant\n * (SECRETS_SPEC §4 `secrets:revoke`, §8.15 cascade). Requires `secrets:revoke`.\n */\nexport const revokeSecret = async (id: string): Promise<void> => {\n await request('revoke', { id });\n};\n\n// The metadata-only `secrets-metadata` channel (Recipe A): the host pushes the\n// current secret metadata on change and replays it on register-frame; gated by\n// `secrets:list`. NEVER carries a value (SECRETS_SPEC §4).\nconst channel = createPushChannel<SecretView[]>({\n pushType: 'secrets-metadata',\n requestType: 'request-secrets-metadata',\n initial: [],\n parse: (msg) => (Array.isArray(msg.secrets) ? (msg.secrets as SecretView[]) : undefined),\n});\n\n/** The metadata of the user's stored secrets (never values), `secrets:list`. Poll\n * for a one-off read; use {@link onSecretsChange}/{@link useSecrets} to react. */\nexport const getSecrets = (): SecretView[] => channel.get();\n\n/** Subscribe to secret-metadata changes (added/revoked). Invoked immediately with\n * the current list, then on every change. Returns an unsubscribe fn. */\nexport const onSecretsChange = (listener: (secrets: SecretView[]) => void): (() => void) =>\n channel.onChange(listener);\n\n/** React hook returning the user's secret metadata (never values), re-rendering\n * on change. For the Settings app (SECRETS_SPEC §7). */\nexport const useSecrets = (): SecretView[] => channel.use();\n"],"mappings":"AAaA,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AA6DlC,MAAM,UAAU,OACd,QACA,QAAgB,CAAC,MACF;AACf,QAAM,MAAO,MAAM,gBAAgB,WAAW,QAAQ,CAAC,KAAK,CAAC;AAC7D,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,uBAAuB;AAC7D,QAAI,OAAQ,KAAK,QAAgC;AACjD,UAAM;AAAA,EACR;AACA,SAAO,IAAI;AACb;AASO,MAAM,mBAAmB,CAAC,QAAqB,CAAC,MACrD,QAAoB,OAAO,KAAK;AAa3B,MAAM,gBAAgB,CAAC,QAAqB,CAAC,MAClD,QAAqB,WAAW,KAAK;AAMhC,MAAM,eAAe,OAAO,OAA8B;AAC/D,QAAM,QAAQ,UAAU,EAAE,GAAG,CAAC;AAChC;AAKA,MAAM,UAAU,kBAAgC;AAAA,EAC9C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS,CAAC;AAAA,EACV,OAAO,CAAC,QAAS,MAAM,QAAQ,IAAI,OAAO,IAAK,IAAI,UAA2B;AAChF,CAAC;AAIM,MAAM,aAAa,MAAoB,QAAQ,IAAI;AAInD,MAAM,kBAAkB,CAAC,aAC9B,QAAQ,SAAS,QAAQ;AAIpB,MAAM,aAAa,MAAoB,QAAQ,IAAI;","names":[]}
|
package/package.json
CHANGED