@book.dev/sdk 1.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/account.d.ts +57 -0
  4. package/dist/account.js +104 -0
  5. package/dist/account.js.map +1 -0
  6. package/dist/ai.d.ts +264 -0
  7. package/dist/ai.js +36 -0
  8. package/dist/ai.js.map +1 -0
  9. package/dist/backup.d.ts +52 -0
  10. package/dist/backup.js +35 -0
  11. package/dist/backup.js.map +1 -0
  12. package/dist/bookFolder.d.ts +44 -0
  13. package/dist/bookFolder.js +98 -0
  14. package/dist/bookFolder.js.map +1 -0
  15. package/dist/bookfile.d.ts +42 -0
  16. package/dist/bookfile.js +159 -0
  17. package/dist/bookfile.js.map +1 -0
  18. package/dist/client.d.ts +279 -0
  19. package/dist/client.js +502 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/connection.d.ts +20 -0
  22. package/dist/connection.js +77 -0
  23. package/dist/connection.js.map +1 -0
  24. package/dist/content.d.ts +38 -0
  25. package/dist/content.js +107 -0
  26. package/dist/content.js.map +1 -0
  27. package/dist/database.d.ts +687 -0
  28. package/dist/database.js +1082 -0
  29. package/dist/database.js.map +1 -0
  30. package/dist/formula.d.ts +41 -0
  31. package/dist/formula.js +469 -0
  32. package/dist/formula.js.map +1 -0
  33. package/dist/forwarding/challenge.d.ts +35 -0
  34. package/dist/forwarding/challenge.js +45 -0
  35. package/dist/forwarding/challenge.js.map +1 -0
  36. package/dist/forwarding/encoding.d.ts +14 -0
  37. package/dist/forwarding/encoding.js +54 -0
  38. package/dist/forwarding/encoding.js.map +1 -0
  39. package/dist/forwarding/forwardingClient.d.ts +76 -0
  40. package/dist/forwarding/forwardingClient.js +128 -0
  41. package/dist/forwarding/forwardingClient.js.map +1 -0
  42. package/dist/forwarding/index.d.ts +5 -0
  43. package/dist/forwarding/index.js +14 -0
  44. package/dist/forwarding/index.js.map +1 -0
  45. package/dist/forwarding/siteKey.d.ts +12 -0
  46. package/dist/forwarding/siteKey.js +36 -0
  47. package/dist/forwarding/siteKey.js.map +1 -0
  48. package/dist/forwarding/tunnelClient.d.ts +56 -0
  49. package/dist/forwarding/tunnelClient.js +206 -0
  50. package/dist/forwarding/tunnelClient.js.map +1 -0
  51. package/dist/forwarding/tunnelProtocol.d.ts +45 -0
  52. package/dist/forwarding/tunnelProtocol.js +29 -0
  53. package/dist/forwarding/tunnelProtocol.js.map +1 -0
  54. package/dist/index.d.ts +23 -0
  55. package/dist/index.js +19 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/mtime.d.ts +51 -0
  58. package/dist/mtime.js +84 -0
  59. package/dist/mtime.js.map +1 -0
  60. package/dist/pageProperties.d.ts +80 -0
  61. package/dist/pageProperties.js +97 -0
  62. package/dist/pageProperties.js.map +1 -0
  63. package/dist/plugins.d.ts +110 -0
  64. package/dist/plugins.js +113 -0
  65. package/dist/plugins.js.map +1 -0
  66. package/dist/routes.d.ts +89 -0
  67. package/dist/routes.js +89 -0
  68. package/dist/routes.js.map +1 -0
  69. package/dist/sampleDocument.d.ts +25 -0
  70. package/dist/sampleDocument.js +67 -0
  71. package/dist/sampleDocument.js.map +1 -0
  72. package/dist/suggestions.d.ts +126 -0
  73. package/dist/suggestions.js +21 -0
  74. package/dist/suggestions.js.map +1 -0
  75. package/dist/templates.d.ts +35 -0
  76. package/dist/templates.js +555 -0
  77. package/dist/templates.js.map +1 -0
  78. package/dist/types.d.ts +146 -0
  79. package/dist/types.js +16 -0
  80. package/dist/types.js.map +1 -0
  81. package/package.json +33 -0
@@ -0,0 +1,97 @@
1
+ /** Reserved, stable id for the Owner (person) property. */
2
+ export const OWNER_PROPERTY_ID = 'sys_owner';
3
+ /** Reserved, stable id for the Verification property. */
4
+ export const VERIFICATION_PROPERTY_ID = 'sys_verification';
5
+ /** Reserved, stable id for the Backlinks (computed) property. */
6
+ export const BACKLINKS_PROPERTY_ID = 'sys_backlinks';
7
+ /**
8
+ * Reserved ids for a page's **appearance**, stored on `page.properties` so a
9
+ * page's theme / cover / typefaces travel with the document (sync across
10
+ * devices) rather than living only in the local browser. They are appearance
11
+ * metadata — not panel/column properties — so they are intentionally NOT part
12
+ * of {@link SYSTEM_PAGE_PROPERTIES}.
13
+ */
14
+ export const THEME_PROPERTY_ID = 'sys_theme';
15
+ export const COVER_PROPERTY_ID = 'sys_cover';
16
+ export const FONTS_PROPERTY_ID = 'sys_fonts';
17
+ /** The page's emoji icon (a string). Projected into {@link PageMeta} so the
18
+ * sidebar/tabs/mentions resolve it from the page list, not a per-page fetch. */
19
+ export const ICON_PROPERTY_ID = 'sys_icon';
20
+ /** The page's full-width layout flag (a boolean; absent = centered column). */
21
+ export const FULLWIDTH_PROPERTY_ID = 'sys_fullwidth';
22
+ /** The built-in properties every page carries, in panel order. */
23
+ export const SYSTEM_PAGE_PROPERTIES = [
24
+ { id: OWNER_PROPERTY_ID, name: 'Owner', type: 'person' },
25
+ { id: VERIFICATION_PROPERTY_ID, name: 'Verification', type: 'verification' },
26
+ { id: BACKLINKS_PROPERTY_ID, name: 'Backlinks', type: 'backlinks' },
27
+ ];
28
+ /** True when a stored value represents a verified page (ignoring expiry). */
29
+ export function isVerified(value) {
30
+ return !!value && typeof value === 'object' && value.verified === true;
31
+ }
32
+ /** True when a verified page's verification has lapsed (expiry is in the past). */
33
+ export function verificationExpired(value, nowMs = Date.now()) {
34
+ if (!isVerified(value))
35
+ return false;
36
+ const exp = value.expiresAt;
37
+ return !!exp && new Date(exp).getTime() <= nowMs;
38
+ }
39
+ /** True when a page is verified AND its verification has not lapsed. */
40
+ export function isVerificationActive(value, nowMs = Date.now()) {
41
+ return isVerified(value) && !verificationExpired(value, nowMs);
42
+ }
43
+ /**
44
+ * A verification value stamped as verified now (the caller supplies the time).
45
+ * `expiresAtIso` sets an expiry; omit/`null` for a verification that never
46
+ * lapses.
47
+ */
48
+ export function makeVerification(by, atIso, expiresAtIso) {
49
+ return {
50
+ verified: true,
51
+ by: by && by.trim() ? by.trim() : null,
52
+ at: atIso,
53
+ ...(expiresAtIso ? { expiresAt: expiresAtIso } : {}),
54
+ };
55
+ }
56
+ /**
57
+ * Pure: the set of page ids this snapshot links to, by scanning the EditorJS
58
+ * blocks for inline mention anchors (`<a … data-page-id="…">`). Order-preserving
59
+ * and de-duplicated — the out-edges of one page in the backlink graph.
60
+ *
61
+ * Works on both the raw HTML form (`data-page-id="id"`) and the JSON-escaped
62
+ * form (`data-page-id=\"id\"`) that appears once the document is serialised, so
63
+ * it can run over a parsed snapshot or a stringified one alike.
64
+ */
65
+ /**
66
+ * Pure: does a page's stored `properties` reference `id`? True when any property
67
+ * value equals `id`, or `id` is an element of an array-valued property (a
68
+ * `relation`). This lets the backlink graph count relation links — set on a
69
+ * row's properties — alongside inline `@`-mentions in the document.
70
+ */
71
+ export function propertiesReferencePage(properties, id) {
72
+ if (!properties)
73
+ return false;
74
+ for (const value of Object.values(properties)) {
75
+ if (value === id)
76
+ return true;
77
+ if (Array.isArray(value) && value.includes(id))
78
+ return true;
79
+ }
80
+ return false;
81
+ }
82
+ export function extractMentionIds(snapshot) {
83
+ const json = JSON.stringify(snapshot.editorjs ?? {});
84
+ const ids = [];
85
+ const seen = new Set();
86
+ const re = /data-page-id=\\?["']([^"'\\]+)/g;
87
+ let match;
88
+ while ((match = re.exec(json)) !== null) {
89
+ const id = match[1];
90
+ if (!seen.has(id)) {
91
+ seen.add(id);
92
+ ids.push(id);
93
+ }
94
+ }
95
+ return ids;
96
+ }
97
+ //# sourceMappingURL=pageProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pageProperties.js","sourceRoot":"","sources":["../src/pageProperties.ts"],"names":[],"mappings":"AAmBA,2DAA2D;AAC3D,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAC7C,yDAAyD;AACzD,MAAM,CAAC,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AAC3D,iEAAiE;AACjE,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAe,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAC7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAC7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAC7C;iFACiF;AACjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAC3C,+EAA+E;AAC/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAe,CAAC;AAarD,kEAAkE;AAClE,MAAM,CAAC,MAAM,sBAAsB,GAAuB;IACxD,EAAC,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAC;IACtD,EAAC,EAAE,EAAE,wBAAwB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAC;IAC1E,EAAC,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAC;CAClE,CAAC;AAEF,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAA2B,CAAC,QAAQ,KAAK,IAAI,CAAC;AAChG,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,KAAc,EAAE,QAAgB,IAAI,CAAC,GAAG,EAAE;IAC5E,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,MAAM,GAAG,GAAI,KAA2B,CAAC,SAAS,CAAC;IACnD,OAAO,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC;AACnD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAAE,QAAgB,IAAI,CAAC,GAAG,EAAE;IAC7E,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAiB,EAAE,KAAa,EAAE,YAA4B;IAC7F,OAAO;QACL,QAAQ,EAAE,IAAI;QACd,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI;QACtC,EAAE,EAAE,KAAK;QACT,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAC,SAAS,EAAE,YAAY,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACnD,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAsD,EAAE,EAAU;IACxG,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAwC;IACxE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,EAAE,GAAG,iCAAiC,CAAC;IAC7C,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The plugin contract: what a plugin package IS (a manifest + TypeScript
3
+ * source files), and the signing scheme that lets a registry vouch for one.
4
+ *
5
+ * Trust model, stated plainly: plugins run with the same privileges as the
6
+ * document's own live code — signing provides **provenance** (this exact
7
+ * content was published by a registry you trust), not sandboxing. Unsigned
8
+ * plugins install fine and are labelled unverified.
9
+ *
10
+ * Signing: Ed25519 over a canonical SHA-256 digest of the manifest + every
11
+ * file (sorted paths, length-prefixed — byte-stable across platforms). The
12
+ * app pins the first-party OpenBook registry key; users can trust additional
13
+ * registry keys, which is all a "third-party registry" needs to be.
14
+ */
15
+ /**
16
+ * An agent tool a plugin contributes. Declared in the manifest (so the server
17
+ * can read it from the stored manifest JSON and surface it to the agent without
18
+ * running any plugin code). The tool's `action` maps to a built-in write
19
+ * primitive that the confirm-gate then applies — so a plugin tool can propose
20
+ * workspace changes, but it cannot execute arbitrary server code. Signing
21
+ * provides provenance, NOT sandboxing — see the module trust note.
22
+ */
23
+ export interface PluginAgentTool {
24
+ /** Tool name the agent calls (namespaced to avoid clashing with built-ins). */
25
+ name: string;
26
+ /** What the tool does (shown to the model). */
27
+ description: string;
28
+ /** JSON-Schema for the tool's arguments object. */
29
+ parameters?: Record<string, unknown>;
30
+ /**
31
+ * The built-in primitive this tool drives. `append_blocks` proposes adding
32
+ * the given blocks to a page; `prompt` simply inlines `instructions` into the
33
+ * agent's context (a recipe). Kept deliberately small — no code execution.
34
+ */
35
+ action: 'append_blocks' | 'prompt';
36
+ /** For `action: 'prompt'`: the instructions inlined when the tool is invoked. */
37
+ instructions?: string;
38
+ }
39
+ export interface PluginManifest {
40
+ /** Stable reverse-DNS-ish identifier, e.g. `openbook.hello-world`. */
41
+ id: string;
42
+ name: string;
43
+ version: string;
44
+ description?: string;
45
+ author?: string;
46
+ /** Emoji shown in lists (keeps the gallery dependency-free). */
47
+ icon?: string;
48
+ /** Entry file inside the package, e.g. `src/index.ts`. */
49
+ main: string;
50
+ /** Agent tools this plugin contributes (read server-side from the manifest). */
51
+ agentTools?: PluginAgentTool[];
52
+ }
53
+ /** A plugin as stored/transported: manifest + its TypeScript source files. */
54
+ export interface PluginPackage {
55
+ manifest: PluginManifest;
56
+ /** path → source text (TypeScript or JavaScript). */
57
+ files: Record<string, string>;
58
+ signature?: PluginSignature;
59
+ }
60
+ export interface PluginSignature {
61
+ /** Human-readable registry name shown in the UI, e.g. `OpenBook Registry`. */
62
+ registry: string;
63
+ /** base64 raw Ed25519 public key of the signing registry. */
64
+ publicKey: string;
65
+ /** base64 Ed25519 signature over {@link canonicalDigest}. */
66
+ signature: string;
67
+ algorithm: 'ed25519';
68
+ }
69
+ /** An installed plugin row as the server stores/lists it. */
70
+ export interface StoredPlugin extends PluginPackage {
71
+ enabled: boolean;
72
+ installedAt: string;
73
+ /** Set by the client after verification — never trusted from the wire. */
74
+ verified?: boolean;
75
+ }
76
+ /** SHA-256 of the canonical bytes (hex) — the thing a registry signs. */
77
+ export declare function canonicalDigest(manifest: PluginManifest, files: Record<string, string>): Promise<string>;
78
+ /** Generate a registry keypair (raw public / pkcs8 private, base64). */
79
+ export declare function generateRegistryKeys(): Promise<{
80
+ publicKey: string;
81
+ privateKey: string;
82
+ }>;
83
+ /** Sign a package (registry-side tooling — needs the private key). */
84
+ export declare function signPlugin(pkg: {
85
+ manifest: PluginManifest;
86
+ files: Record<string, string>;
87
+ }, privateKeyBase64: string, registry: string, publicKeyBase64: string): Promise<PluginSignature>;
88
+ /**
89
+ * Verify a package against a set of trusted registry keys. Returns the
90
+ * matching trusted registry name, or null when unsigned, signed by an
91
+ * untrusted key, or tampered with.
92
+ */
93
+ export declare function verifyPlugin(pkg: PluginPackage, trustedKeys: Array<{
94
+ name: string;
95
+ publicKey: string;
96
+ }>): Promise<{
97
+ registry: string;
98
+ } | null>;
99
+ /**
100
+ * The pinned first-party registry key. Every OpenBook build trusts this;
101
+ * additional registries are user-added keys on top (Settings → Extensions).
102
+ * NOTE: a placeholder development key until the real registry launches —
103
+ * regenerate and replace before publishing plugins for real.
104
+ */
105
+ export declare const OPENBOOK_REGISTRY: {
106
+ name: string;
107
+ publicKey: string;
108
+ };
109
+ /** Validate a manifest's shape; returns a human-readable problem or null. */
110
+ export declare function validateManifest(m: unknown): string | null;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The plugin contract: what a plugin package IS (a manifest + TypeScript
3
+ * source files), and the signing scheme that lets a registry vouch for one.
4
+ *
5
+ * Trust model, stated plainly: plugins run with the same privileges as the
6
+ * document's own live code — signing provides **provenance** (this exact
7
+ * content was published by a registry you trust), not sandboxing. Unsigned
8
+ * plugins install fine and are labelled unverified.
9
+ *
10
+ * Signing: Ed25519 over a canonical SHA-256 digest of the manifest + every
11
+ * file (sorted paths, length-prefixed — byte-stable across platforms). The
12
+ * app pins the first-party OpenBook registry key; users can trust additional
13
+ * registry keys, which is all a "third-party registry" needs to be.
14
+ */
15
+ const te = new TextEncoder();
16
+ /**
17
+ * Deterministic bytes for signing: the manifest (sorted-key JSON), then each
18
+ * file in sorted path order, every part length-prefixed so boundaries can't
19
+ * be confused (`a + bc` ≠ `ab + c`).
20
+ */
21
+ function canonicalBytes(manifest, files) {
22
+ const parts = [];
23
+ const push = (s) => {
24
+ const bytes = te.encode(s);
25
+ const len = new Uint8Array(4);
26
+ new DataView(len.buffer).setUint32(0, bytes.length);
27
+ parts.push(len, bytes);
28
+ };
29
+ push(JSON.stringify(manifest, Object.keys(manifest).sort()));
30
+ for (const path of Object.keys(files).sort()) {
31
+ push(path);
32
+ push(files[path]);
33
+ }
34
+ const total = parts.reduce((n, p) => n + p.length, 0);
35
+ const out = new Uint8Array(total);
36
+ let at = 0;
37
+ for (const p of parts) {
38
+ out.set(p, at);
39
+ at += p.length;
40
+ }
41
+ return out;
42
+ }
43
+ /** SHA-256 of the canonical bytes (hex) — the thing a registry signs. */
44
+ export async function canonicalDigest(manifest, files) {
45
+ const hash = await crypto.subtle.digest('SHA-256', canonicalBytes(manifest, files));
46
+ return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, '0')).join('');
47
+ }
48
+ const fromBase64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
49
+ const toBase64 = (b) => btoa(String.fromCharCode(...b));
50
+ /** Generate a registry keypair (raw public / pkcs8 private, base64). */
51
+ export async function generateRegistryKeys() {
52
+ const pair = (await crypto.subtle.generateKey('Ed25519', true, ['sign', 'verify']));
53
+ const pub = new Uint8Array(await crypto.subtle.exportKey('raw', pair.publicKey));
54
+ const priv = new Uint8Array(await crypto.subtle.exportKey('pkcs8', pair.privateKey));
55
+ return { publicKey: toBase64(pub), privateKey: toBase64(priv) };
56
+ }
57
+ /** Sign a package (registry-side tooling — needs the private key). */
58
+ export async function signPlugin(pkg, privateKeyBase64, registry, publicKeyBase64) {
59
+ const key = await crypto.subtle.importKey('pkcs8', fromBase64(privateKeyBase64), 'Ed25519', false, ['sign']);
60
+ const digest = await canonicalDigest(pkg.manifest, pkg.files);
61
+ const sig = new Uint8Array(await crypto.subtle.sign('Ed25519', key, te.encode(digest)));
62
+ return { registry, publicKey: publicKeyBase64, signature: toBase64(sig), algorithm: 'ed25519' };
63
+ }
64
+ /**
65
+ * Verify a package against a set of trusted registry keys. Returns the
66
+ * matching trusted registry name, or null when unsigned, signed by an
67
+ * untrusted key, or tampered with.
68
+ */
69
+ export async function verifyPlugin(pkg, trustedKeys) {
70
+ const sig = pkg.signature;
71
+ if (!sig || sig.algorithm !== 'ed25519')
72
+ return null;
73
+ const trusted = trustedKeys.find((k) => k.publicKey === sig.publicKey);
74
+ if (!trusted)
75
+ return null;
76
+ try {
77
+ const key = await crypto.subtle.importKey('raw', fromBase64(sig.publicKey), 'Ed25519', false, ['verify']);
78
+ const digest = await canonicalDigest(pkg.manifest, pkg.files);
79
+ const ok = await crypto.subtle.verify('Ed25519', key, fromBase64(sig.signature), te.encode(digest));
80
+ return ok ? { registry: trusted.name } : null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ /**
87
+ * The pinned first-party registry key. Every OpenBook build trusts this;
88
+ * additional registries are user-added keys on top (Settings → Extensions).
89
+ * NOTE: a placeholder development key until the real registry launches —
90
+ * regenerate and replace before publishing plugins for real.
91
+ */
92
+ export const OPENBOOK_REGISTRY = {
93
+ name: 'OpenBook Registry',
94
+ publicKey: 'nI4eBQzqrIyVPEmJSEzGtqC9B0+kfWTXKyN5t8Yki/E=',
95
+ };
96
+ const PLUGIN_ID_RE = /^[a-z0-9][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*)+$/;
97
+ /** Validate a manifest's shape; returns a human-readable problem or null. */
98
+ export function validateManifest(m) {
99
+ if (!m || typeof m !== 'object')
100
+ return 'openbook.json is missing or not an object';
101
+ const man = m;
102
+ if (!man.id || typeof man.id !== 'string' || !PLUGIN_ID_RE.test(man.id)) {
103
+ return 'id must look like "publisher.plugin-name" (lowercase, dots and dashes)';
104
+ }
105
+ if (!man.name || typeof man.name !== 'string')
106
+ return 'name is required';
107
+ if (!man.version || typeof man.version !== 'string')
108
+ return 'version is required';
109
+ if (!man.main || typeof man.main !== 'string')
110
+ return 'main (the entry file) is required';
111
+ return null;
112
+ }
113
+ //# sourceMappingURL=plugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The HTTP contract shared by the server and clients. Keeping the paths in one
3
+ * place means `HttpDataClient` and the server's router cannot disagree about
4
+ * where a resource lives.
5
+ */
6
+ export declare const API: {
7
+ readonly health: "/health";
8
+ /** Collection: `GET` (list) / `POST` (create). */
9
+ readonly pages: "/api/pages";
10
+ /** Single page: `GET` / `PUT` (upsert) / `PATCH` (rename) / `DELETE` (to trash). */
11
+ readonly page: (id: string) => string;
12
+ /** A page's structured properties (owner, verification, …): `PATCH` (shallow merge). */
13
+ readonly pageProperties: (id: string) => string;
14
+ /** Pages that link to this one (the backlink graph): `GET`. */
15
+ readonly pageBacklinks: (id: string) => string;
16
+ /** Restore a trashed page (and the subtree trashed with it): `POST`. */
17
+ readonly pageRestore: (id: string) => string;
18
+ /** Move/reorder a page in the sidebar tree (re-parent + reorder siblings): `PUT`. */
19
+ readonly pageMove: (id: string) => string;
20
+ /** Whole-space backup: `GET` returns every live page + database as one bundle. */
21
+ readonly exportSpace: "/api/export";
22
+ /** Restore a backup: `POST` `{pages, databases, mode}` → import summary. */
23
+ readonly importSpace: "/api/import";
24
+ /** The trash: `GET` (list trashed pages) / `DELETE` (empty the whole trash). */
25
+ readonly trash: "/api/trash";
26
+ /** A single trashed page: `DELETE` (permanently purge it and its subtree). */
27
+ readonly trashItem: (id: string) => string;
28
+ /** SSE stream of the page list (created / renamed / deleted). */
29
+ readonly stream: "/api/stream";
30
+ /** SSE stream of a single page's live updates + deletion. */
31
+ readonly pageStream: (id: string) => string;
32
+ /**
33
+ * The multiplexed live stream: one SSE connection carrying every event (page
34
+ * list, page updates/deletions, database rows). Clients open exactly one of
35
+ * these per tab and filter by the ids they care about, so an open tab costs a
36
+ * single connection regardless of how many pages/databases it watches.
37
+ */
38
+ readonly live: "/api/live";
39
+ /** Collection: `POST` (create a database for a host page). */
40
+ readonly databases: "/api/databases";
41
+ /** Single database: `GET` / `PATCH` (name + schema) / `DELETE`. */
42
+ readonly database: (id: string) => string;
43
+ /** The database hosted by a page: `GET` (or 404 if the page hosts none). */
44
+ readonly pageDatabase: (pageId: string) => string;
45
+ /** A database's rows: `GET` (list) / `POST` (create a row page). */
46
+ readonly databaseRows: (id: string) => string;
47
+ /** Set the manual row order: `PUT` `{orderedIds}`. */
48
+ readonly databaseRowsOrder: (id: string) => string;
49
+ /** A single row: `PATCH` (title + manual properties). Row content/deletion use the page routes. */
50
+ readonly databaseRow: (id: string, rowId: string) => string;
51
+ /** SSE stream of a database's row list (any row created / edited / deleted). */
52
+ readonly databaseStream: (id: string) => string;
53
+ /** Engine status (provider, readiness, index state, download progress): `GET`. */
54
+ readonly aiStatus: "/api/ai/status";
55
+ /** Engine configuration: `PUT` `{provider, model?, baseUrl?, autoStart?}`. */
56
+ readonly aiConfig: "/api/ai/config";
57
+ /** (Re)build the note-search index: `POST`. */
58
+ readonly aiIndex: "/api/ai/index";
59
+ /** Search notes: `POST` `{query, limit?}` → ranked results + snippets. */
60
+ readonly aiSearch: "/api/ai/search";
61
+ /** Stream a completion: `POST` `{prompt, system?, maxTokens?}` → SSE. */
62
+ readonly aiGenerate: "/api/ai/generate";
63
+ /** Break a goal into actionable tasks: `POST` `{goal, context?}`. */
64
+ readonly aiTasks: "/api/ai/tasks";
65
+ /** Continue/complete document text: `POST` `{text, instruction?}` → SSE. */
66
+ readonly aiComplete: "/api/ai/complete";
67
+ /** Download a model file for the in-process engine: `POST` `{url?}`. */
68
+ readonly aiModelDownload: "/api/ai/models/download";
69
+ /** The agent harness: `POST` `{messages, effort?, thinking?, skills?}` → SSE tool/reasoning/proposal/final events. */
70
+ readonly agentChat: "/api/agent/chat";
71
+ /** User-authored prompt/recipe skills: `GET` (list) / `PUT` `{skill}` (upsert). */
72
+ readonly aiSkills: "/api/ai/skills";
73
+ /** One skill by name: `DELETE`. */
74
+ readonly aiSkill: (name: string) => string;
75
+ readonly plugins: "/api/plugins";
76
+ readonly plugin: (id: string) => string;
77
+ /** A page's suggestions: `GET` (list, optionally `?status=open`) / `POST` (create). */
78
+ readonly suggestions: (pageId: string) => string;
79
+ /** A single suggestion: `PATCH` (status: accepted/rejected) / `DELETE`. */
80
+ readonly suggestion: (id: string) => string;
81
+ /** A page's comments (standalone block comments + suggestion threads): `GET` / `POST` (create). */
82
+ readonly comments: (pageId: string) => string;
83
+ /** A single comment: `DELETE`. */
84
+ readonly comment: (id: string) => string;
85
+ };
86
+ /** Error body shape returned by the API for non-2xx responses. */
87
+ export interface ApiError {
88
+ error: string;
89
+ }
package/dist/routes.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The HTTP contract shared by the server and clients. Keeping the paths in one
3
+ * place means `HttpDataClient` and the server's router cannot disagree about
4
+ * where a resource lives.
5
+ */
6
+ export const API = {
7
+ health: '/health',
8
+ /** Collection: `GET` (list) / `POST` (create). */
9
+ pages: '/api/pages',
10
+ /** Single page: `GET` / `PUT` (upsert) / `PATCH` (rename) / `DELETE` (to trash). */
11
+ page: (id) => `/api/pages/${encodeURIComponent(id)}`,
12
+ /** A page's structured properties (owner, verification, …): `PATCH` (shallow merge). */
13
+ pageProperties: (id) => `/api/pages/${encodeURIComponent(id)}/properties`,
14
+ /** Pages that link to this one (the backlink graph): `GET`. */
15
+ pageBacklinks: (id) => `/api/pages/${encodeURIComponent(id)}/backlinks`,
16
+ /** Restore a trashed page (and the subtree trashed with it): `POST`. */
17
+ pageRestore: (id) => `/api/pages/${encodeURIComponent(id)}/restore`,
18
+ /** Move/reorder a page in the sidebar tree (re-parent + reorder siblings): `PUT`. */
19
+ pageMove: (id) => `/api/pages/${encodeURIComponent(id)}/move`,
20
+ /** Whole-space backup: `GET` returns every live page + database as one bundle. */
21
+ exportSpace: '/api/export',
22
+ /** Restore a backup: `POST` `{pages, databases, mode}` → import summary. */
23
+ importSpace: '/api/import',
24
+ /** The trash: `GET` (list trashed pages) / `DELETE` (empty the whole trash). */
25
+ trash: '/api/trash',
26
+ /** A single trashed page: `DELETE` (permanently purge it and its subtree). */
27
+ trashItem: (id) => `/api/trash/${encodeURIComponent(id)}`,
28
+ /** SSE stream of the page list (created / renamed / deleted). */
29
+ stream: '/api/stream',
30
+ /** SSE stream of a single page's live updates + deletion. */
31
+ pageStream: (id) => `/api/pages/${encodeURIComponent(id)}/stream`,
32
+ /**
33
+ * The multiplexed live stream: one SSE connection carrying every event (page
34
+ * list, page updates/deletions, database rows). Clients open exactly one of
35
+ * these per tab and filter by the ids they care about, so an open tab costs a
36
+ * single connection regardless of how many pages/databases it watches.
37
+ */
38
+ live: '/api/live',
39
+ // ── Databases ──────────────────────────────────────────────────────────────
40
+ /** Collection: `POST` (create a database for a host page). */
41
+ databases: '/api/databases',
42
+ /** Single database: `GET` / `PATCH` (name + schema) / `DELETE`. */
43
+ database: (id) => `/api/databases/${encodeURIComponent(id)}`,
44
+ /** The database hosted by a page: `GET` (or 404 if the page hosts none). */
45
+ pageDatabase: (pageId) => `/api/pages/${encodeURIComponent(pageId)}/database`,
46
+ /** A database's rows: `GET` (list) / `POST` (create a row page). */
47
+ databaseRows: (id) => `/api/databases/${encodeURIComponent(id)}/rows`,
48
+ /** Set the manual row order: `PUT` `{orderedIds}`. */
49
+ databaseRowsOrder: (id) => `/api/databases/${encodeURIComponent(id)}/rows/order`,
50
+ /** A single row: `PATCH` (title + manual properties). Row content/deletion use the page routes. */
51
+ databaseRow: (id, rowId) => `/api/databases/${encodeURIComponent(id)}/rows/${encodeURIComponent(rowId)}`,
52
+ /** SSE stream of a database's row list (any row created / edited / deleted). */
53
+ databaseStream: (id) => `/api/databases/${encodeURIComponent(id)}/stream`,
54
+ // ── Optional local AI ──────────────────────────────────────────────────────
55
+ /** Engine status (provider, readiness, index state, download progress): `GET`. */
56
+ aiStatus: '/api/ai/status',
57
+ /** Engine configuration: `PUT` `{provider, model?, baseUrl?, autoStart?}`. */
58
+ aiConfig: '/api/ai/config',
59
+ /** (Re)build the note-search index: `POST`. */
60
+ aiIndex: '/api/ai/index',
61
+ /** Search notes: `POST` `{query, limit?}` → ranked results + snippets. */
62
+ aiSearch: '/api/ai/search',
63
+ /** Stream a completion: `POST` `{prompt, system?, maxTokens?}` → SSE. */
64
+ aiGenerate: '/api/ai/generate',
65
+ /** Break a goal into actionable tasks: `POST` `{goal, context?}`. */
66
+ aiTasks: '/api/ai/tasks',
67
+ /** Continue/complete document text: `POST` `{text, instruction?}` → SSE. */
68
+ aiComplete: '/api/ai/complete',
69
+ /** Download a model file for the in-process engine: `POST` `{url?}`. */
70
+ aiModelDownload: '/api/ai/models/download',
71
+ /** The agent harness: `POST` `{messages, effort?, thinking?, skills?}` → SSE tool/reasoning/proposal/final events. */
72
+ agentChat: '/api/agent/chat',
73
+ /** User-authored prompt/recipe skills: `GET` (list) / `PUT` `{skill}` (upsert). */
74
+ aiSkills: '/api/ai/skills',
75
+ /** One skill by name: `DELETE`. */
76
+ aiSkill: (name) => `/api/ai/skills/${encodeURIComponent(name)}`,
77
+ plugins: '/api/plugins',
78
+ plugin: (id) => `/api/plugins/${id}`,
79
+ // ── Suggestions + comments (the review layer) ────────────────────────────────
80
+ /** A page's suggestions: `GET` (list, optionally `?status=open`) / `POST` (create). */
81
+ suggestions: (pageId) => `/api/pages/${encodeURIComponent(pageId)}/suggestions`,
82
+ /** A single suggestion: `PATCH` (status: accepted/rejected) / `DELETE`. */
83
+ suggestion: (id) => `/api/suggestions/${encodeURIComponent(id)}`,
84
+ /** A page's comments (standalone block comments + suggestion threads): `GET` / `POST` (create). */
85
+ comments: (pageId) => `/api/pages/${encodeURIComponent(pageId)}/comments`,
86
+ /** A single comment: `DELETE`. */
87
+ comment: (id) => `/api/comments/${encodeURIComponent(id)}`,
88
+ };
89
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { DataClient } from './client';
2
+ import type { PageInput, StoredPage } from './types';
3
+ /**
4
+ * A known-good document that exercises the reactive blocks end to end, plus a
5
+ * one-call seeder for it. A `months` slider feeds a live code block that emits
6
+ * four compound-growth curves, which a kit chart plots. Used by the `seed` CLI
7
+ * command and the in-app "Insert sample document" action so testing and
8
+ * dogfooding never need a document rebuilt by hand.
9
+ *
10
+ * Authored as a **block-doc** (`editor: 'blocks'` + a `blockdoc.blocks` JSON
11
+ * projection), the same native shape the gallery templates use — NOT the legacy
12
+ * EditorJS form. (The old EditorJS version migrated its `chart` block into a
13
+ * "not supported" warning callout, since the migration has no chart target; the
14
+ * native `kitchart` block renders the curves directly.)
15
+ */
16
+ /** Name of the seeded page. Unique (page names are), so re-seeding is idempotent. */
17
+ export declare const SAMPLE_DOCUMENT_NAME = "Compound Growth (sample)";
18
+ /** Build the sample document as a {@link PageInput} (no id → a fresh page). */
19
+ export declare function buildSampleDocument(): PageInput;
20
+ /**
21
+ * Upsert the sample document through a data client and return the stored page.
22
+ * Idempotent: reuses the existing sample page's id (names are unique) so
23
+ * re-seeding refreshes it in place instead of 409-ing on the name conflict.
24
+ */
25
+ export declare function seedSampleDocument(client: DataClient): Promise<StoredPage>;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * A known-good document that exercises the reactive blocks end to end, plus a
3
+ * one-call seeder for it. A `months` slider feeds a live code block that emits
4
+ * four compound-growth curves, which a kit chart plots. Used by the `seed` CLI
5
+ * command and the in-app "Insert sample document" action so testing and
6
+ * dogfooding never need a document rebuilt by hand.
7
+ *
8
+ * Authored as a **block-doc** (`editor: 'blocks'` + a `blockdoc.blocks` JSON
9
+ * projection), the same native shape the gallery templates use — NOT the legacy
10
+ * EditorJS form. (The old EditorJS version migrated its `chart` block into a
11
+ * "not supported" warning callout, since the migration has no chart target; the
12
+ * native `kitchart` block renders the curves directly.)
13
+ */
14
+ /** Name of the seeded page. Unique (page names are), so re-seeding is idempotent. */
15
+ export const SAMPLE_DOCUMENT_NAME = 'Compound Growth (sample)';
16
+ const INITIAL_MONTHS = 120;
17
+ // `months` is published by the slider; this live block reads it and returns an
18
+ // object of named arrays — the multi-series shape the kit chart plots (one line
19
+ // per annual rate). Returning bare arrays here would collapse to a single line.
20
+ const GROWTH_SOURCE = `return {
21
+ '3%': Array.from({length: months}, (_, i) => Math.pow(1.03, i / 12)),
22
+ '5%': Array.from({length: months}, (_, i) => Math.pow(1.05, i / 12)),
23
+ '7%': Array.from({length: months}, (_, i) => Math.pow(1.07, i / 12)),
24
+ '10%': Array.from({length: months}, (_, i) => Math.pow(1.10, i / 12)),
25
+ };`;
26
+ /** The reactive sample as a block-doc projection (ids double as stable block ids). */
27
+ const SAMPLE_BLOCKS = [
28
+ {
29
+ id: 'sample-intro',
30
+ type: 'paragraph',
31
+ text: [
32
+ { t: 'Sample reactive document. Drag ' },
33
+ { t: 'months', a: { b: true } },
34
+ { t: ' to watch four compound-growth curves (3 / 5 / 7 / 10% annual) recompute live.' },
35
+ ],
36
+ },
37
+ { id: 'sample-months', type: 'slider', props: { name: 'months', label: 'Months', value: INITIAL_MONTHS, min: 1, max: 360 } },
38
+ {
39
+ id: 'sample-growth',
40
+ type: 'code',
41
+ text: [{ t: GROWTH_SOURCE }],
42
+ props: { live: true, name: 'growth', language: 'js', collapsed: true },
43
+ },
44
+ { id: 'sample-chart', type: 'kitchart', props: { kind: 'line', title: 'Growth of £1 by annual rate', source: 'growth' } },
45
+ ];
46
+ /** Build the sample document as a {@link PageInput} (no id → a fresh page). */
47
+ export function buildSampleDocument() {
48
+ const data = {
49
+ editorjs: { blocks: [] },
50
+ values: [],
51
+ names: [],
52
+ editor: 'blocks',
53
+ blockdoc: { blocks: SAMPLE_BLOCKS },
54
+ };
55
+ return { name: SAMPLE_DOCUMENT_NAME, data };
56
+ }
57
+ /**
58
+ * Upsert the sample document through a data client and return the stored page.
59
+ * Idempotent: reuses the existing sample page's id (names are unique) so
60
+ * re-seeding refreshes it in place instead of 409-ing on the name conflict.
61
+ */
62
+ export async function seedSampleDocument(client) {
63
+ const existing = (await client.listPages()).find((p) => p.name === SAMPLE_DOCUMENT_NAME);
64
+ const input = buildSampleDocument();
65
+ return client.savePage(existing ? { ...input, id: existing.id } : input);
66
+ }
67
+ //# sourceMappingURL=sampleDocument.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sampleDocument.js","sourceRoot":"","sources":["../src/sampleDocument.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AAEH,qFAAqF;AACrF,MAAM,CAAC,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAE/D,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,+EAA+E;AAC/E,gFAAgF;AAChF,gFAAgF;AAChF,MAAM,aAAa,GAAG;;;;;GAKnB,CAAC;AAEJ,sFAAsF;AACtF,MAAM,aAAa,GAAG;IACpB;QACE,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE;YACJ,EAAC,CAAC,EAAE,iCAAiC,EAAC;YACtC,EAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAC,CAAC,EAAE,IAAI,EAAC,EAAC;YAC3B,EAAC,CAAC,EAAE,gFAAgF,EAAC;SACtF;KACF;IACD,EAAC,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAC,EAAC;IACxH;QACE,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,CAAC,EAAC,CAAC,EAAE,aAAa,EAAC,CAAC;QAC1B,KAAK,EAAE,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAC;KACrE;IACD,EAAC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,6BAA6B,EAAE,MAAM,EAAE,QAAQ,EAAC,EAAC;CACtH,CAAC;AAEF,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB;IACjC,MAAM,IAAI,GAAiB;QACzB,QAAQ,EAAE,EAAC,MAAM,EAAE,EAAE,EAAC;QACtB,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,EAAC,MAAM,EAAE,aAAa,EAAC;KAClC,CAAC;IACF,OAAO,EAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAkB;IACzD,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAC;IACzF,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAC,GAAG,KAAK,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC"}