@book.dev/sdk 3.8.0 → 3.10.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 (53) hide show
  1. package/dist/ai.d.ts +12 -2
  2. package/dist/ai.js.map +1 -1
  3. package/dist/blockCatalogue.d.ts +560 -0
  4. package/dist/blockCatalogue.js +336 -0
  5. package/dist/blockCatalogue.js.map +1 -0
  6. package/dist/bookFolder.d.ts +9 -1
  7. package/dist/bookFolder.js +64 -2
  8. package/dist/bookFolder.js.map +1 -1
  9. package/dist/client.d.ts +22 -2
  10. package/dist/client.js +6 -2
  11. package/dist/client.js.map +1 -1
  12. package/dist/content.d.ts +40 -1
  13. package/dist/content.js +29 -7
  14. package/dist/content.js.map +1 -1
  15. package/dist/forwarding/forwardingClient.d.ts +68 -2
  16. package/dist/forwarding/forwardingClient.js +126 -12
  17. package/dist/forwarding/forwardingClient.js.map +1 -1
  18. package/dist/forwarding/index.d.ts +2 -1
  19. package/dist/forwarding/index.js +2 -1
  20. package/dist/forwarding/index.js.map +1 -1
  21. package/dist/forwarding/namespacedKeyStore.d.ts +52 -0
  22. package/dist/forwarding/namespacedKeyStore.js +99 -0
  23. package/dist/forwarding/namespacedKeyStore.js.map +1 -0
  24. package/dist/index.d.ts +10 -5
  25. package/dist/index.js +10 -5
  26. package/dist/index.js.map +1 -1
  27. package/dist/ledger.d.ts +29 -0
  28. package/dist/ledger.js +43 -0
  29. package/dist/ledger.js.map +1 -1
  30. package/dist/ledgerExportSection.d.ts +160 -0
  31. package/dist/ledgerExportSection.js +594 -0
  32. package/dist/ledgerExportSection.js.map +1 -0
  33. package/dist/orderKeys.d.ts +36 -0
  34. package/dist/orderKeys.js +88 -0
  35. package/dist/orderKeys.js.map +1 -0
  36. package/dist/plugins.d.ts +79 -8
  37. package/dist/plugins.js +98 -16
  38. package/dist/plugins.js.map +1 -1
  39. package/dist/provenance.d.ts +13 -0
  40. package/dist/registryClient.d.ts +227 -0
  41. package/dist/registryClient.js +397 -0
  42. package/dist/registryClient.js.map +1 -0
  43. package/dist/routes.d.ts +9 -0
  44. package/dist/routes.js +9 -0
  45. package/dist/routes.js.map +1 -1
  46. package/dist/suggestions.d.ts +12 -2
  47. package/dist/tableSnapshot.d.ts +233 -0
  48. package/dist/tableSnapshot.js +680 -0
  49. package/dist/tableSnapshot.js.map +1 -0
  50. package/dist/templates.d.ts +8 -0
  51. package/dist/templates.js +7 -2
  52. package/dist/templates.js.map +1 -1
  53. package/package.json +1 -1
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Fractional order keys — pure, dependency-free (TBL-1).
3
+ *
4
+ * A key is a non-empty string over the base-62 alphabet `0-9A-Za-z` whose
5
+ * plain lexicographic order IS its numeric order: read it as a fraction in
6
+ * (0, 1) written in base 62 (`'V'` ≈ 0.5, `'0V'` ≈ 0.008…). The ASCII order
7
+ * of the alphabet matches its digit order, so `a < b` on the raw strings is
8
+ * the whole comparator — no parsing, ever.
9
+ *
10
+ * Invariant: a key never ends with the zero digit `'0'`. That guarantees any
11
+ * two distinct keys (and either open end) always have a midpoint, so a move
12
+ * only ever writes ONE small string — the mover's new key — and never has to
13
+ * renumber neighbours. Keys grow ~1 character per ~5 inserts into the same
14
+ * gap (worst case); callers that see a key longer than
15
+ * {@link ORDER_KEY_REBALANCE_LENGTH} should rewrite the whole axis with
16
+ * {@link keysBetween} (see `model.ts` table ops for the pattern).
17
+ */
18
+ /** Keys longer than this ask the owning axis for a rebalance (rare). */
19
+ export declare const ORDER_KEY_REBALANCE_LENGTH = 48;
20
+ /** True for a well-formed order key (base-62, non-empty, no trailing zero). */
21
+ export declare function isOrderKey(value: unknown): value is string;
22
+ /** Lexicographic comparator (identical to `<` on the raw strings). */
23
+ export declare function compareOrderKeys(a: string, b: string): number;
24
+ /**
25
+ * A key strictly between `a` and `b` (`null` = the open end of the axis).
26
+ * Throws on malformed keys or `a >= b` — callers own their bounds (the table
27
+ * ops fall back to a full-axis rebalance instead of passing bad bounds).
28
+ */
29
+ export declare function keyBetween(a: string | null, b: string | null): string;
30
+ /**
31
+ * `n` fresh keys strictly between `a` and `b`, in ascending order — balanced
32
+ * binary subdivision, so lengths stay ~log₆₂(n). Deterministic: the same
33
+ * bounds and count always produce the same keys (two peers migrating the same
34
+ * legacy table concurrently write identical values and converge trivially).
35
+ */
36
+ export declare function keysBetween(a: string | null, b: string | null, n: number): string[];
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Fractional order keys — pure, dependency-free (TBL-1).
3
+ *
4
+ * A key is a non-empty string over the base-62 alphabet `0-9A-Za-z` whose
5
+ * plain lexicographic order IS its numeric order: read it as a fraction in
6
+ * (0, 1) written in base 62 (`'V'` ≈ 0.5, `'0V'` ≈ 0.008…). The ASCII order
7
+ * of the alphabet matches its digit order, so `a < b` on the raw strings is
8
+ * the whole comparator — no parsing, ever.
9
+ *
10
+ * Invariant: a key never ends with the zero digit `'0'`. That guarantees any
11
+ * two distinct keys (and either open end) always have a midpoint, so a move
12
+ * only ever writes ONE small string — the mover's new key — and never has to
13
+ * renumber neighbours. Keys grow ~1 character per ~5 inserts into the same
14
+ * gap (worst case); callers that see a key longer than
15
+ * {@link ORDER_KEY_REBALANCE_LENGTH} should rewrite the whole axis with
16
+ * {@link keysBetween} (see `model.ts` table ops for the pattern).
17
+ */
18
+ const DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
19
+ const ZERO = DIGITS[0];
20
+ const BASE = DIGITS.length;
21
+ /** Keys longer than this ask the owning axis for a rebalance (rare). */
22
+ export const ORDER_KEY_REBALANCE_LENGTH = 48;
23
+ /** True for a well-formed order key (base-62, non-empty, no trailing zero). */
24
+ export function isOrderKey(value) {
25
+ return (typeof value === 'string' &&
26
+ value.length > 0 &&
27
+ !value.endsWith(ZERO) &&
28
+ [...value].every((ch) => DIGITS.includes(ch)));
29
+ }
30
+ /** Lexicographic comparator (identical to `<` on the raw strings). */
31
+ export function compareOrderKeys(a, b) {
32
+ return a < b ? -1 : a > b ? 1 : 0;
33
+ }
34
+ /**
35
+ * The midpoint of two fraction strings, `a < result < b`.
36
+ * `a === ''` means the lower bound 0; `b === null` means the upper bound 1.
37
+ * Neither input may have a trailing zero digit; the result never does.
38
+ */
39
+ function midpoint(a, b) {
40
+ if (b !== null) {
41
+ // Shared prefix passes through untouched; recurse on the differing tail.
42
+ let n = 0;
43
+ while ((a[n] ?? ZERO) === b[n])
44
+ n += 1;
45
+ if (n > 0)
46
+ return b.slice(0, n) + midpoint(a.slice(n), b.slice(n));
47
+ }
48
+ const digitA = a ? DIGITS.indexOf(a[0]) : 0;
49
+ const digitB = b !== null && b.length > 0 ? DIGITS.indexOf(b[0]) : BASE;
50
+ if (digitB - digitA > 1) {
51
+ return DIGITS[Math.round((digitA + digitB) / 2)];
52
+ }
53
+ // Consecutive leading digits: either borrow b's head (when it has a tail to
54
+ // stay below), or extend a's head with a midpoint above a's tail.
55
+ if (b !== null && b.length > 1)
56
+ return b[0];
57
+ return DIGITS[digitA] + midpoint(a.slice(1), null);
58
+ }
59
+ /**
60
+ * A key strictly between `a` and `b` (`null` = the open end of the axis).
61
+ * Throws on malformed keys or `a >= b` — callers own their bounds (the table
62
+ * ops fall back to a full-axis rebalance instead of passing bad bounds).
63
+ */
64
+ export function keyBetween(a, b) {
65
+ if (a !== null && !isOrderKey(a))
66
+ throw new RangeError(`invalid order key: ${JSON.stringify(a)}`);
67
+ if (b !== null && !isOrderKey(b))
68
+ throw new RangeError(`invalid order key: ${JSON.stringify(b)}`);
69
+ if (a !== null && b !== null && a >= b)
70
+ throw new RangeError(`order keys out of order: ${a} >= ${b}`);
71
+ return midpoint(a ?? '', b);
72
+ }
73
+ /**
74
+ * `n` fresh keys strictly between `a` and `b`, in ascending order — balanced
75
+ * binary subdivision, so lengths stay ~log₆₂(n). Deterministic: the same
76
+ * bounds and count always produce the same keys (two peers migrating the same
77
+ * legacy table concurrently write identical values and converge trivially).
78
+ */
79
+ export function keysBetween(a, b, n) {
80
+ if (n <= 0)
81
+ return [];
82
+ const mid = keyBetween(a, b);
83
+ if (n === 1)
84
+ return [mid];
85
+ const left = (n - 1) >> 1;
86
+ return [...keysBetween(a, mid, left), mid, ...keysBetween(mid, b, n - 1 - left)];
87
+ }
88
+ //# sourceMappingURL=orderKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orderKeys.js","sourceRoot":"","sources":["../src/orderKeys.ts"],"names":[],"mappings":"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"}
package/dist/plugins.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  * The plugin contract: what a plugin package IS (a manifest + TypeScript
3
3
  * source files), and the signing scheme that lets a registry vouch for one.
4
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.
5
+ * Extensions run with the same access as your documents’ live code. A
6
+ * “Verified” badge means a registry you trust signed this exact content —
7
+ * provenance, not a sandbox. Unsigned plugins install fine and are labelled
8
+ * unverified.
9
9
  *
10
10
  * Signing: Ed25519 over a canonical SHA-256 digest of the manifest + every
11
11
  * file (sorted paths, length-prefixed — byte-stable across platforms). The
@@ -66,6 +66,24 @@ export interface PluginManifest {
66
66
  apiVersion?: number;
67
67
  /** Agent tools this plugin contributes (read server-side from the manifest). */
68
68
  agentTools?: PluginAgentTool[];
69
+ /**
70
+ * The block types this plugin registers at activation (WITHOUT the
71
+ * `<pluginId>/` prefix the host adds). Declared in the manifest so servers —
72
+ * which never run plugin code — can list a plugin's blocks (the agent/MCP
73
+ * `list_block_types` tool) straight from the stored manifest JSON. Optional:
74
+ * a plugin that declares none still works, its block types are simply not
75
+ * enumerable server-side. For bundled first-party plugins the declaration is
76
+ * verified against the source's `blocks.register` calls at bundle time
77
+ * (packages/ui/scripts/bundlePlugins.ts), so it cannot drift.
78
+ */
79
+ blocks?: PluginBlockDeclaration[];
80
+ }
81
+ /** One manifest-declared plugin block (see {@link PluginManifest.blocks}). */
82
+ export interface PluginBlockDeclaration {
83
+ /** The unprefixed block type, e.g. `journal-entry`. */
84
+ type: string;
85
+ /** One-line description surfaced by `list_block_types`. */
86
+ description?: string;
69
87
  }
70
88
  /**
71
89
  * The host-side activation gate for {@link PluginManifest.apiVersion}:
@@ -97,6 +115,21 @@ export interface StoredPlugin extends PluginPackage {
97
115
  /** Set by the client after verification — never trusted from the wire. */
98
116
  verified?: boolean;
99
117
  }
118
+ /**
119
+ * Canonical JSON for signing: objects emit ALL keys, sorted, at EVERY depth;
120
+ * arrays are positional; primitives follow JSON.stringify semantics.
121
+ * `undefined`, functions, and symbols are rejected outright (never silently
122
+ * dropped) — anything the signer skips is something an attacker can vary for
123
+ * free.
124
+ *
125
+ * Deliberately NOT `JSON.stringify(value, sortedKeysArray)`: a replacer ARRAY
126
+ * allowlists those keys at every depth, so nested keys absent from the top
127
+ * level (e.g. `agentTools[0].action`) silently vanish from the signed bytes.
128
+ *
129
+ * Mirrored byte-for-byte by the store's server-side port
130
+ * (open-book-pub `packages/store/lib/canonical.ts`) — change both together.
131
+ */
132
+ export declare function canonicalJson(value: unknown): string;
100
133
  /** SHA-256 of the canonical bytes (hex) — the thing a registry signs. */
101
134
  export declare function canonicalDigest(manifest: PluginManifest, files: Record<string, string>): Promise<string>;
102
135
  /** Generate a registry keypair (raw public / pkcs8 private, base64). */
@@ -109,6 +142,14 @@ export declare function signPlugin(pkg: {
109
142
  manifest: PluginManifest;
110
143
  files: Record<string, string>;
111
144
  }, privateKeyBase64: string, registry: string, publicKeyBase64: string): Promise<PluginSignature>;
145
+ /**
146
+ * Verify an Ed25519 signature (base64, raw 64 bytes) over a UTF-8 message
147
+ * with a base64 RAW 32-byte public key. Returns false — never throws — on
148
+ * malformed inputs. The registry protocol signs the UTF-8 bytes of the
149
+ * lowercase hex canonical digest with exactly this scheme, for the publisher
150
+ * signature, the notary countersignature, and revocation entries alike.
151
+ */
152
+ export declare function verifyEd25519Message(publicKeyBase64: string, message: string, signatureBase64: string): Promise<boolean>;
112
153
  /**
113
154
  * Verify a package against a set of trusted registry keys. Returns the
114
155
  * matching trusted registry name, or null when unsigned, signed by an
@@ -121,10 +162,40 @@ export declare function verifyPlugin(pkg: PluginPackage, trustedKeys: Array<{
121
162
  registry: string;
122
163
  } | null>;
123
164
  /**
124
- * The pinned first-party registry key. Every OpenBook build trusts this;
125
- * additional registries are user-added keys on top (Settings → Extensions).
126
- * NOTE: a placeholder development key until the real registry launches —
127
- * regenerate and replace before publishing plugins for real.
165
+ * The pinned first-party registry keys. Every OpenBook build trusts ALL of
166
+ * these; additional registries are user-added keys on top (Settings →
167
+ * Extensions).
168
+ *
169
+ * THIS LIST IS THE ONE PLACE THE PRODUCTION KEY(S) LIVE. The key ceremony
170
+ * (docs/plugin-signing.md) is: run `node scripts/gen-registry-key.mjs`, commit
171
+ * the printed PUBLIC key here, and store the private half as the
172
+ * `OPENBOOK_REGISTRY_PRIVATE_KEY` GitHub Actions secret — the release build
173
+ * signs the bundled first-party plugins with it (packages/ui/scripts/
174
+ * bundlePlugins.ts).
175
+ *
176
+ * A LIST so rotation can overlap (add-then-remove): append the NEW key as a
177
+ * second entry and ship — clients of that build verify signatures from either
178
+ * key. Once the overlap build is broadly installed, cut signing over to the
179
+ * new key (swap the CI secret), and a later release removes the old entry.
180
+ * The signing key SHOULD be entry [0]; extra entries exist only during
181
+ * rotation windows. Full runbook: docs/plugin-signing.md.
182
+ *
183
+ * NOTE: currently a single production key, minted 2026-08-09. Its private
184
+ * half is held only in the GitHub Actions `publish` environment secret
185
+ * `OPENBOOK_REGISTRY_PRIVATE_KEY`. No entry may EVER match
186
+ * scripts/test-registry-key.json (its private half is public); CI guards
187
+ * enforce that for every entry (.github/workflows/release.yml).
188
+ */
189
+ export declare const OPENBOOK_REGISTRY_KEYS: Array<{
190
+ name: string;
191
+ publicKey: string;
192
+ }>;
193
+ /**
194
+ * The primary pinned first-party key — entry [0] of
195
+ * {@link OPENBOOK_REGISTRY_KEYS}.
196
+ * @deprecated trust decisions must consume the whole list
197
+ * ({@link OPENBOOK_REGISTRY_KEYS}); this alias exists for display and
198
+ * back-compat only.
128
199
  */
129
200
  export declare const OPENBOOK_REGISTRY: {
130
201
  name: string;
package/dist/plugins.js CHANGED
@@ -2,10 +2,10 @@
2
2
  * The plugin contract: what a plugin package IS (a manifest + TypeScript
3
3
  * source files), and the signing scheme that lets a registry vouch for one.
4
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.
5
+ * Extensions run with the same access as your documents’ live code. A
6
+ * “Verified” badge means a registry you trust signed this exact content —
7
+ * provenance, not a sandbox. Unsigned plugins install fine and are labelled
8
+ * unverified.
9
9
  *
10
10
  * Signing: Ed25519 over a canonical SHA-256 digest of the manifest + every
11
11
  * file (sorted paths, length-prefixed — byte-stable across platforms). The
@@ -36,9 +36,43 @@ export function pluginApiVersionError(manifest) {
36
36
  }
37
37
  const te = new TextEncoder();
38
38
  /**
39
- * Deterministic bytes for signing: the manifest (sorted-key JSON), then each
40
- * file in sorted path order, every part length-prefixed so boundaries can't
41
- * be confused (`a + bc` ≠ `ab + c`).
39
+ * Canonical JSON for signing: objects emit ALL keys, sorted, at EVERY depth;
40
+ * arrays are positional; primitives follow JSON.stringify semantics.
41
+ * `undefined`, functions, and symbols are rejected outright (never silently
42
+ * dropped) — anything the signer skips is something an attacker can vary for
43
+ * free.
44
+ *
45
+ * Deliberately NOT `JSON.stringify(value, sortedKeysArray)`: a replacer ARRAY
46
+ * allowlists those keys at every depth, so nested keys absent from the top
47
+ * level (e.g. `agentTools[0].action`) silently vanish from the signed bytes.
48
+ *
49
+ * Mirrored byte-for-byte by the store's server-side port
50
+ * (open-book-pub `packages/store/lib/canonical.ts`) — change both together.
51
+ */
52
+ export function canonicalJson(value) {
53
+ if (value === undefined || typeof value === 'function' || typeof value === 'symbol') {
54
+ throw new TypeError(`canonical JSON cannot contain ${typeof value}`);
55
+ }
56
+ if (value === null || typeof value !== 'object')
57
+ return JSON.stringify(value);
58
+ if (Array.isArray(value))
59
+ return `[${value.map((v) => canonicalJson(v)).join(',')}]`;
60
+ const obj = value;
61
+ const members = Object.keys(obj)
62
+ .sort()
63
+ .map((k) => {
64
+ if (obj[k] === undefined || typeof obj[k] === 'function' || typeof obj[k] === 'symbol') {
65
+ throw new TypeError(`canonical JSON cannot contain ${typeof obj[k]} (at key "${k}")`);
66
+ }
67
+ return `${JSON.stringify(k)}:${canonicalJson(obj[k])}`;
68
+ });
69
+ return `{${members.join(',')}}`;
70
+ }
71
+ /**
72
+ * Deterministic bytes for signing: the manifest (canonical JSON — keys sorted
73
+ * recursively, see {@link canonicalJson}), then each file in sorted path
74
+ * order, every part length-prefixed so boundaries can't be confused
75
+ * (`a + bc` ≠ `ab + c`).
42
76
  */
43
77
  function canonicalBytes(manifest, files) {
44
78
  const parts = [];
@@ -48,7 +82,7 @@ function canonicalBytes(manifest, files) {
48
82
  new DataView(len.buffer).setUint32(0, bytes.length);
49
83
  parts.push(len, bytes);
50
84
  };
51
- push(JSON.stringify(manifest, Object.keys(manifest).sort()));
85
+ push(canonicalJson(manifest));
52
86
  for (const path of Object.keys(files).sort()) {
53
87
  push(path);
54
88
  push(files[path]);
@@ -83,6 +117,25 @@ export async function signPlugin(pkg, privateKeyBase64, registry, publicKeyBase6
83
117
  const sig = new Uint8Array(await crypto.subtle.sign('Ed25519', key, te.encode(digest)));
84
118
  return { registry, publicKey: publicKeyBase64, signature: toBase64(sig), algorithm: 'ed25519' };
85
119
  }
120
+ /**
121
+ * Verify an Ed25519 signature (base64, raw 64 bytes) over a UTF-8 message
122
+ * with a base64 RAW 32-byte public key. Returns false — never throws — on
123
+ * malformed inputs. The registry protocol signs the UTF-8 bytes of the
124
+ * lowercase hex canonical digest with exactly this scheme, for the publisher
125
+ * signature, the notary countersignature, and revocation entries alike.
126
+ */
127
+ export async function verifyEd25519Message(publicKeyBase64, message, signatureBase64) {
128
+ try {
129
+ const raw = fromBase64(publicKeyBase64);
130
+ if (raw.length !== 32)
131
+ return false;
132
+ const key = await crypto.subtle.importKey('raw', raw, 'Ed25519', false, ['verify']);
133
+ return await crypto.subtle.verify('Ed25519', key, fromBase64(signatureBase64), te.encode(message));
134
+ }
135
+ catch {
136
+ return false;
137
+ }
138
+ }
86
139
  /**
87
140
  * Verify a package against a set of trusted registry keys. Returns the
88
141
  * matching trusted registry name, or null when unsigned, signed by an
@@ -106,15 +159,44 @@ export async function verifyPlugin(pkg, trustedKeys) {
106
159
  }
107
160
  }
108
161
  /**
109
- * The pinned first-party registry key. Every OpenBook build trusts this;
110
- * additional registries are user-added keys on top (Settings → Extensions).
111
- * NOTE: a placeholder development key until the real registry launches —
112
- * regenerate and replace before publishing plugins for real.
162
+ * The pinned first-party registry keys. Every OpenBook build trusts ALL of
163
+ * these; additional registries are user-added keys on top (Settings →
164
+ * Extensions).
165
+ *
166
+ * THIS LIST IS THE ONE PLACE THE PRODUCTION KEY(S) LIVE. The key ceremony
167
+ * (docs/plugin-signing.md) is: run `node scripts/gen-registry-key.mjs`, commit
168
+ * the printed PUBLIC key here, and store the private half as the
169
+ * `OPENBOOK_REGISTRY_PRIVATE_KEY` GitHub Actions secret — the release build
170
+ * signs the bundled first-party plugins with it (packages/ui/scripts/
171
+ * bundlePlugins.ts).
172
+ *
173
+ * A LIST so rotation can overlap (add-then-remove): append the NEW key as a
174
+ * second entry and ship — clients of that build verify signatures from either
175
+ * key. Once the overlap build is broadly installed, cut signing over to the
176
+ * new key (swap the CI secret), and a later release removes the old entry.
177
+ * The signing key SHOULD be entry [0]; extra entries exist only during
178
+ * rotation windows. Full runbook: docs/plugin-signing.md.
179
+ *
180
+ * NOTE: currently a single production key, minted 2026-08-09. Its private
181
+ * half is held only in the GitHub Actions `publish` environment secret
182
+ * `OPENBOOK_REGISTRY_PRIVATE_KEY`. No entry may EVER match
183
+ * scripts/test-registry-key.json (its private half is public); CI guards
184
+ * enforce that for every entry (.github/workflows/release.yml).
185
+ */
186
+ export const OPENBOOK_REGISTRY_KEYS = [
187
+ {
188
+ name: 'OpenBook Registry',
189
+ publicKey: '62Gry7q0cRFZFgZNFXwuB4XyVHQhGxTXuR5oqZG4eVU=',
190
+ },
191
+ ];
192
+ /**
193
+ * The primary pinned first-party key — entry [0] of
194
+ * {@link OPENBOOK_REGISTRY_KEYS}.
195
+ * @deprecated trust decisions must consume the whole list
196
+ * ({@link OPENBOOK_REGISTRY_KEYS}); this alias exists for display and
197
+ * back-compat only.
113
198
  */
114
- export const OPENBOOK_REGISTRY = {
115
- name: 'OpenBook Registry',
116
- publicKey: 'nI4eBQzqrIyVPEmJSEzGtqC9B0+kfWTXKyN5t8Yki/E=',
117
- };
199
+ export const OPENBOOK_REGISTRY = OPENBOOK_REGISTRY_KEYS[0];
118
200
  const PLUGIN_ID_RE = /^[a-z0-9][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*)+$/;
119
201
  /** Validate a manifest's shape; returns a human-readable problem or null. */
120
202
  export function validateManifest(m) {
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
@@ -173,6 +173,19 @@ export interface InstanceInfo {
173
173
  * identity and falls back to a reachability-only probe. */
174
174
  instanceId?: string | null;
175
175
  ownerSubject: string | null;
176
+ /**
177
+ * Whether this instance has an owner at all — WITHOUT saying who (PUB-1 / Sasha
178
+ * M-1). {@link ownerSubject} cannot answer this: GATE-7 nulls it for an anonymous
179
+ * caller on a claimed instance, so `ownerSubject === null` means either "unclaimed"
180
+ * or "claimed, but you may not know the owner". A client that needs the CLAIM
181
+ * STATE — e.g. to warn that an unclaimed library ignores `defaultVisibility`
182
+ * entirely (authorize rule 0 short-circuits on the guest gate alone) — must read
183
+ * this instead. Deliberately non-sensitive: a boolean "someone owns this" leaks no
184
+ * identity and no recon surface beyond what the guest gate's own behaviour already
185
+ * reveals. Optional: absent on a pre-PUB-1 server / a test fixture — a client then
186
+ * knows nothing and should stay silent rather than guess a claim state.
187
+ */
188
+ claimed?: boolean;
176
189
  trustedIssuers: string[];
177
190
  /** This server's audience identifier, so a client can request an `aud`-scoped
178
191
  * identity token (OB-177). `null` for the single-server (unscoped) model. */