@immediately-run/sdk 0.1.4 → 0.1.5
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.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/mounts.cjs +28 -0
- package/dist/mounts.cjs.map +1 -1
- package/dist/mounts.d.cts +43 -7
- package/dist/mounts.d.ts +43 -7
- package/dist/mounts.js +23 -0
- package/dist/mounts.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -5,7 +5,7 @@ export { Include, RenderExportedComponent, RenderExportedComponentContext, Rende
|
|
|
5
5
|
export { DEFAULT_MDX_COMPONENTS, InternalLink, Link } from './components/MDXComponents.cjs';
|
|
6
6
|
export { useFileMetadata, useMetadataQuery } from './hooks.cjs';
|
|
7
7
|
export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.cjs';
|
|
8
|
-
export { MountQuery, SandboxMount, findMount, getMounts, onMountsChange, useMounts, waitForMount } from './mounts.cjs';
|
|
8
|
+
export { MountQuery, SandboxMount, SpaceError, SpaceInfo, createSpace, findMount, getMounts, listSpaces, mountSpace, onMountsChange, openAppSpace, unmountSpace, useMounts, waitForMount } from './mounts.cjs';
|
|
9
9
|
export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.cjs';
|
|
10
10
|
import 'react';
|
|
11
11
|
import './TinkerableContext.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { Include, RenderExportedComponent, RenderExportedComponentContext, Rende
|
|
|
5
5
|
export { DEFAULT_MDX_COMPONENTS, InternalLink, Link } from './components/MDXComponents.js';
|
|
6
6
|
export { useFileMetadata, useMetadataQuery } from './hooks.js';
|
|
7
7
|
export { AuthState, AuthStatus, SandboxUser, getAuthState, onAuthChange, useAuth } from './auth.js';
|
|
8
|
-
export { MountQuery, SandboxMount, findMount, getMounts, onMountsChange, useMounts, waitForMount } from './mounts.js';
|
|
8
|
+
export { MountQuery, SandboxMount, SpaceError, SpaceInfo, createSpace, findMount, getMounts, listSpaces, mountSpace, onMountsChange, openAppSpace, unmountSpace, useMounts, waitForMount } from './mounts.js';
|
|
9
9
|
export { EvaluationContext, FileQueryResult, FilesMetadata, Metadata, MetadataQueryFunction, MetadataQueryResult, ModuleExports } from './sandboxTypes.js';
|
|
10
10
|
import 'react';
|
|
11
11
|
import './TinkerableContext.js';
|
package/dist/mounts.cjs
CHANGED
|
@@ -18,14 +18,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var mounts_exports = {};
|
|
20
20
|
__export(mounts_exports, {
|
|
21
|
+
createSpace: () => createSpace,
|
|
21
22
|
findMount: () => findMount,
|
|
22
23
|
getMounts: () => getMounts,
|
|
24
|
+
listSpaces: () => listSpaces,
|
|
25
|
+
mountSpace: () => mountSpace,
|
|
23
26
|
onMountsChange: () => onMountsChange,
|
|
27
|
+
openAppSpace: () => openAppSpace,
|
|
28
|
+
unmountSpace: () => unmountSpace,
|
|
24
29
|
useMounts: () => useMounts,
|
|
25
30
|
waitForMount: () => waitForMount
|
|
26
31
|
});
|
|
27
32
|
module.exports = __toCommonJS(mounts_exports);
|
|
28
33
|
var import_react = require("react");
|
|
34
|
+
var import_sandboxUtils = require("./sandboxUtils");
|
|
29
35
|
const mountService = () => {
|
|
30
36
|
return module.evaluation.module.bundler.mounts;
|
|
31
37
|
};
|
|
@@ -50,11 +56,33 @@ const useMounts = () => {
|
|
|
50
56
|
(0, import_react.useEffect)(() => onMountsChange(setMounts), []);
|
|
51
57
|
return mounts;
|
|
52
58
|
};
|
|
59
|
+
const request = async (method, query = {}) => {
|
|
60
|
+
const res = await (0, import_sandboxUtils.protocolRequest)("spaces", method, [query]);
|
|
61
|
+
if (!res || res.ok !== true) {
|
|
62
|
+
const err = new Error(res?.message ?? "space request failed");
|
|
63
|
+
err.code = res?.code ?? "unknown";
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
return res.data;
|
|
67
|
+
};
|
|
68
|
+
const awaitReady = (descriptor) => waitForMount({ id: descriptor.id ?? descriptor.path });
|
|
69
|
+
const openAppSpace = async (slot = "default") => awaitReady(await request("open", { slot }));
|
|
70
|
+
const mountSpace = async (query) => awaitReady(await request("mount", query));
|
|
71
|
+
const createSpace = async (opts = {}) => awaitReady(await request("create", opts));
|
|
72
|
+
const listSpaces = async (opts = {}) => await request("list", opts);
|
|
73
|
+
const unmountSpace = async (query) => {
|
|
74
|
+
await request("unmount", query);
|
|
75
|
+
};
|
|
53
76
|
// Annotate the CommonJS export names for ESM import in node:
|
|
54
77
|
0 && (module.exports = {
|
|
78
|
+
createSpace,
|
|
55
79
|
findMount,
|
|
56
80
|
getMounts,
|
|
81
|
+
listSpaces,
|
|
82
|
+
mountSpace,
|
|
57
83
|
onMountsChange,
|
|
84
|
+
openAppSpace,
|
|
85
|
+
unmountSpace,
|
|
58
86
|
useMounts,
|
|
59
87
|
waitForMount
|
|
60
88
|
});
|
package/dist/mounts.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mounts.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/**\n * A filesystem mount available to the sandbox, mirrored from the host window.\n *\n * Mounts appear
|
|
1
|
+
{"version":3,"sources":["../src/mounts.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { protocolRequest } from './sandboxUtils';\n\n/**\n * A filesystem mount available to the sandbox, mirrored from the host window.\n *\n * Mounts appear on demand — call {@link openAppSpace} / {@link mountSpace} to ask\n * the host to mount a Firestore-backed \"space\"; it appears at `/spaces/{id}`.\n * Read or subscribe to the set, then access the files through the `fs` module at\n * the mount's `path`.\n */\nexport interface SandboxMount {\n /** Absolute path where the mount is reachable (e.g. `/spaces/{id}`). */\n path: string;\n /** Backend kind, e.g. `'firestore'`. */\n type: string;\n /** Optional stable identifier (the spaceId, for spaces). */\n id?: string;\n}\n\ninterface MountService {\n getMounts(): SandboxMount[];\n onChange(listener: (mounts: SandboxMount[]) => void): { dispose(): void };\n}\n\n// `module.evaluation.module.bundler` is the sandbox bundler injected into the\n// evaluation context (same path the other SDK helpers reach for `messageBus`).\nconst mountService = (): MountService => {\n // @ts-ignore - injected by the sandbox runtime\n return module.evaluation.module.bundler.mounts;\n};\n\n/** A predicate-style matcher for {@link findMount} / {@link waitForMount}. */\nexport type MountQuery = { type?: string; id?: string; path?: string };\n\nconst matches = (mount: SandboxMount, query: MountQuery): boolean =>\n (query.type === undefined || mount.type === query.type) &&\n (query.id === undefined || mount.id === query.id) &&\n (query.path === undefined || mount.path === query.path);\n\n/**\n * Returns the mounts currently available. Poll this whenever you need a one-off\n * read; use {@link onMountsChange} or {@link useMounts} to react to changes.\n */\nexport const getMounts = (): SandboxMount[] => mountService().getMounts();\n\n/** Returns the first mount matching `query`, or `undefined`. */\nexport const findMount = (query: MountQuery): SandboxMount | undefined =>\n getMounts().find((m) => matches(m, query));\n\n/**\n * Subscribe to mount changes. The listener is invoked immediately with the\n * current mounts, then again on every change. Returns an unsubscribe fn.\n */\nexport const onMountsChange = (listener: (mounts: SandboxMount[]) => void): (() => void) => {\n const disposable = mountService().onChange(listener);\n return () => disposable.dispose();\n};\n\n/**\n * Resolves once a mount matching `query` is present (immediately if it already\n * is). Handy for \"use it when it appears\" — e.g.\n * `await waitForMount({ type: 'firestore' })` before reading `/firestore`.\n */\nexport const waitForMount = (query: MountQuery): Promise<SandboxMount> =>\n new Promise((resolve) => {\n const unsubscribe = onMountsChange((mounts) => {\n const found = mounts.find((m) => matches(m, query));\n if (found) {\n // Defer unsubscribe so we don't dispose during the initial replay call.\n Promise.resolve().then(unsubscribe);\n resolve(found);\n }\n });\n });\n\n/** React hook returning the mounts currently available, re-rendering on change. */\nexport const useMounts = (): SandboxMount[] => {\n const [mounts, setMounts] = useState<SandboxMount[]>(getMounts);\n useEffect(() => onMountsChange(setMounts), []);\n return mounts;\n};\n\n// ---------------------------------------------------------------------------\n// Spaces — on-demand, shareable Firestore-backed filesystems.\n// The host owns all UX: if you aren't signed in, or the space doesn't exist or\n// isn't accessible, the parent window presents sign-in / create / request-access\n// and only then resolves these calls. See docs/specs/FILE_SHARING_SPEC.md.\n// ---------------------------------------------------------------------------\n\n/** Summary of a space, as returned by {@link listSpaces}. */\nexport interface SpaceInfo {\n spaceId: string;\n role?: 'owner' | 'writer' | 'reader';\n owner?: string;\n name?: string;\n}\n\n/** An error from a space operation, carrying a machine-readable `code`. */\nexport interface SpaceError extends Error {\n code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'unknown';\n}\n\ntype SpaceResult =\n | { ok: true; data: unknown }\n | { ok: false; code: string; message: string };\n\nconst request = async (method: string, query: Record<string, unknown> = {}): Promise<unknown> => {\n const res = (await protocolRequest('spaces', method, [query])) as SpaceResult;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'space request failed') as SpaceError;\n err.code = (res?.code as SpaceError['code']) ?? 'unknown';\n throw err;\n }\n return res.data;\n};\n\n// The host announces the mount (`mount-add`) separately from the protocol reply,\n// so wait until the ZenFS port mount is actually registered before returning —\n// otherwise an immediate read could race the mount.\nconst awaitReady = (descriptor: SandboxMount): Promise<SandboxMount> =>\n waitForMount({ id: descriptor.id ?? descriptor.path });\n\n/**\n * Open this app's workspace for the signed-in user (the zero-config path). The\n * `slot` names which workspace (default `'default'`); pass distinct slots for\n * multiple filesystems in one app. On a missing slot the host shows a\n * create-or-pick dialog. Rejects with a {@link SpaceError} (`.code`) on cancel.\n */\nexport const openAppSpace = async (slot = 'default'): Promise<SandboxMount> =>\n awaitReady((await request('open', { slot })) as SandboxMount);\n\n/** Mount a specific space by id (e.g. one shared with you, or from a link). */\nexport const mountSpace = async (query: { spaceId: string }): Promise<SandboxMount> =>\n awaitReady((await request('mount', query)) as SandboxMount);\n\n/** Create a brand-new space, optionally binding it to this app (a slot). */\nexport const createSpace = async (\n opts: { name?: string; slot?: string; bindToApp?: boolean } = {}\n): Promise<SandboxMount> => awaitReady((await request('create', opts)) as SandboxMount);\n\n/** List spaces you can access — all of them, or just those bound to this app. */\nexport const listSpaces = async (opts: { app?: boolean } = {}): Promise<SpaceInfo[]> =>\n (await request('list', opts)) as SpaceInfo[];\n\n/** Release a mounted space (stops its listener on the host). */\nexport const unmountSpace = async (query: { spaceId: string }): Promise<void> => {\n await request('unmount', query);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAoC;AACpC,0BAAgC;AA0BhC,MAAM,eAAe,MAAoB;AAEvC,SAAO,OAAO,WAAW,OAAO,QAAQ;AAC1C;AAKA,MAAM,UAAU,CAAC,OAAqB,WACnC,MAAM,SAAS,UAAa,MAAM,SAAS,MAAM,UACjD,MAAM,OAAO,UAAa,MAAM,OAAO,MAAM,QAC7C,MAAM,SAAS,UAAa,MAAM,SAAS,MAAM;AAM7C,MAAM,YAAY,MAAsB,aAAa,EAAE,UAAU;AAGjE,MAAM,YAAY,CAAC,UACxB,UAAU,EAAE,KAAK,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAMpC,MAAM,iBAAiB,CAAC,aAA6D;AAC1F,QAAM,aAAa,aAAa,EAAE,SAAS,QAAQ;AACnD,SAAO,MAAM,WAAW,QAAQ;AAClC;AAOO,MAAM,eAAe,CAAC,UAC3B,IAAI,QAAQ,CAAC,YAAY;AACvB,QAAM,cAAc,eAAe,CAAC,WAAW;AAC7C,UAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAClD,QAAI,OAAO;AAET,cAAQ,QAAQ,EAAE,KAAK,WAAW;AAClC,cAAQ,KAAK;AAAA,IACf;AAAA,EACF,CAAC;AACH,CAAC;AAGI,MAAM,YAAY,MAAsB;AAC7C,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAyB,SAAS;AAC9D,8BAAU,MAAM,eAAe,SAAS,GAAG,CAAC,CAAC;AAC7C,SAAO;AACT;AA0BA,MAAM,UAAU,OAAO,QAAgB,QAAiC,CAAC,MAAwB;AAC/F,QAAM,MAAO,UAAM,qCAAgB,UAAU,QAAQ,CAAC,KAAK,CAAC;AAC5D,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,sBAAsB;AAC5D,QAAI,OAAQ,KAAK,QAA+B;AAChD,UAAM;AAAA,EACR;AACA,SAAO,IAAI;AACb;AAKA,MAAM,aAAa,CAAC,eAClB,aAAa,EAAE,IAAI,WAAW,MAAM,WAAW,KAAK,CAAC;AAQhD,MAAM,eAAe,OAAO,OAAO,cACxC,WAAY,MAAM,QAAQ,QAAQ,EAAE,KAAK,CAAC,CAAkB;AAGvD,MAAM,aAAa,OAAO,UAC/B,WAAY,MAAM,QAAQ,SAAS,KAAK,CAAkB;AAGrD,MAAM,cAAc,OACzB,OAA8D,CAAC,MACrC,WAAY,MAAM,QAAQ,UAAU,IAAI,CAAkB;AAG/E,MAAM,aAAa,OAAO,OAA0B,CAAC,MACzD,MAAM,QAAQ,QAAQ,IAAI;AAGtB,MAAM,eAAe,OAAO,UAA8C;AAC/E,QAAM,QAAQ,WAAW,KAAK;AAChC;","names":[]}
|
package/dist/mounts.d.cts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A filesystem mount available to the sandbox, mirrored from the host window.
|
|
3
3
|
*
|
|
4
|
-
* Mounts appear
|
|
5
|
-
*
|
|
6
|
-
* or subscribe to the set, then access the files through the `fs` module at
|
|
7
|
-
* mount's `path`.
|
|
4
|
+
* Mounts appear on demand — call {@link openAppSpace} / {@link mountSpace} to ask
|
|
5
|
+
* the host to mount a Firestore-backed "space"; it appears at `/spaces/{id}`.
|
|
6
|
+
* Read or subscribe to the set, then access the files through the `fs` module at
|
|
7
|
+
* the mount's `path`.
|
|
8
8
|
*/
|
|
9
9
|
interface SandboxMount {
|
|
10
|
-
/** Absolute path where the mount is reachable (e.g. `/
|
|
10
|
+
/** Absolute path where the mount is reachable (e.g. `/spaces/{id}`). */
|
|
11
11
|
path: string;
|
|
12
12
|
/** Backend kind, e.g. `'firestore'`. */
|
|
13
13
|
type: string;
|
|
14
|
-
/** Optional stable identifier. */
|
|
14
|
+
/** Optional stable identifier (the spaceId, for spaces). */
|
|
15
15
|
id?: string;
|
|
16
16
|
}
|
|
17
17
|
/** A predicate-style matcher for {@link findMount} / {@link waitForMount}. */
|
|
@@ -40,5 +40,41 @@ declare const onMountsChange: (listener: (mounts: SandboxMount[]) => void) => ((
|
|
|
40
40
|
declare const waitForMount: (query: MountQuery) => Promise<SandboxMount>;
|
|
41
41
|
/** React hook returning the mounts currently available, re-rendering on change. */
|
|
42
42
|
declare const useMounts: () => SandboxMount[];
|
|
43
|
+
/** Summary of a space, as returned by {@link listSpaces}. */
|
|
44
|
+
interface SpaceInfo {
|
|
45
|
+
spaceId: string;
|
|
46
|
+
role?: 'owner' | 'writer' | 'reader';
|
|
47
|
+
owner?: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
}
|
|
50
|
+
/** An error from a space operation, carrying a machine-readable `code`. */
|
|
51
|
+
interface SpaceError extends Error {
|
|
52
|
+
code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'unknown';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Open this app's workspace for the signed-in user (the zero-config path). The
|
|
56
|
+
* `slot` names which workspace (default `'default'`); pass distinct slots for
|
|
57
|
+
* multiple filesystems in one app. On a missing slot the host shows a
|
|
58
|
+
* create-or-pick dialog. Rejects with a {@link SpaceError} (`.code`) on cancel.
|
|
59
|
+
*/
|
|
60
|
+
declare const openAppSpace: (slot?: string) => Promise<SandboxMount>;
|
|
61
|
+
/** Mount a specific space by id (e.g. one shared with you, or from a link). */
|
|
62
|
+
declare const mountSpace: (query: {
|
|
63
|
+
spaceId: string;
|
|
64
|
+
}) => Promise<SandboxMount>;
|
|
65
|
+
/** Create a brand-new space, optionally binding it to this app (a slot). */
|
|
66
|
+
declare const createSpace: (opts?: {
|
|
67
|
+
name?: string;
|
|
68
|
+
slot?: string;
|
|
69
|
+
bindToApp?: boolean;
|
|
70
|
+
}) => Promise<SandboxMount>;
|
|
71
|
+
/** List spaces you can access — all of them, or just those bound to this app. */
|
|
72
|
+
declare const listSpaces: (opts?: {
|
|
73
|
+
app?: boolean;
|
|
74
|
+
}) => Promise<SpaceInfo[]>;
|
|
75
|
+
/** Release a mounted space (stops its listener on the host). */
|
|
76
|
+
declare const unmountSpace: (query: {
|
|
77
|
+
spaceId: string;
|
|
78
|
+
}) => Promise<void>;
|
|
43
79
|
|
|
44
|
-
export { type MountQuery, type SandboxMount, findMount, getMounts, onMountsChange, useMounts, waitForMount };
|
|
80
|
+
export { type MountQuery, type SandboxMount, type SpaceError, type SpaceInfo, createSpace, findMount, getMounts, listSpaces, mountSpace, onMountsChange, openAppSpace, unmountSpace, useMounts, waitForMount };
|
package/dist/mounts.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A filesystem mount available to the sandbox, mirrored from the host window.
|
|
3
3
|
*
|
|
4
|
-
* Mounts appear
|
|
5
|
-
*
|
|
6
|
-
* or subscribe to the set, then access the files through the `fs` module at
|
|
7
|
-
* mount's `path`.
|
|
4
|
+
* Mounts appear on demand — call {@link openAppSpace} / {@link mountSpace} to ask
|
|
5
|
+
* the host to mount a Firestore-backed "space"; it appears at `/spaces/{id}`.
|
|
6
|
+
* Read or subscribe to the set, then access the files through the `fs` module at
|
|
7
|
+
* the mount's `path`.
|
|
8
8
|
*/
|
|
9
9
|
interface SandboxMount {
|
|
10
|
-
/** Absolute path where the mount is reachable (e.g. `/
|
|
10
|
+
/** Absolute path where the mount is reachable (e.g. `/spaces/{id}`). */
|
|
11
11
|
path: string;
|
|
12
12
|
/** Backend kind, e.g. `'firestore'`. */
|
|
13
13
|
type: string;
|
|
14
|
-
/** Optional stable identifier. */
|
|
14
|
+
/** Optional stable identifier (the spaceId, for spaces). */
|
|
15
15
|
id?: string;
|
|
16
16
|
}
|
|
17
17
|
/** A predicate-style matcher for {@link findMount} / {@link waitForMount}. */
|
|
@@ -40,5 +40,41 @@ declare const onMountsChange: (listener: (mounts: SandboxMount[]) => void) => ((
|
|
|
40
40
|
declare const waitForMount: (query: MountQuery) => Promise<SandboxMount>;
|
|
41
41
|
/** React hook returning the mounts currently available, re-rendering on change. */
|
|
42
42
|
declare const useMounts: () => SandboxMount[];
|
|
43
|
+
/** Summary of a space, as returned by {@link listSpaces}. */
|
|
44
|
+
interface SpaceInfo {
|
|
45
|
+
spaceId: string;
|
|
46
|
+
role?: 'owner' | 'writer' | 'reader';
|
|
47
|
+
owner?: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
}
|
|
50
|
+
/** An error from a space operation, carrying a machine-readable `code`. */
|
|
51
|
+
interface SpaceError extends Error {
|
|
52
|
+
code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'unknown';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Open this app's workspace for the signed-in user (the zero-config path). The
|
|
56
|
+
* `slot` names which workspace (default `'default'`); pass distinct slots for
|
|
57
|
+
* multiple filesystems in one app. On a missing slot the host shows a
|
|
58
|
+
* create-or-pick dialog. Rejects with a {@link SpaceError} (`.code`) on cancel.
|
|
59
|
+
*/
|
|
60
|
+
declare const openAppSpace: (slot?: string) => Promise<SandboxMount>;
|
|
61
|
+
/** Mount a specific space by id (e.g. one shared with you, or from a link). */
|
|
62
|
+
declare const mountSpace: (query: {
|
|
63
|
+
spaceId: string;
|
|
64
|
+
}) => Promise<SandboxMount>;
|
|
65
|
+
/** Create a brand-new space, optionally binding it to this app (a slot). */
|
|
66
|
+
declare const createSpace: (opts?: {
|
|
67
|
+
name?: string;
|
|
68
|
+
slot?: string;
|
|
69
|
+
bindToApp?: boolean;
|
|
70
|
+
}) => Promise<SandboxMount>;
|
|
71
|
+
/** List spaces you can access — all of them, or just those bound to this app. */
|
|
72
|
+
declare const listSpaces: (opts?: {
|
|
73
|
+
app?: boolean;
|
|
74
|
+
}) => Promise<SpaceInfo[]>;
|
|
75
|
+
/** Release a mounted space (stops its listener on the host). */
|
|
76
|
+
declare const unmountSpace: (query: {
|
|
77
|
+
spaceId: string;
|
|
78
|
+
}) => Promise<void>;
|
|
43
79
|
|
|
44
|
-
export { type MountQuery, type SandboxMount, findMount, getMounts, onMountsChange, useMounts, waitForMount };
|
|
80
|
+
export { type MountQuery, type SandboxMount, type SpaceError, type SpaceInfo, createSpace, findMount, getMounts, listSpaces, mountSpace, onMountsChange, openAppSpace, unmountSpace, useMounts, waitForMount };
|
package/dist/mounts.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
+
import { protocolRequest } from "./sandboxUtils";
|
|
2
3
|
const mountService = () => {
|
|
3
4
|
return module.evaluation.module.bundler.mounts;
|
|
4
5
|
};
|
|
@@ -23,10 +24,32 @@ const useMounts = () => {
|
|
|
23
24
|
useEffect(() => onMountsChange(setMounts), []);
|
|
24
25
|
return mounts;
|
|
25
26
|
};
|
|
27
|
+
const request = async (method, query = {}) => {
|
|
28
|
+
const res = await protocolRequest("spaces", method, [query]);
|
|
29
|
+
if (!res || res.ok !== true) {
|
|
30
|
+
const err = new Error(res?.message ?? "space request failed");
|
|
31
|
+
err.code = res?.code ?? "unknown";
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
return res.data;
|
|
35
|
+
};
|
|
36
|
+
const awaitReady = (descriptor) => waitForMount({ id: descriptor.id ?? descriptor.path });
|
|
37
|
+
const openAppSpace = async (slot = "default") => awaitReady(await request("open", { slot }));
|
|
38
|
+
const mountSpace = async (query) => awaitReady(await request("mount", query));
|
|
39
|
+
const createSpace = async (opts = {}) => awaitReady(await request("create", opts));
|
|
40
|
+
const listSpaces = async (opts = {}) => await request("list", opts);
|
|
41
|
+
const unmountSpace = async (query) => {
|
|
42
|
+
await request("unmount", query);
|
|
43
|
+
};
|
|
26
44
|
export {
|
|
45
|
+
createSpace,
|
|
27
46
|
findMount,
|
|
28
47
|
getMounts,
|
|
48
|
+
listSpaces,
|
|
49
|
+
mountSpace,
|
|
29
50
|
onMountsChange,
|
|
51
|
+
openAppSpace,
|
|
52
|
+
unmountSpace,
|
|
30
53
|
useMounts,
|
|
31
54
|
waitForMount
|
|
32
55
|
};
|
package/dist/mounts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mounts.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/**\n * A filesystem mount available to the sandbox, mirrored from the host window.\n *\n * Mounts appear
|
|
1
|
+
{"version":3,"sources":["../src/mounts.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { protocolRequest } from './sandboxUtils';\n\n/**\n * A filesystem mount available to the sandbox, mirrored from the host window.\n *\n * Mounts appear on demand — call {@link openAppSpace} / {@link mountSpace} to ask\n * the host to mount a Firestore-backed \"space\"; it appears at `/spaces/{id}`.\n * Read or subscribe to the set, then access the files through the `fs` module at\n * the mount's `path`.\n */\nexport interface SandboxMount {\n /** Absolute path where the mount is reachable (e.g. `/spaces/{id}`). */\n path: string;\n /** Backend kind, e.g. `'firestore'`. */\n type: string;\n /** Optional stable identifier (the spaceId, for spaces). */\n id?: string;\n}\n\ninterface MountService {\n getMounts(): SandboxMount[];\n onChange(listener: (mounts: SandboxMount[]) => void): { dispose(): void };\n}\n\n// `module.evaluation.module.bundler` is the sandbox bundler injected into the\n// evaluation context (same path the other SDK helpers reach for `messageBus`).\nconst mountService = (): MountService => {\n // @ts-ignore - injected by the sandbox runtime\n return module.evaluation.module.bundler.mounts;\n};\n\n/** A predicate-style matcher for {@link findMount} / {@link waitForMount}. */\nexport type MountQuery = { type?: string; id?: string; path?: string };\n\nconst matches = (mount: SandboxMount, query: MountQuery): boolean =>\n (query.type === undefined || mount.type === query.type) &&\n (query.id === undefined || mount.id === query.id) &&\n (query.path === undefined || mount.path === query.path);\n\n/**\n * Returns the mounts currently available. Poll this whenever you need a one-off\n * read; use {@link onMountsChange} or {@link useMounts} to react to changes.\n */\nexport const getMounts = (): SandboxMount[] => mountService().getMounts();\n\n/** Returns the first mount matching `query`, or `undefined`. */\nexport const findMount = (query: MountQuery): SandboxMount | undefined =>\n getMounts().find((m) => matches(m, query));\n\n/**\n * Subscribe to mount changes. The listener is invoked immediately with the\n * current mounts, then again on every change. Returns an unsubscribe fn.\n */\nexport const onMountsChange = (listener: (mounts: SandboxMount[]) => void): (() => void) => {\n const disposable = mountService().onChange(listener);\n return () => disposable.dispose();\n};\n\n/**\n * Resolves once a mount matching `query` is present (immediately if it already\n * is). Handy for \"use it when it appears\" — e.g.\n * `await waitForMount({ type: 'firestore' })` before reading `/firestore`.\n */\nexport const waitForMount = (query: MountQuery): Promise<SandboxMount> =>\n new Promise((resolve) => {\n const unsubscribe = onMountsChange((mounts) => {\n const found = mounts.find((m) => matches(m, query));\n if (found) {\n // Defer unsubscribe so we don't dispose during the initial replay call.\n Promise.resolve().then(unsubscribe);\n resolve(found);\n }\n });\n });\n\n/** React hook returning the mounts currently available, re-rendering on change. */\nexport const useMounts = (): SandboxMount[] => {\n const [mounts, setMounts] = useState<SandboxMount[]>(getMounts);\n useEffect(() => onMountsChange(setMounts), []);\n return mounts;\n};\n\n// ---------------------------------------------------------------------------\n// Spaces — on-demand, shareable Firestore-backed filesystems.\n// The host owns all UX: if you aren't signed in, or the space doesn't exist or\n// isn't accessible, the parent window presents sign-in / create / request-access\n// and only then resolves these calls. See docs/specs/FILE_SHARING_SPEC.md.\n// ---------------------------------------------------------------------------\n\n/** Summary of a space, as returned by {@link listSpaces}. */\nexport interface SpaceInfo {\n spaceId: string;\n role?: 'owner' | 'writer' | 'reader';\n owner?: string;\n name?: string;\n}\n\n/** An error from a space operation, carrying a machine-readable `code`. */\nexport interface SpaceError extends Error {\n code: 'auth-required' | 'cancelled' | 'forbidden' | 'not-found' | 'unknown';\n}\n\ntype SpaceResult =\n | { ok: true; data: unknown }\n | { ok: false; code: string; message: string };\n\nconst request = async (method: string, query: Record<string, unknown> = {}): Promise<unknown> => {\n const res = (await protocolRequest('spaces', method, [query])) as SpaceResult;\n if (!res || res.ok !== true) {\n const err = new Error(res?.message ?? 'space request failed') as SpaceError;\n err.code = (res?.code as SpaceError['code']) ?? 'unknown';\n throw err;\n }\n return res.data;\n};\n\n// The host announces the mount (`mount-add`) separately from the protocol reply,\n// so wait until the ZenFS port mount is actually registered before returning —\n// otherwise an immediate read could race the mount.\nconst awaitReady = (descriptor: SandboxMount): Promise<SandboxMount> =>\n waitForMount({ id: descriptor.id ?? descriptor.path });\n\n/**\n * Open this app's workspace for the signed-in user (the zero-config path). The\n * `slot` names which workspace (default `'default'`); pass distinct slots for\n * multiple filesystems in one app. On a missing slot the host shows a\n * create-or-pick dialog. Rejects with a {@link SpaceError} (`.code`) on cancel.\n */\nexport const openAppSpace = async (slot = 'default'): Promise<SandboxMount> =>\n awaitReady((await request('open', { slot })) as SandboxMount);\n\n/** Mount a specific space by id (e.g. one shared with you, or from a link). */\nexport const mountSpace = async (query: { spaceId: string }): Promise<SandboxMount> =>\n awaitReady((await request('mount', query)) as SandboxMount);\n\n/** Create a brand-new space, optionally binding it to this app (a slot). */\nexport const createSpace = async (\n opts: { name?: string; slot?: string; bindToApp?: boolean } = {}\n): Promise<SandboxMount> => awaitReady((await request('create', opts)) as SandboxMount);\n\n/** List spaces you can access — all of them, or just those bound to this app. */\nexport const listSpaces = async (opts: { app?: boolean } = {}): Promise<SpaceInfo[]> =>\n (await request('list', opts)) as SpaceInfo[];\n\n/** Release a mounted space (stops its listener on the host). */\nexport const unmountSpace = async (query: { spaceId: string }): Promise<void> => {\n await request('unmount', query);\n};\n"],"mappings":"AAAA,SAAS,WAAW,gBAAgB;AACpC,SAAS,uBAAuB;AA0BhC,MAAM,eAAe,MAAoB;AAEvC,SAAO,OAAO,WAAW,OAAO,QAAQ;AAC1C;AAKA,MAAM,UAAU,CAAC,OAAqB,WACnC,MAAM,SAAS,UAAa,MAAM,SAAS,MAAM,UACjD,MAAM,OAAO,UAAa,MAAM,OAAO,MAAM,QAC7C,MAAM,SAAS,UAAa,MAAM,SAAS,MAAM;AAM7C,MAAM,YAAY,MAAsB,aAAa,EAAE,UAAU;AAGjE,MAAM,YAAY,CAAC,UACxB,UAAU,EAAE,KAAK,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAMpC,MAAM,iBAAiB,CAAC,aAA6D;AAC1F,QAAM,aAAa,aAAa,EAAE,SAAS,QAAQ;AACnD,SAAO,MAAM,WAAW,QAAQ;AAClC;AAOO,MAAM,eAAe,CAAC,UAC3B,IAAI,QAAQ,CAAC,YAAY;AACvB,QAAM,cAAc,eAAe,CAAC,WAAW;AAC7C,UAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAClD,QAAI,OAAO;AAET,cAAQ,QAAQ,EAAE,KAAK,WAAW;AAClC,cAAQ,KAAK;AAAA,IACf;AAAA,EACF,CAAC;AACH,CAAC;AAGI,MAAM,YAAY,MAAsB;AAC7C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAyB,SAAS;AAC9D,YAAU,MAAM,eAAe,SAAS,GAAG,CAAC,CAAC;AAC7C,SAAO;AACT;AA0BA,MAAM,UAAU,OAAO,QAAgB,QAAiC,CAAC,MAAwB;AAC/F,QAAM,MAAO,MAAM,gBAAgB,UAAU,QAAQ,CAAC,KAAK,CAAC;AAC5D,MAAI,CAAC,OAAO,IAAI,OAAO,MAAM;AAC3B,UAAM,MAAM,IAAI,MAAM,KAAK,WAAW,sBAAsB;AAC5D,QAAI,OAAQ,KAAK,QAA+B;AAChD,UAAM;AAAA,EACR;AACA,SAAO,IAAI;AACb;AAKA,MAAM,aAAa,CAAC,eAClB,aAAa,EAAE,IAAI,WAAW,MAAM,WAAW,KAAK,CAAC;AAQhD,MAAM,eAAe,OAAO,OAAO,cACxC,WAAY,MAAM,QAAQ,QAAQ,EAAE,KAAK,CAAC,CAAkB;AAGvD,MAAM,aAAa,OAAO,UAC/B,WAAY,MAAM,QAAQ,SAAS,KAAK,CAAkB;AAGrD,MAAM,cAAc,OACzB,OAA8D,CAAC,MACrC,WAAY,MAAM,QAAQ,UAAU,IAAI,CAAkB;AAG/E,MAAM,aAAa,OAAO,OAA0B,CAAC,MACzD,MAAM,QAAQ,QAAQ,IAAI;AAGtB,MAAM,eAAe,OAAO,UAA8C;AAC/E,QAAM,QAAQ,WAAW,KAAK;AAChC;","names":[]}
|
package/package.json
CHANGED