@book.dev/sdk 1.76.2 → 2.1.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/ai.d.ts +108 -4
- package/dist/authorize.js +18 -7
- package/dist/authorize.js.map +1 -1
- package/dist/backup.d.ts +1 -1
- package/dist/bookFolder.d.ts +38 -21
- package/dist/bookFolder.js +42 -18
- package/dist/bookFolder.js.map +1 -1
- package/dist/bookfile.d.ts +1 -1
- package/dist/client.d.ts +53 -5
- package/dist/client.js +35 -5
- package/dist/client.js.map +1 -1
- package/dist/database.d.ts +9 -3
- package/dist/database.js +23 -7
- package/dist/database.js.map +1 -1
- package/dist/forwarding/forwardingClient.d.ts +38 -0
- package/dist/forwarding/forwardingClient.js +57 -4
- package/dist/forwarding/forwardingClient.js.map +1 -1
- package/dist/forwarding/index.d.ts +2 -2
- package/dist/forwarding/index.js +2 -2
- package/dist/forwarding/index.js.map +1 -1
- package/dist/forwarding/rosterAssertion.d.ts +61 -12
- package/dist/forwarding/rosterAssertion.js +77 -26
- package/dist/forwarding/rosterAssertion.js.map +1 -1
- package/dist/identity.d.ts +44 -1
- package/dist/identity.js.map +1 -1
- package/dist/import.d.ts +3 -3
- package/dist/import.js +3 -3
- package/dist/import.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/provenance.d.ts +38 -27
- package/dist/provenance.js.map +1 -1
- package/dist/routes.d.ts +34 -3
- package/dist/routes.js +36 -4
- package/dist/routes.js.map +1 -1
- package/dist/templates.d.ts +22 -6
- package/dist/templates.js +461 -14
- package/dist/templates.js.map +1 -1
- package/package.json +1 -1
package/dist/ai.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export type AiEffort = 'low' | 'med' | 'high';
|
|
|
31
31
|
* claude all set up at once and switch between them per agent run. */
|
|
32
32
|
export interface AiProviderSettings {
|
|
33
33
|
/** Model identifier: a GGUF filename (llama), an MLX model id (mlx), a served
|
|
34
|
-
* model name (openai), or a Claude model id (e.g. `claude-
|
|
34
|
+
* model name (openai), or a Claude model id (e.g. `claude-opus-4-8`). */
|
|
35
35
|
model?: string;
|
|
36
36
|
/** Base URL for `mlx` / `openai` / `claude`. Defaults: mlx
|
|
37
37
|
* http://127.0.0.1:8080, openai http://127.0.0.1:11434, claude
|
|
@@ -271,13 +271,18 @@ export type AgentChatEvent = {
|
|
|
271
271
|
result: string;
|
|
272
272
|
}
|
|
273
273
|
/**
|
|
274
|
-
* The agent is asking
|
|
275
|
-
*
|
|
276
|
-
*
|
|
274
|
+
* The agent is asking for a sticky, per-conversation permission. `kind`
|
|
275
|
+
* distinguishes them (default `direct_edits` for back-compat):
|
|
276
|
+
* - `direct_edits` — apply its edits DIRECTLY (without the review pane);
|
|
277
|
+
* granting makes subsequent edits apply immediately (see {@link apply}).
|
|
278
|
+
* - `external_tools` — call EXTERNAL MCP tools (`mcp__*`), which send inputs
|
|
279
|
+
* off the workspace; granting lets the agent use them for this conversation.
|
|
280
|
+
* The UI shows an allow / keep-reviewing prompt either way.
|
|
277
281
|
*/
|
|
278
282
|
| {
|
|
279
283
|
type: 'permission_request';
|
|
280
284
|
summary: string;
|
|
285
|
+
kind?: 'direct_edits' | 'external_tools';
|
|
281
286
|
}
|
|
282
287
|
/** The agent is asking the user a multi-step interview; answers return as the
|
|
283
288
|
* user's next message. */
|
|
@@ -346,6 +351,105 @@ export interface AgentChatOptions {
|
|
|
346
351
|
* via an {@link AgentChatEvent.apply} event instead of becoming review
|
|
347
352
|
* suggestions. Sticky for the conversation once granted. */
|
|
348
353
|
allowDirectEdits?: boolean;
|
|
354
|
+
/** When true (the user consented), the agent may call EXTERNAL MCP tools
|
|
355
|
+
* (`mcp__*`) without pausing. Sticky for the conversation; the first external
|
|
356
|
+
* call otherwise emits a `permission_request` with `kind:'external_tools'`. */
|
|
357
|
+
allowExternalTools?: boolean;
|
|
358
|
+
/** When true, an external MCP tool was already used earlier in this conversation
|
|
359
|
+
* — the client re-sends it (set once it sees any `mcp__*` tool event) so taint
|
|
360
|
+
* (edits routed through review) stays sticky for the rest of the conversation,
|
|
361
|
+
* not just the run that made the external call. */
|
|
362
|
+
externalToolsUsed?: boolean;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* How the in-app agent reaches an external MCP server:
|
|
366
|
+
* - `stdio` — spawn a local child process and speak MCP over its stdio. This is
|
|
367
|
+
* host **command execution** (the child runs as the server user and can reach
|
|
368
|
+
* loopback services the identity layer trusts as the machine owner), so it is
|
|
369
|
+
* permitted ONLY on a desktop / UNCLAIMED instance. On a claimed multi-user
|
|
370
|
+
* instance the server rejects a `stdio` registration and the UI hides it.
|
|
371
|
+
* - `http` — a remote (or loopback) Streamable-HTTP MCP endpoint, authed with a
|
|
372
|
+
* static bearer token. The only transport offered on a claimed instance.
|
|
373
|
+
*/
|
|
374
|
+
export type McpTransport = 'stdio' | 'http';
|
|
375
|
+
/**
|
|
376
|
+
* One registered external MCP server. Admin-managed (see {@link McpClientConfig});
|
|
377
|
+
* connections are pooled server-side and its tools are merged into an agent run
|
|
378
|
+
* namespaced `mcp__<id>__<tool>` (so `id` forbids underscores — the delimiter).
|
|
379
|
+
*/
|
|
380
|
+
export interface McpServerConfig {
|
|
381
|
+
/** Stable slug, `^[a-z0-9][a-z0-9-]{0,31}$` (NO underscores — the namespace
|
|
382
|
+
* delimiter). Unique within {@link McpClientConfig.servers}. */
|
|
383
|
+
id: string;
|
|
384
|
+
/** Optional display name (defaults to {@link id}). */
|
|
385
|
+
name?: string;
|
|
386
|
+
/** Per-server enable. Default false — a registered server does nothing until
|
|
387
|
+
* explicitly enabled (and the global {@link McpClientConfig.enabled} is on). */
|
|
388
|
+
enabled: boolean;
|
|
389
|
+
transport: McpTransport;
|
|
390
|
+
/** The executable to spawn (stdio). */
|
|
391
|
+
command?: string;
|
|
392
|
+
/** Arguments for {@link command} (stdio). NEVER carries the auth token. */
|
|
393
|
+
args?: string[];
|
|
394
|
+
/** Extra environment for the child (stdio). Overlaid on a MINIMAL default env
|
|
395
|
+
* (never the server's own `process.env`); the auth token is injected under
|
|
396
|
+
* {@link authEnvVar}, not here. */
|
|
397
|
+
env?: Record<string, string>;
|
|
398
|
+
/** Env var name the auth token is injected under (stdio). Default `MCP_AUTH_TOKEN`. */
|
|
399
|
+
authEnvVar?: string;
|
|
400
|
+
/** The Streamable-HTTP MCP endpoint (http). */
|
|
401
|
+
url?: string;
|
|
402
|
+
/** Extra request headers (http). The auth token is sent as `Authorization:
|
|
403
|
+
* Bearer <token>`, NOT here. */
|
|
404
|
+
headers?: Record<string, string>;
|
|
405
|
+
/**
|
|
406
|
+
* The static bearer token (http) or injected secret (stdio). **Write-only
|
|
407
|
+
* across the wire** — the server never returns it. Same three-way contract as
|
|
408
|
+
* {@link AiProviderSettings.apiKey}:
|
|
409
|
+
* • omitted / empty string → PRESERVE the stored token;
|
|
410
|
+
* • a non-empty string → set a new token;
|
|
411
|
+
* • explicit `null` → CLEAR the stored token.
|
|
412
|
+
*/
|
|
413
|
+
authToken?: string | null;
|
|
414
|
+
/** Response-only signal: the server holds a non-empty token for this server.
|
|
415
|
+
* Set by `GET /api/ai/mcp` in place of the redacted {@link authToken}. */
|
|
416
|
+
authTokenSet?: boolean;
|
|
417
|
+
/** Per-call timeout for this server's tools, ms. Default 30000, clamped
|
|
418
|
+
* 1000..120000. */
|
|
419
|
+
timeoutMs?: number;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The workspace's external-tool (MCP client) configuration, persisted server-side
|
|
423
|
+
* under the `ai.mcp` settings key. Admin-managed. OFF and empty by default —
|
|
424
|
+
* nothing connects until an admin adds a server, enables it, and flips the global
|
|
425
|
+
* switch. A deployment env kill-switch (`OPENBOOK_MCP_CLIENTS=0`) hard-disables
|
|
426
|
+
* the whole subsystem regardless.
|
|
427
|
+
*/
|
|
428
|
+
export interface McpClientConfig {
|
|
429
|
+
/** Global kill-switch. Default false — with it off no server connects, even an
|
|
430
|
+
* individually-enabled one. */
|
|
431
|
+
enabled: boolean;
|
|
432
|
+
servers: McpServerConfig[];
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* `GET /api/ai/mcp` (admin only): the redacted config (every {@link
|
|
436
|
+
* McpServerConfig.authToken} stripped, {@link McpServerConfig.authTokenSet}
|
|
437
|
+
* flagged) plus `stdioAllowed` — whether this instance's trust level permits the
|
|
438
|
+
* `stdio` transport (true on a desktop / unclaimed instance, false once claimed).
|
|
439
|
+
* The UI hides the stdio option when false; the PUT route enforces the same rule.
|
|
440
|
+
*/
|
|
441
|
+
export interface McpConfigResponse {
|
|
442
|
+
config: McpClientConfig;
|
|
443
|
+
stdioAllowed: boolean;
|
|
444
|
+
}
|
|
445
|
+
/** Result of `POST /api/ai/mcp/test` (admin only): a connect + list-tools dry-run
|
|
446
|
+
* against one server config. Never returns secrets. */
|
|
447
|
+
export interface McpTestResult {
|
|
448
|
+
ok: boolean;
|
|
449
|
+
/** Tool names discovered on a successful connect. */
|
|
450
|
+
tools?: string[];
|
|
451
|
+
/** A human-readable failure reason (error class / message), never headers/env. */
|
|
452
|
+
error?: string;
|
|
349
453
|
}
|
|
350
454
|
/**
|
|
351
455
|
* A user-authored prompt/recipe skill: markdown instructions the agent can
|
package/dist/authorize.js
CHANGED
|
@@ -32,12 +32,15 @@ export function isEmailAuthoritative(principal, config) {
|
|
|
32
32
|
* satisfy an `account.book.pub`-scoped email grant.
|
|
33
33
|
*/
|
|
34
34
|
function matchAcl(principal, acl, ctx) {
|
|
35
|
-
|
|
35
|
+
// A **subject** entry matches a `jws` OR a `pat` principal with that subject: an
|
|
36
|
+
// agent PAT (AGENT-6) rides the exact subject-keyed grants its bound user has. An
|
|
37
|
+
// **email** entry stays jws-only (a PAT carries no persona email — see below).
|
|
38
|
+
const subjectEligible = principal.verifiedVia === 'jws' || principal.verifiedVia === 'pat';
|
|
36
39
|
let best = null;
|
|
37
40
|
for (const entry of acl) {
|
|
38
41
|
let matches = false;
|
|
39
42
|
if (entry.subject) {
|
|
40
|
-
matches =
|
|
43
|
+
matches = subjectEligible && entry.subject === principal.subject;
|
|
41
44
|
}
|
|
42
45
|
else if (entry.email) {
|
|
43
46
|
matches =
|
|
@@ -62,8 +65,9 @@ function scopeAllowsRead(principal, ctx, guestBlocked) {
|
|
|
62
65
|
// guest when `guestAccess='off'` (rule 6 / footnote ¹).
|
|
63
66
|
return !guestBlocked;
|
|
64
67
|
case 'authenticated':
|
|
65
|
-
// Any signed-in (jws) user
|
|
66
|
-
|
|
68
|
+
// Any signed-in (jws) user, or an agent PAT bound to one (AGENT-6); guests
|
|
69
|
+
// denied (N8).
|
|
70
|
+
return principal.verifiedVia === 'jws' || principal.verifiedVia === 'pat';
|
|
67
71
|
case 'members':
|
|
68
72
|
// Only active roster members — an active row resolves to a non-null role.
|
|
69
73
|
// A signed-in non-member or invited/suspended persona (role null) gets
|
|
@@ -94,13 +98,20 @@ export function authorize(principal, page, ctx) {
|
|
|
94
98
|
const { config } = ctx;
|
|
95
99
|
const isLocal = principal.verifiedVia === 'local';
|
|
96
100
|
const isJws = principal.verifiedVia === 'jws';
|
|
101
|
+
// An agent PAT (AGENT-6) rides the SUBJECT-keyed rungs its bound user would —
|
|
102
|
+
// owner-content (rule 2), subject-ACL (rule 3), authenticated-read (rule 5), and
|
|
103
|
+
// the unclaimed rule-0 short-circuit — but is NEVER a roster member (rule 4:
|
|
104
|
+
// `ctx.role` is jws-only via `resolveMemberRole`, so a PAT can't ride the
|
|
105
|
+
// admin/viewer rung) and carries no persona email (no email-ACL). Its write
|
|
106
|
+
// ceiling is additionally enforced out-of-band by the HTTP scope-gate.
|
|
107
|
+
const isPat = principal.verifiedVia === 'pat';
|
|
97
108
|
// Rule 0 — unclaimed instance: legacy short-circuit, preserving today's
|
|
98
109
|
// loopback behaviour exactly. Roster/scope/ACL don't exist until claimed; the
|
|
99
110
|
// in-process (`local`) and any `jws` caller always read+write (truth-table
|
|
100
111
|
// footer), everyone else is judged by the guest gate. Reachable only on
|
|
101
112
|
// loopback (the §2.6 exposure invariant — a claim is required before exposure).
|
|
102
113
|
if (config.ownerSubject === undefined) {
|
|
103
|
-
const privileged = isJws || isLocal;
|
|
114
|
+
const privileged = isJws || isLocal || isPat;
|
|
104
115
|
return {
|
|
105
116
|
canRead: config.guestAccess !== 'off' || privileged,
|
|
106
117
|
canWrite: config.guestAccess === 'write' || privileged,
|
|
@@ -108,7 +119,7 @@ export function authorize(principal, page, ctx) {
|
|
|
108
119
|
};
|
|
109
120
|
}
|
|
110
121
|
// ── Claimed instance ──────────────────────────────────────────────────────
|
|
111
|
-
const isOwner = isJws && principal.subject === config.ownerSubject; // rule 2
|
|
122
|
+
const isOwner = (isJws || isPat) && principal.subject === config.ownerSubject; // rule 2
|
|
112
123
|
const aclMatch = matchAcl(principal, page.acl, ctx); // rule 3
|
|
113
124
|
const isAdmin = ctx.role === 'admin'; // rule 4
|
|
114
125
|
const isViewer = ctx.role === 'viewer'; // rule 4
|
|
@@ -120,7 +131,7 @@ export function authorize(principal, page, ctx) {
|
|
|
120
131
|
// past the `guestAccess='off'` floor onto a `public` page either (defence in
|
|
121
132
|
// depth behind the middleware, which already rejects such principals at the gate
|
|
122
133
|
// on an identity-enabled instance).
|
|
123
|
-
const guestBlocked = !isJws && !isLocal && config.guestAccess === 'off';
|
|
134
|
+
const guestBlocked = !isJws && !isLocal && !isPat && config.guestAccess === 'off';
|
|
124
135
|
const scopeRead = scopeAllowsRead(principal, ctx, guestBlocked); // rule 5
|
|
125
136
|
// WRITE — only rules 1/2/3(write)/4(admin) ever grant it. `viewer` is locked,
|
|
126
137
|
// jws-non-members and guests are read-only on a claimed instance.
|
package/dist/authorize.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../src/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA2EH;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAoB,EACpB,MAA8C;IAE9C,OAAO,CACL,SAAS,CAAC,WAAW,KAAK,KAAK;QAC/B,CAAC,CAAC,MAAM,CAAC,cAAc;QACvB,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC,cAAc,CAC3C,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,SAAoB,EAAE,GAAe,EAAE,GAAc;IACrE,MAAM,
|
|
1
|
+
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../src/authorize.ts"],"names":[],"mappings":"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"}
|
package/dist/backup.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import type { StoredPage } from './types';
|
|
13
13
|
import type { StoredDatabase } from './database';
|
|
14
14
|
export declare const BACKUP_VERSION = 1;
|
|
15
|
-
export interface
|
|
15
|
+
export interface LibraryBackup {
|
|
16
16
|
version: number;
|
|
17
17
|
exportedAt: string;
|
|
18
18
|
pages: StoredPage[];
|
package/dist/bookFolder.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { StoredDatabase } from './database';
|
|
|
3
3
|
/**
|
|
4
4
|
* Whole-space → folder-of-files serialisation, shared by every "dump my books
|
|
5
5
|
* to a folder" surface: the desktop's native folder export and the web app's
|
|
6
|
-
* File System Access export both call {@link
|
|
6
|
+
* File System Access export both call {@link libraryToBookFiles}, and the layout
|
|
7
7
|
* is byte-compatible with the server's on-disk {@link BookMirror} (OB-134) so a
|
|
8
8
|
* folder written by one can be re-imported by the other.
|
|
9
9
|
*
|
|
@@ -19,33 +19,49 @@ export interface BookFolderFile {
|
|
|
19
19
|
path: string;
|
|
20
20
|
contents: string;
|
|
21
21
|
}
|
|
22
|
-
/** Everything in a space, as returned by `DataClient.
|
|
23
|
-
export interface
|
|
22
|
+
/** Everything in a space, as returned by `DataClient.exportLibrary`. */
|
|
23
|
+
export interface LibrarySnapshot {
|
|
24
24
|
pages: StoredPage[];
|
|
25
25
|
databases: StoredDatabase[];
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Lossless structured sidecar filename that NEW exports write, parsed back by
|
|
29
|
+
* {@link parseBookFolder}. Renamed from the legacy `openbook.space.json`
|
|
30
|
+
* (LIB-4): the writer emits only this, while the reader also accepts
|
|
31
|
+
* {@link LEGACY_SPACE_BUNDLE_FILE} so folders exported before the rename still
|
|
32
|
+
* re-import losslessly.
|
|
33
|
+
*/
|
|
34
|
+
export declare const SPACE_BUNDLE_FILE = "openbook.library.json";
|
|
35
|
+
/**
|
|
36
|
+
* The pre-LIB-4 sidecar filename. READ-ONLY back-compat: {@link parseBookFolder}
|
|
37
|
+
* falls back to it so already-exported book folders keep importing. The writer
|
|
38
|
+
* never emits it.
|
|
39
|
+
*/
|
|
40
|
+
export declare const LEGACY_SPACE_BUNDLE_FILE = "openbook.space.json";
|
|
29
41
|
/**
|
|
30
42
|
* The whole-space **source-island** payload embedded in a standalone *site* HTML
|
|
31
|
-
* export: the full {@link
|
|
43
|
+
* export: the full {@link LibrarySnapshot} (pages + databases + nesting via each
|
|
32
44
|
* page's `parentId`/`databaseId`) plus the root id shown first. Same structure as
|
|
33
45
|
* {@link SPACE_BUNDLE_FILE}, so a site export re-imports with structure intact.
|
|
34
46
|
*/
|
|
35
|
-
export interface
|
|
47
|
+
export interface LibraryIsland {
|
|
36
48
|
version: 1;
|
|
37
49
|
rootId: string;
|
|
38
|
-
space:
|
|
50
|
+
space: LibrarySnapshot;
|
|
39
51
|
}
|
|
40
52
|
/** Wrap a whole-space bundle as its source-island `<script>` (versioned, escaped). */
|
|
41
|
-
export declare function
|
|
53
|
+
export declare function libraryIslandScript(rootId: string, space: LibrarySnapshot, opts?: {
|
|
42
54
|
attrs?: string;
|
|
43
55
|
indent?: string;
|
|
44
56
|
}): string;
|
|
45
|
-
/**
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Read a site export's space island back, or `null` when absent/corrupt.
|
|
59
|
+
* Dual-read: prefer the new `library` key, fall back to the legacy `space` key
|
|
60
|
+
* so bundles published before LIB-4 still import.
|
|
61
|
+
*/
|
|
62
|
+
export declare function readLibraryIsland(html: string): LibraryIsland | null;
|
|
63
|
+
/** Options for {@link libraryToBookFiles}. */
|
|
64
|
+
export interface LibraryToBookFilesOptions {
|
|
49
65
|
/** Include the lossless {@link SPACE_BUNDLE_FILE} sidecar. Default true. */
|
|
50
66
|
includeBundle?: boolean;
|
|
51
67
|
/**
|
|
@@ -63,14 +79,15 @@ export interface SpaceToBookFilesOptions {
|
|
|
63
79
|
* Serialise a space to its on-disk files. By default includes the lossless
|
|
64
80
|
* {@link SPACE_BUNDLE_FILE}; pass `includeBundle: false` for the human-readable
|
|
65
81
|
* HTML files only. Pass `runtime` (the viewer bundle source) to make the folder
|
|
66
|
-
* self-hydrating — see {@link
|
|
82
|
+
* self-hydrating — see {@link LibraryToBookFilesOptions.runtime}.
|
|
67
83
|
*/
|
|
68
|
-
export declare function
|
|
84
|
+
export declare function libraryToBookFiles(snapshot: LibrarySnapshot, opts?: LibraryToBookFilesOptions): BookFolderFile[];
|
|
69
85
|
/**
|
|
70
|
-
* Reconstruct a space from a folder's files. Prefers the lossless
|
|
71
|
-
* {@link SPACE_BUNDLE_FILE}
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
86
|
+
* Reconstruct a space from a folder's files. Prefers the lossless structured
|
|
87
|
+
* sidecar ({@link SPACE_BUNDLE_FILE}, or the legacy {@link LEGACY_SPACE_BUNDLE_FILE}
|
|
88
|
+
* for folders exported before LIB-4) when present; otherwise falls back to
|
|
89
|
+
* parsing the `.html` files into a flat list of pages (no databases, no nesting
|
|
90
|
+
* — the most a human-readable folder can recover). Returns `null` if nothing
|
|
91
|
+
* parseable was found, so the caller can surface "not an OpenBook folder".
|
|
75
92
|
*/
|
|
76
|
-
export declare function parseBookFolder(files: BookFolderFile[]):
|
|
93
|
+
export declare function parseBookFolder(files: BookFolderFile[]): LibrarySnapshot | null;
|
package/dist/bookFolder.js
CHANGED
|
@@ -1,22 +1,40 @@
|
|
|
1
1
|
import { pageToBookHtml, bookHtmlToPage, slugify, BOOK_RUNTIME_FILE } from './bookfile';
|
|
2
2
|
import { islandScript, readIsland } from './island';
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Lossless structured sidecar filename that NEW exports write, parsed back by
|
|
5
|
+
* {@link parseBookFolder}. Renamed from the legacy `openbook.space.json`
|
|
6
|
+
* (LIB-4): the writer emits only this, while the reader also accepts
|
|
7
|
+
* {@link LEGACY_SPACE_BUNDLE_FILE} so folders exported before the rename still
|
|
8
|
+
* re-import losslessly.
|
|
9
|
+
*/
|
|
10
|
+
export const SPACE_BUNDLE_FILE = 'openbook.library.json';
|
|
11
|
+
/**
|
|
12
|
+
* The pre-LIB-4 sidecar filename. READ-ONLY back-compat: {@link parseBookFolder}
|
|
13
|
+
* falls back to it so already-exported book folders keep importing. The writer
|
|
14
|
+
* never emits it.
|
|
15
|
+
*/
|
|
16
|
+
export const LEGACY_SPACE_BUNDLE_FILE = 'openbook.space.json';
|
|
5
17
|
/** Wrap a whole-space bundle as its source-island `<script>` (versioned, escaped). */
|
|
6
|
-
export function
|
|
7
|
-
|
|
18
|
+
export function libraryIslandScript(rootId, space, opts = {}) {
|
|
19
|
+
// Writer emits ONLY the new `library` key; the reader dual-reads for back-compat.
|
|
20
|
+
return islandScript({ version: 1, rootId, library: space }, opts);
|
|
8
21
|
}
|
|
9
|
-
/**
|
|
10
|
-
export
|
|
22
|
+
/**
|
|
23
|
+
* Read a site export's space island back, or `null` when absent/corrupt.
|
|
24
|
+
* Dual-read: prefer the new `library` key, fall back to the legacy `space` key
|
|
25
|
+
* so bundles published before LIB-4 still import.
|
|
26
|
+
*/
|
|
27
|
+
export function readLibraryIsland(html) {
|
|
11
28
|
const parsed = readIsland(html);
|
|
12
|
-
|
|
29
|
+
const bundle = parsed?.library ?? parsed?.space;
|
|
30
|
+
if (!bundle || !Array.isArray(bundle.pages))
|
|
13
31
|
return null;
|
|
14
32
|
return {
|
|
15
33
|
version: 1,
|
|
16
|
-
rootId: parsed
|
|
34
|
+
rootId: parsed?.rootId ?? '',
|
|
17
35
|
space: {
|
|
18
|
-
pages:
|
|
19
|
-
databases: Array.isArray(
|
|
36
|
+
pages: bundle.pages,
|
|
37
|
+
databases: Array.isArray(bundle.databases) ? bundle.databases : [],
|
|
20
38
|
},
|
|
21
39
|
};
|
|
22
40
|
}
|
|
@@ -47,9 +65,9 @@ function rootOf(page, byId, dbHost) {
|
|
|
47
65
|
* Serialise a space to its on-disk files. By default includes the lossless
|
|
48
66
|
* {@link SPACE_BUNDLE_FILE}; pass `includeBundle: false` for the human-readable
|
|
49
67
|
* HTML files only. Pass `runtime` (the viewer bundle source) to make the folder
|
|
50
|
-
* self-hydrating — see {@link
|
|
68
|
+
* self-hydrating — see {@link LibraryToBookFilesOptions.runtime}.
|
|
51
69
|
*/
|
|
52
|
-
export function
|
|
70
|
+
export function libraryToBookFiles(snapshot, opts = {}) {
|
|
53
71
|
const { pages, databases } = snapshot;
|
|
54
72
|
const byId = new Map(pages.map((p) => [p.id, p]));
|
|
55
73
|
const dbHost = new Map(databases.map((d) => [d.id, d.pageId]));
|
|
@@ -73,15 +91,21 @@ export function spaceToBookFiles(snapshot, opts = {}) {
|
|
|
73
91
|
}
|
|
74
92
|
return files;
|
|
75
93
|
}
|
|
94
|
+
/** Match a sidecar file by basename — the new name first, then the legacy one. */
|
|
95
|
+
const isSpaceBundleFile = (path) => path === SPACE_BUNDLE_FILE ||
|
|
96
|
+
path.endsWith(`/${SPACE_BUNDLE_FILE}`) ||
|
|
97
|
+
path === LEGACY_SPACE_BUNDLE_FILE ||
|
|
98
|
+
path.endsWith(`/${LEGACY_SPACE_BUNDLE_FILE}`);
|
|
76
99
|
/**
|
|
77
|
-
* Reconstruct a space from a folder's files. Prefers the lossless
|
|
78
|
-
* {@link SPACE_BUNDLE_FILE}
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
100
|
+
* Reconstruct a space from a folder's files. Prefers the lossless structured
|
|
101
|
+
* sidecar ({@link SPACE_BUNDLE_FILE}, or the legacy {@link LEGACY_SPACE_BUNDLE_FILE}
|
|
102
|
+
* for folders exported before LIB-4) when present; otherwise falls back to
|
|
103
|
+
* parsing the `.html` files into a flat list of pages (no databases, no nesting
|
|
104
|
+
* — the most a human-readable folder can recover). Returns `null` if nothing
|
|
105
|
+
* parseable was found, so the caller can surface "not an OpenBook folder".
|
|
82
106
|
*/
|
|
83
107
|
export function parseBookFolder(files) {
|
|
84
|
-
const bundle = files.find((f) => f.path
|
|
108
|
+
const bundle = files.find((f) => isSpaceBundleFile(f.path));
|
|
85
109
|
if (bundle) {
|
|
86
110
|
try {
|
|
87
111
|
const parsed = JSON.parse(bundle.contents);
|
package/dist/bookFolder.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bookFolder.js","sourceRoot":"","sources":["../src/bookFolder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,cAAc,EAAE,cAAc,EAAE,OAAO,EAAE,iBAAiB,EAAC,MAAM,YAAY,CAAC;AACtF,OAAO,EAAC,YAAY,EAAE,UAAU,EAAC,MAAM,UAAU,CAAC;AA6BlD
|
|
1
|
+
{"version":3,"file":"bookFolder.js","sourceRoot":"","sources":["../src/bookFolder.ts"],"names":[],"mappings":"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"}
|
package/dist/bookfile.d.ts
CHANGED
|
@@ -121,7 +121,7 @@ export interface BookHtmlOptions {
|
|
|
121
121
|
* Reference the folder's shared viewer runtime (`_openbook/viewer.js`) so the
|
|
122
122
|
* file, opened directly in a browser, hydrates into the interactive locked
|
|
123
123
|
* viewer. Pass true ONLY when the writer also ships the bundle into the folder
|
|
124
|
-
* (sdk `
|
|
124
|
+
* (sdk `libraryToBookFiles({runtime})` / server `BookMirror` with `runtimeBundle`)
|
|
125
125
|
* — a reference without the bundle degrades gracefully (static article), but
|
|
126
126
|
* writers keep the invariant anyway. Emitters MUST agree on this flag for the
|
|
127
127
|
* SDK/server byte-compatibility contract to hold.
|
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type CompactResult } from './routes';
|
|
2
2
|
import type { PluginPackage, StoredPlugin } from './plugins';
|
|
3
|
-
import type { AgentChatEvent, AgentChatMessage, AgentChatOptions, AiConfig, AiPricingResponse, AiPricingTable, AiUsageResponse, AiSearchResponse, AiSkill, AiStatus, AiTasksResponse } from './ai';
|
|
3
|
+
import type { AgentChatEvent, AgentChatMessage, AgentChatOptions, AiConfig, AiPricingResponse, AiPricingTable, AiUsageResponse, AiSearchResponse, AiSkill, AiStatus, AiTasksResponse, McpClientConfig, McpConfigResponse, McpServerConfig, McpTestResult } from './ai';
|
|
4
4
|
import type { AclLevel, Member, MemberRole, MemberStatus, PageAcl, PageInput, PageMeta, PageVisibility, StoredPage } from './types';
|
|
5
5
|
import type { InstanceConfig, InstanceInfo, StoredEdit } from './provenance';
|
|
6
|
+
import type { AgentTokenMeta, AgentTokenScope } from './identity';
|
|
6
7
|
import type { BackupCadence, BackupConfig, BackupStatus, ImportRequest, ImportResult } from './backup';
|
|
7
8
|
import type { DatabaseInput, DatabaseRow, DatabaseUpdate, RowInput, RowUpdate, StoredDatabase } from './database';
|
|
8
9
|
import type { CommentInput, StoredComment, StoredSuggestion, SuggestionInput, SuggestionStatus, SuggestionUpdate } from './suggestions';
|
|
@@ -13,6 +14,23 @@ export interface PageSubscription {
|
|
|
13
14
|
/** The page was deleted. */
|
|
14
15
|
onDeleted?: (id: string) => void;
|
|
15
16
|
}
|
|
17
|
+
/** Input to {@link DataClient.createAgentToken}. `scope` defaults to `read`;
|
|
18
|
+
* `expiresInDays` defaults to 90 server-side, and `null` mints a no-expiry token. */
|
|
19
|
+
export interface CreateAgentTokenInput {
|
|
20
|
+
name: string;
|
|
21
|
+
scope?: AgentTokenScope;
|
|
22
|
+
expiresInDays?: number | null;
|
|
23
|
+
}
|
|
24
|
+
/** The one-time create response: the plaintext `token` (shown ONCE) + its meta. */
|
|
25
|
+
export interface CreatedAgentToken {
|
|
26
|
+
token: string;
|
|
27
|
+
meta: AgentTokenMeta;
|
|
28
|
+
}
|
|
29
|
+
/** The agent-token management view: the dark `agentApi` on/off state + the list. */
|
|
30
|
+
export interface AgentTokenList {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
tokens: AgentTokenMeta[];
|
|
33
|
+
}
|
|
16
34
|
/**
|
|
17
35
|
* Storage-agnostic data access used by the document UI.
|
|
18
36
|
*
|
|
@@ -90,6 +108,16 @@ export interface DataClient {
|
|
|
90
108
|
setAiUsageRetention(days: number): Promise<{
|
|
91
109
|
days: number;
|
|
92
110
|
}>;
|
|
111
|
+
/** Read the external-tools (MCP client) config (admin only): redacted config +
|
|
112
|
+
* whether the stdio transport is permitted on this instance. */
|
|
113
|
+
getMcpConfig(): Promise<McpConfigResponse>;
|
|
114
|
+
/** Save the external-tools (MCP client) config (admin only). Auth tokens are
|
|
115
|
+
* write-only (omit/blank preserves, a value sets, `null` clears). Returns the
|
|
116
|
+
* redacted result. */
|
|
117
|
+
putMcpConfig(config: McpClientConfig): Promise<McpConfigResponse>;
|
|
118
|
+
/** Dry-run one MCP server config (admin only): connect + list tools; never
|
|
119
|
+
* returns secrets. */
|
|
120
|
+
testMcpServer(server: McpServerConfig): Promise<McpTestResult>;
|
|
93
121
|
listPlugins(): Promise<StoredPlugin[]>;
|
|
94
122
|
installPlugin(pkg: PluginPackage): Promise<StoredPlugin>;
|
|
95
123
|
setPluginEnabled(id: string, enabled: boolean): Promise<StoredPlugin>;
|
|
@@ -101,12 +129,12 @@ export interface DataClient {
|
|
|
101
129
|
*/
|
|
102
130
|
deletePage(id: string): Promise<boolean>;
|
|
103
131
|
/** Export the whole space: every live page (full data) + every database. */
|
|
104
|
-
|
|
132
|
+
exportLibrary(): Promise<{
|
|
105
133
|
pages: StoredPage[];
|
|
106
134
|
databases: StoredDatabase[];
|
|
107
135
|
}>;
|
|
108
136
|
/** Restore a (client-selected) set of pages/databases; see {@link ImportRequest}. */
|
|
109
|
-
|
|
137
|
+
importLibrary(req: ImportRequest): Promise<ImportResult>;
|
|
110
138
|
/** List the trash (most-recently-deleted first). */
|
|
111
139
|
listTrash(): Promise<PageMeta[]>;
|
|
112
140
|
/** Restore a trashed page, or `null` if it isn't in the trash. */
|
|
@@ -269,6 +297,17 @@ export interface DataClient {
|
|
|
269
297
|
}): Promise<Member>;
|
|
270
298
|
/** Revoke a roster row by id. `true` if one was removed. */
|
|
271
299
|
removeMember(id: string): Promise<boolean>;
|
|
300
|
+
/** List minted agent tokens (redacted) plus the dark `agentApi` on/off state. */
|
|
301
|
+
listAgentTokens(): Promise<AgentTokenList>;
|
|
302
|
+
/** Toggle the dark `agentApi` setting on/off. Returns the new state. */
|
|
303
|
+
setAgentApiEnabled(enabled: boolean): Promise<{
|
|
304
|
+
enabled: boolean;
|
|
305
|
+
}>;
|
|
306
|
+
/** Mint a token (requires `agentApi` enabled). The plaintext `token` comes back
|
|
307
|
+
* exactly ONCE — store it now; only its hash is kept server-side. */
|
|
308
|
+
createAgentToken(input: CreateAgentTokenInput): Promise<CreatedAgentToken>;
|
|
309
|
+
/** Revoke a token by id. `true` if one was removed. */
|
|
310
|
+
revokeAgentToken(id: string): Promise<boolean>;
|
|
272
311
|
/** Scheduled-backup policy + per-cadence status. */
|
|
273
312
|
getBackupStatus(): Promise<BackupStatus>;
|
|
274
313
|
/** Update the backup policy (enable, cadences, retention, folder). Owner-only. */
|
|
@@ -404,11 +443,11 @@ export declare class HttpDataClient implements DataClient {
|
|
|
404
443
|
orderedIds: string[];
|
|
405
444
|
}): Promise<StoredPage>;
|
|
406
445
|
deletePage(id: string): Promise<boolean>;
|
|
407
|
-
|
|
446
|
+
exportLibrary(): Promise<{
|
|
408
447
|
pages: StoredPage[];
|
|
409
448
|
databases: StoredDatabase[];
|
|
410
449
|
}>;
|
|
411
|
-
|
|
450
|
+
importLibrary(req: ImportRequest): Promise<ImportResult>;
|
|
412
451
|
listTrash(): Promise<PageMeta[]>;
|
|
413
452
|
restorePage(id: string): Promise<StoredPage | null>;
|
|
414
453
|
purgePage(id: string): Promise<boolean>;
|
|
@@ -501,6 +540,12 @@ export declare class HttpDataClient implements DataClient {
|
|
|
501
540
|
}): Promise<Member>;
|
|
502
541
|
/** Revoke a roster row by id. `true` if one was removed. */
|
|
503
542
|
removeMember(id: string): Promise<boolean>;
|
|
543
|
+
listAgentTokens(): Promise<AgentTokenList>;
|
|
544
|
+
setAgentApiEnabled(enabled: boolean): Promise<{
|
|
545
|
+
enabled: boolean;
|
|
546
|
+
}>;
|
|
547
|
+
createAgentToken(input: CreateAgentTokenInput): Promise<CreatedAgentToken>;
|
|
548
|
+
revokeAgentToken(id: string): Promise<boolean>;
|
|
504
549
|
/** A page's stored visibility scope (raw — `inherit` not yet resolved), or
|
|
505
550
|
* `null` if the page does not exist. Gated on read of the page. */
|
|
506
551
|
getPageVisibility(pageId: string): Promise<PageVisibility | null>;
|
|
@@ -554,6 +599,9 @@ export declare class HttpDataClient implements DataClient {
|
|
|
554
599
|
aiDeleteSkill(name: string): Promise<boolean>;
|
|
555
600
|
getAiPricing(): Promise<AiPricingResponse>;
|
|
556
601
|
setAiPricing(override: AiPricingTable): Promise<AiPricingResponse>;
|
|
602
|
+
getMcpConfig(): Promise<McpConfigResponse>;
|
|
603
|
+
putMcpConfig(config: McpClientConfig): Promise<McpConfigResponse>;
|
|
604
|
+
testMcpServer(server: McpServerConfig): Promise<McpTestResult>;
|
|
557
605
|
getAiUsage(): Promise<AiUsageResponse>;
|
|
558
606
|
setAiUsageRetention(days: number): Promise<{
|
|
559
607
|
days: number;
|