@book.dev/sdk 1.60.0 → 1.65.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 (49) hide show
  1. package/dist/account.d.ts +11 -0
  2. package/dist/account.js +27 -0
  3. package/dist/account.js.map +1 -1
  4. package/dist/ai.d.ts +10 -0
  5. package/dist/ai.js +12 -0
  6. package/dist/ai.js.map +1 -1
  7. package/dist/authorize.d.ts +104 -0
  8. package/dist/authorize.js +151 -0
  9. package/dist/authorize.js.map +1 -0
  10. package/dist/authors.d.ts +26 -0
  11. package/dist/authors.js +81 -0
  12. package/dist/authors.js.map +1 -0
  13. package/dist/backup.d.ts +46 -0
  14. package/dist/backup.js +15 -0
  15. package/dist/backup.js.map +1 -1
  16. package/dist/client.d.ts +124 -3
  17. package/dist/client.js +113 -10
  18. package/dist/client.js.map +1 -1
  19. package/dist/connection.d.ts +23 -0
  20. package/dist/connection.js +56 -0
  21. package/dist/connection.js.map +1 -1
  22. package/dist/forwarding/index.d.ts +2 -1
  23. package/dist/forwarding/index.js +2 -1
  24. package/dist/forwarding/index.js.map +1 -1
  25. package/dist/forwarding/rosterAssertion.d.ts +49 -0
  26. package/dist/forwarding/rosterAssertion.js +89 -0
  27. package/dist/forwarding/rosterAssertion.js.map +1 -0
  28. package/dist/forwarding/tunnelClient.js +11 -1
  29. package/dist/forwarding/tunnelClient.js.map +1 -1
  30. package/dist/forwarding/tunnelProtocol.d.ts +11 -0
  31. package/dist/forwarding/tunnelProtocol.js +11 -0
  32. package/dist/forwarding/tunnelProtocol.js.map +1 -1
  33. package/dist/identity.d.ts +238 -0
  34. package/dist/identity.js +273 -0
  35. package/dist/identity.js.map +1 -0
  36. package/dist/index.d.ts +13 -9
  37. package/dist/index.js +9 -5
  38. package/dist/index.js.map +1 -1
  39. package/dist/provenance.d.ts +168 -0
  40. package/dist/provenance.js +31 -0
  41. package/dist/provenance.js.map +1 -0
  42. package/dist/routes.d.ts +53 -0
  43. package/dist/routes.js +50 -0
  44. package/dist/routes.js.map +1 -1
  45. package/dist/suggestions.d.ts +17 -2
  46. package/dist/types.d.ts +100 -0
  47. package/dist/types.js +9 -0
  48. package/dist/types.js.map +1 -1
  49. package/package.json +6 -1
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Verifiable user identity for multi-user OpenBook (OB-165).
3
+ *
4
+ * A user proves who they are with a compact **JWS** (JSON Web Signature) signed
5
+ * by a trusted **issuer** (account.book.pub, or any federated issuer) using
6
+ * **Ed25519 / `alg: EdDSA`** — the same primitive the forwarding site keys and
7
+ * plugin provenance already use, so this adds no dependency. The data server
8
+ * verifies the assertion against the issuer's published JWKS (which it caches,
9
+ * so verification works offline and on any federated instance), then attributes
10
+ * every change to the resulting {@link Principal}.
11
+ *
12
+ * Design: see `docs/multi-user-and-backups-2026-06.md`. This module is
13
+ * isomorphic (Web Crypto only) so it runs in the server, the desktop app, the
14
+ * web shell, and tests alike.
15
+ */
16
+ import { b64uDecode, b64uEncode, b64uDecodeString, b64uEncodeString, utf8 } from './forwarding/encoding';
17
+ const ED25519 = { name: 'Ed25519' };
18
+ /** A guest principal with an optional display name. */
19
+ export function guestPrincipal(name = '') {
20
+ const label = name.trim();
21
+ return {
22
+ kind: 'guest',
23
+ subject: label ? `guest:${label}` : 'guest:anonymous',
24
+ issuer: '',
25
+ name: label,
26
+ verifiedVia: 'guest',
27
+ };
28
+ }
29
+ /** The implicit local owner (in-process / loopback desktop). */
30
+ export function localPrincipal(name = 'Local') {
31
+ return { kind: 'user', subject: 'local:owner', issuer: 'local', name, verifiedVia: 'local' };
32
+ }
33
+ /** Stable short id for a principal — the value embedded in CRDT edit origins. */
34
+ export function principalId(p) {
35
+ return p.subject;
36
+ }
37
+ /**
38
+ * Mint a fresh issuer keypair (Ed25519). Used by the dev issuer and tests; the
39
+ * real issuer (account.book.pub) holds the equivalent and rotates `kid`s.
40
+ */
41
+ export async function mintIdentityKeypair(kid = 'dev-1') {
42
+ const kp = (await crypto.subtle.generateKey(ED25519, true, ['sign', 'verify']));
43
+ const raw = new Uint8Array(await crypto.subtle.exportKey('raw', kp.publicKey));
44
+ const priv = new Uint8Array(await crypto.subtle.exportKey('pkcs8', kp.privateKey));
45
+ return {
46
+ publicJwk: { kty: 'OKP', crv: 'Ed25519', x: b64uEncode(raw), kid, use: 'sig', alg: 'EdDSA' },
47
+ privateKey: b64uEncode(priv),
48
+ };
49
+ }
50
+ /**
51
+ * Sign an arbitrary JSON payload into a compact EdDSA JWS:
52
+ * `base64url(header).base64url(payload).base64url(sig)`. Shared by the identity
53
+ * assertion ({@link signIdentity}) and the revocation document
54
+ * ({@link signRevocations}) — both are the same JWS shape over a different payload.
55
+ */
56
+ async function signCompactJws(privateKeyPkcs8, payload, kid) {
57
+ const header = { alg: 'EdDSA', typ: 'JWT', ...(kid ? { kid } : {}) };
58
+ const signingInput = `${b64uEncodeString(JSON.stringify(header))}.${b64uEncodeString(JSON.stringify(payload))}`;
59
+ const key = await crypto.subtle.importKey('pkcs8', b64uDecode(privateKeyPkcs8), ED25519, false, ['sign']);
60
+ const sig = await crypto.subtle.sign(ED25519, key, utf8(signingInput));
61
+ return `${signingInput}.${b64uEncode(new Uint8Array(sig))}`;
62
+ }
63
+ /**
64
+ * Sign an identity assertion (issuer side / dev / tests). Produces a compact
65
+ * EdDSA JWS: `base64url(header).base64url(claims).base64url(sig)`.
66
+ */
67
+ export async function signIdentity(privateKeyPkcs8, claims, kid) {
68
+ return signCompactJws(privateKeyPkcs8, claims, kid);
69
+ }
70
+ /**
71
+ * Decode an assertion's header + claims **without** verifying the signature.
72
+ * For client-side display, and for the server's "claimed-but-unverified"
73
+ * provenance fallback. Never use this to make a trust decision.
74
+ */
75
+ export function decodeIdentity(jws) {
76
+ const parts = jws.split('.');
77
+ if (parts.length !== 3)
78
+ return null;
79
+ try {
80
+ const header = JSON.parse(b64uDecodeString(parts[0]));
81
+ const claims = JSON.parse(b64uDecodeString(parts[1]));
82
+ if (!claims || typeof claims.iss !== 'string' || typeof claims.sub !== 'string')
83
+ return null;
84
+ return { header, claims };
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ }
90
+ /**
91
+ * Verify a compact EdDSA JWS's *signature* against a JWKS. Pure + offline.
92
+ * Returns `'unknown-key'` when no key matches the header `kid`, `'bad-signature'`
93
+ * when candidate keys exist but none validated, and `'ok'` on success. Shared by
94
+ * the identity-token ({@link verifyIdentity}) and revocation-document
95
+ * ({@link verifyRevocations}) verifiers — both prove the same EdDSA signature.
96
+ */
97
+ async function verifyCompactSignature(jws, header, jwks) {
98
+ // Pick candidate keys: the kid-matched one, else every key (kid is a hint).
99
+ const candidates = header.kid ? jwks.keys.filter((k) => k.kid === header.kid) : jwks.keys;
100
+ if (candidates.length === 0)
101
+ return 'unknown-key';
102
+ const parts = jws.split('.');
103
+ const signingInput = utf8(`${parts[0]}.${parts[1]}`);
104
+ const sig = b64uDecode(parts[2]);
105
+ for (const jwk of candidates) {
106
+ try {
107
+ const key = await crypto.subtle.importKey('raw', b64uDecode(jwk.x), ED25519, false, ['verify']);
108
+ if (await crypto.subtle.verify(ED25519, key, sig, signingInput))
109
+ return 'ok';
110
+ }
111
+ catch {
112
+ // Malformed key — try the next candidate.
113
+ }
114
+ }
115
+ return 'bad-signature';
116
+ }
117
+ /**
118
+ * Verify an identity assertion against an issuer's JWKS. Pure + offline: the
119
+ * caller supplies the (cached) key set, so no network call happens here.
120
+ *
121
+ * Returns `{ok:true, claims}` only on a fresh, signature-valid, in-window,
122
+ * trusted-issuer, non-revoked assertion. On failure returns a reason (and the
123
+ * decoded claims when they parsed, so the server can record a claimed-but-
124
+ * unverified identity).
125
+ */
126
+ export async function verifyIdentity(jws, jwks, opts = {}) {
127
+ const decoded = decodeIdentity(jws);
128
+ if (!decoded)
129
+ return { ok: false, reason: 'malformed' };
130
+ const { header, claims } = decoded;
131
+ if (header.alg !== 'EdDSA')
132
+ return { ok: false, reason: 'unsupported-alg', claims };
133
+ if (opts.allowedIssuers && !opts.allowedIssuers.includes(claims.iss)) {
134
+ return { ok: false, reason: 'untrusted-issuer', claims };
135
+ }
136
+ const sigCheck = await verifyCompactSignature(jws, header, jwks);
137
+ if (sigCheck !== 'ok')
138
+ return { ok: false, reason: sigCheck, claims };
139
+ // Time window (after the signature is proven, so we can distinguish expired
140
+ // from forged). Tolerance covers clock skew and short offline spells.
141
+ const tol = opts.clockToleranceSec ?? 60;
142
+ const now = Math.floor((opts.nowMs ?? Date.now()) / 1000);
143
+ if (typeof claims.nbf === 'number' && now + tol < claims.nbf) {
144
+ return { ok: false, reason: 'not-yet-valid', claims };
145
+ }
146
+ if (typeof claims.exp === 'number' && now - tol > claims.exp) {
147
+ return { ok: false, reason: 'expired', claims };
148
+ }
149
+ // Audience binding (OB-177). A scoped token must name THIS server; an unscoped
150
+ // token is accepted only when the server doesn't demand scoping. Checked after
151
+ // the signature so a forged `aud` can't pass — `aud` is inside the signed payload.
152
+ if (typeof claims.aud === 'string' && claims.aud.length > 0) {
153
+ if (!opts.audience || claims.aud !== opts.audience) {
154
+ return { ok: false, reason: 'wrong-audience', claims };
155
+ }
156
+ }
157
+ else if (opts.requireAudience) {
158
+ return { ok: false, reason: 'wrong-audience', claims };
159
+ }
160
+ // Revocation (OB-106). Checked LAST — after the signature and the time/aud
161
+ // window — so only a genuine, in-window token can ever be marked revoked (a
162
+ // forged token has already failed). The set was signature-verified by the
163
+ // caller (see {@link verifyRevocations}). A token is revoked when its issuer
164
+ // published a revocation for this `sub` whose `since` is newer than the token's
165
+ // `iat`, so a fresh re-login (a newer `iat`) is unaffected.
166
+ const rev = opts.revocations;
167
+ if (rev && rev.iss === claims.iss && typeof claims.iat === 'number') {
168
+ const entry = rev.revocations.find((r) => r.sub === claims.sub);
169
+ if (entry && claims.iat < entry.since)
170
+ return { ok: false, reason: 'revoked', claims };
171
+ }
172
+ return { ok: true, claims, header };
173
+ }
174
+ /**
175
+ * Validate + normalise a decoded revocations payload into a {@link RevocationSet}.
176
+ * Returns `null` when the top-level shape is wrong (so a malformed document is
177
+ * ignored rather than trusted), and drops any entry missing a `sub` or a numeric
178
+ * `since`.
179
+ */
180
+ function normalizeRevocationSet(payload) {
181
+ if (!payload || typeof payload !== 'object')
182
+ return null;
183
+ const p = payload;
184
+ if (typeof p.iss !== 'string' || !Array.isArray(p.revocations))
185
+ return null;
186
+ const revocations = [];
187
+ for (const raw of p.revocations) {
188
+ if (!raw || typeof raw !== 'object')
189
+ continue;
190
+ const e = raw;
191
+ if (typeof e.sub !== 'string' || typeof e.since !== 'number')
192
+ continue;
193
+ revocations.push({ sub: e.sub, since: e.since, ...(typeof e.reason === 'string' ? { reason: e.reason } : {}) });
194
+ }
195
+ return {
196
+ iss: p.iss,
197
+ ...(typeof p.iat === 'number' ? { iat: p.iat } : {}),
198
+ ...(typeof p.ttl === 'number' ? { ttl: p.ttl } : {}),
199
+ revocations,
200
+ };
201
+ }
202
+ /**
203
+ * Verify an issuer's revocation document — a compact EdDSA JWS, the same format
204
+ * as an identity token — against the issuer's JWKS, returning the parsed
205
+ * {@link RevocationSet}. Pure + offline (the caller supplies the cached JWKS).
206
+ * Returns `null` on a malformed document, unsupported alg, or bad signature, so a
207
+ * forged or unsigned document can never revoke anything.
208
+ */
209
+ export async function verifyRevocations(jws, jwks) {
210
+ const parts = jws.split('.');
211
+ if (parts.length !== 3)
212
+ return null;
213
+ let header;
214
+ let payload;
215
+ try {
216
+ header = JSON.parse(b64uDecodeString(parts[0]));
217
+ payload = JSON.parse(b64uDecodeString(parts[1]));
218
+ }
219
+ catch {
220
+ return null;
221
+ }
222
+ if (header.alg !== 'EdDSA')
223
+ return null;
224
+ if ((await verifyCompactSignature(jws, header, jwks)) !== 'ok')
225
+ return null;
226
+ return normalizeRevocationSet(payload);
227
+ }
228
+ /**
229
+ * Sign a revocation document (issuer side / dev / tests) — the counterpart to
230
+ * {@link verifyRevocations}. Produces the same compact EdDSA JWS the account
231
+ * service publishes at its revocations endpoint.
232
+ */
233
+ export async function signRevocations(privateKeyPkcs8, set, kid) {
234
+ return signCompactJws(privateKeyPkcs8, set, kid);
235
+ }
236
+ /** The active-persona email (lowercased) carried by an assertion, if any. */
237
+ function personaEmail(claims) {
238
+ const email = claims.email?.trim().toLowerCase();
239
+ return email ? email : undefined;
240
+ }
241
+ /** Build a verified user principal from validated claims. */
242
+ export function principalFromClaims(claims, header) {
243
+ const email = personaEmail(claims);
244
+ return {
245
+ kind: 'user',
246
+ subject: `${claims.iss}#${claims.sub}`,
247
+ issuer: claims.iss,
248
+ name: claims.name ?? '',
249
+ ...(email ? { email } : {}),
250
+ verifiedVia: 'jws',
251
+ assertion: { kid: header?.kid, jti: claims.jti },
252
+ };
253
+ }
254
+ /**
255
+ * Build a claimed-but-unverified principal from an assertion that parsed but
256
+ * didn't verify fresh (e.g. expired while offline). Provenance still names the
257
+ * claimed subject, flagged `unverified`.
258
+ */
259
+ export function unverifiedPrincipalFromClaims(claims) {
260
+ const email = personaEmail(claims);
261
+ return {
262
+ kind: 'user',
263
+ subject: `${claims.iss}#${claims.sub}`,
264
+ issuer: claims.iss,
265
+ name: claims.name ?? '',
266
+ // Carried for attribution only — an unverified principal is never `jws`, so
267
+ // `emailIsAuthoritative` is false and this email never drives a grant (B1/N8).
268
+ ...(email ? { email } : {}),
269
+ verifiedVia: 'unverified',
270
+ assertion: { jti: claims.jti },
271
+ };
272
+ }
273
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,23 +1,27 @@
1
- export type { PageSnapshot, PageMeta, StoredPage, PageInput, ServerInfo, ServerControls } from './types';
2
- export { emptyPageSnapshot } from './types';
3
- export { API, type ApiError } from './routes';
4
- export type { DataClient, PageSubscription, FetchLike, LiveSourceLike, HttpDataClientOptions } from './client';
1
+ export type { PageSnapshot, PageMeta, StoredPage, PageInput, ServerInfo, ServerControls, PageVisibility, Visibility, MemberRole, MemberStatus, MemberSource, AclLevel, Member, PageAcl, } from './types';
2
+ export { emptyPageSnapshot, PAGE_VISIBILITIES } from './types';
3
+ export { API, type ApiError, type CompactResult } from './routes';
4
+ export type { DataClient, PageSubscription, FetchLike, LiveSourceLike, HttpDataClientOptions, IdentityCredential } from './client';
5
5
  export { HttpDataClient } from './client';
6
- export { ForwardingClient, TunnelClient, MemoryKeyStore, mintSiteKeypair, signWithSiteKey, type KeyStore, type SiteIdentity, type ForwardingClientOptions, type TunnelStatus, } from './forwarding';
6
+ export { ForwardingClient, TunnelClient, MemoryKeyStore, mintSiteKeypair, signWithSiteKey, verifyWithSiteKey, FORWARDED_HEADER, signRosterAssertion, verifyRosterAssertion, ROSTER_ASSERTION_VERSION, ROSTER_ASSERTION_SKEW_MS, type KeyStore, type SiteIdentity, type ForwardingClientOptions, type TunnelStatus, type RosterAssertionPayload, type SignRosterAssertionInput, type VerifyRosterAssertionInput, } from './forwarding';
7
7
  export type { DatabasePropertyType, NumberFormat, NumberDisplay, StatusGroup, RollupFunction, RollupConfig, RelationCardinality, DatabaseSelectOption, DatabaseProperty, DateRange, LocationValue, PropertyGroup, RowTemplate, DatabaseViewType, ChartAggregate, SummaryType, FilterOperator, FilterConjunction, DatabaseFilter, DatabaseFilterGroup, FilterNode, SortDirection, DatabaseSort, DatabaseView, DatabaseMetric, ColorRule, DatabaseSchema, StoredDatabase, DatabaseInput, DatabaseUpdate, DatabaseRow, RowInput, RowUpdate, RowGroup, ChartDatum, ChartSeries, ChartSegment, ChartGroup, ChartMatrix, DateSpan, GraphNode, GraphEdge, DependencyGraph, InverseUpdate, RowTreeNode, } from './database';
8
8
  export { TITLE_PROPERTY_ID, SELECT_COLORS, NO_VALUE_GROUP, STATUS_GROUPS, RELATIVE_DATE_OPS, projectExports, rowValue, matchesFilter, rowMatchesCondition, applyView, viewFilterRoot, isFilterGroup, shortId, defaultDatabaseSchema, defaultView, defaultStatusOptions, removeProperty, formatNumber, formatUniqueId, numberProgress, groupRows, groupRowsBy, groupRowsByParent, PARENT_GROUP_ID, NO_PARENT_GROUP, aggregateRows, aggregateMatrix, CHART_TOTAL_SERIES, summarizeColumn, dateStart, dateEnd, parseDay, rowDateSpan, rowLocation, asLocation, dependencyGraph, syncInverseUpdates, relationSides, buildRowTree, flattenRowTree, isImageUrl, firstImageUrl, coverImageUrl, } from './database';
9
9
  export { evaluateFormula, formulaReferences, FormulaError, type FormulaValue, type FormulaResolver, } from './formula';
10
10
  export { OWNER_PROPERTY_ID, VERIFICATION_PROPERTY_ID, BACKLINKS_PROPERTY_ID, THEME_PROPERTY_ID, COVER_PROPERTY_ID, FONTS_PROPERTY_ID, ICON_PROPERTY_ID, FULLWIDTH_PROPERTY_ID, SYSTEM_PAGE_PROPERTIES, isVerified, verificationExpired, isVerificationActive, makeVerification, extractMentionIds, propertiesReferencePage, type VerificationValue, } from './pageProperties';
11
- export { getServerUrlOverride, setServerUrlOverride, getServerTokenOverride, setServerTokenOverride, isMixedContentBlocked } from './connection';
11
+ export { getServerUrlOverride, setServerUrlOverride, getServerTokenOverride, setServerTokenOverride, getIdentityCredential, setIdentityToken, setGuestName, getForwardingAudience, setForwardingAudience, isMixedContentBlocked } from './connection';
12
12
  export { AccountClient, AccountError, DEFAULT_ACCOUNT_URL, getAccountUrlOverride, setAccountUrlOverride, resolveAccountUrl, type AccountSettings, } from './account';
13
+ export { guestPrincipal, localPrincipal, principalId, mintIdentityKeypair, signIdentity, decodeIdentity, verifyIdentity, verifyRevocations, signRevocations, principalFromClaims, unverifiedPrincipalFromClaims, type Principal, type PrincipalKind, type VerifiedVia, type IdentityHeader, type IdentityClaims, type Jwk, type Jwks, type RevocationEntry, type RevocationSet, type IdentityKeypair, type VerifyOptions, type VerifyResult, type VerifyFailure, } from './identity';
14
+ export { DEFAULT_INSTANCE_CONFIG, type GuestAccess, type TrustedIssuerConfig, type InstanceConfig, type InstanceInfo, type StoredEdit, type WorkspaceBinding, type WorkspaceRoster, type WorkspaceRosterEntry, } from './provenance';
15
+ export { authorize, isEmailAuthoritative, type Role, type EffectiveVisibility, type AclEntry, type AccessPage, type AccessCtx, type Decision, } from './authorize';
13
16
  export { snapshotText, paragraphBlocks, textSnapshot, appendTextToSnapshot, appendBlocksToSnapshot, type AppendBlock } from './content';
14
17
  export { snapshotBlocks, contentHash, computeBlockMtimes, stampSnapshotMtimes, latestBlockMtime, type BlockDigest, } from './mtime';
18
+ export { computeBlockAuthors, stampSnapshotAuthors, latestSnapshotAuthor } from './authors';
15
19
  export { pageToBookHtml, bookHtmlToPage, readBookHtmlMeta, slugify, type BookPageRecord, } from './bookfile';
16
20
  export { spaceToBookFiles, parseBookFolder, SPACE_BUNDLE_FILE, type BookFolderFile, type SpaceSnapshot, } from './bookFolder';
17
21
  export { canonicalDigest, generateRegistryKeys, signPlugin, verifyPlugin, validateManifest, OPENBOOK_REGISTRY, type PluginManifest, type PluginAgentTool, type PluginPackage, type PluginSignature, type StoredPlugin, } from './plugins';
18
22
  export { buildSampleDocument, seedSampleDocument, SAMPLE_DOCUMENT_NAME } from './sampleDocument';
19
- export type { CommentRun, SuggestionAuthorKind, SuggestionKind, SuggestionStatus, SuggestionTarget, StoredSuggestion, SuggestionInput, SuggestionUpdate, StoredComment, CommentInput, } from './suggestions';
23
+ export type { CommentRun, AuthoredIdentity, SuggestionAuthorKind, SuggestionKind, SuggestionStatus, SuggestionTarget, StoredSuggestion, SuggestionInput, SuggestionUpdate, StoredComment, CommentInput, } from './suggestions';
20
24
  export { PAGE_TEMPLATES, instantiateTemplate, type PageTemplate } from './templates';
21
- export { BACKUP_VERSION, remapBundle, type SpaceBackup, type ImportMode, type ImportRequest, type ImportResult, } from './backup';
25
+ export { BACKUP_VERSION, BACKUP_CADENCES, BACKUP_CADENCE_MS, DEFAULT_BACKUP_CONFIG, remapBundle, type SpaceBackup, type ImportMode, type ImportRequest, type ImportResult, type BackupCadence, type BackupConfig, type BackupCadenceStatus, type BackupStatus, } from './backup';
22
26
  export type { AgentChatEvent, AgentChatMessage, AgentChatOptions, AgentProposal, InterviewStep, AiProvider, AiConfig, AiProviderSettings, AiEffort, AiSkill, AiStatus, AiSearchResult, AiSearchResponse, AiTasksResponse, AiStreamEvent, } from './ai';
23
- export { providerSettings } from './ai';
27
+ export { providerSettings, isPaidProvider } from './ai';
package/dist/index.js CHANGED
@@ -1,19 +1,23 @@
1
- export { emptyPageSnapshot } from './types';
1
+ export { emptyPageSnapshot, PAGE_VISIBILITIES } from './types';
2
2
  export { API } from './routes';
3
3
  export { HttpDataClient } from './client';
4
- export { ForwardingClient, TunnelClient, MemoryKeyStore, mintSiteKeypair, signWithSiteKey, } from './forwarding';
4
+ export { ForwardingClient, TunnelClient, MemoryKeyStore, mintSiteKeypair, signWithSiteKey, verifyWithSiteKey, FORWARDED_HEADER, signRosterAssertion, verifyRosterAssertion, ROSTER_ASSERTION_VERSION, ROSTER_ASSERTION_SKEW_MS, } from './forwarding';
5
5
  export { TITLE_PROPERTY_ID, SELECT_COLORS, NO_VALUE_GROUP, STATUS_GROUPS, RELATIVE_DATE_OPS, projectExports, rowValue, matchesFilter, rowMatchesCondition, applyView, viewFilterRoot, isFilterGroup, shortId, defaultDatabaseSchema, defaultView, defaultStatusOptions, removeProperty, formatNumber, formatUniqueId, numberProgress, groupRows, groupRowsBy, groupRowsByParent, PARENT_GROUP_ID, NO_PARENT_GROUP, aggregateRows, aggregateMatrix, CHART_TOTAL_SERIES, summarizeColumn, dateStart, dateEnd, parseDay, rowDateSpan, rowLocation, asLocation, dependencyGraph, syncInverseUpdates, relationSides, buildRowTree, flattenRowTree, isImageUrl, firstImageUrl, coverImageUrl, } from './database';
6
6
  export { evaluateFormula, formulaReferences, FormulaError, } from './formula';
7
7
  export { OWNER_PROPERTY_ID, VERIFICATION_PROPERTY_ID, BACKLINKS_PROPERTY_ID, THEME_PROPERTY_ID, COVER_PROPERTY_ID, FONTS_PROPERTY_ID, ICON_PROPERTY_ID, FULLWIDTH_PROPERTY_ID, SYSTEM_PAGE_PROPERTIES, isVerified, verificationExpired, isVerificationActive, makeVerification, extractMentionIds, propertiesReferencePage, } from './pageProperties';
8
- export { getServerUrlOverride, setServerUrlOverride, getServerTokenOverride, setServerTokenOverride, isMixedContentBlocked } from './connection';
8
+ export { getServerUrlOverride, setServerUrlOverride, getServerTokenOverride, setServerTokenOverride, getIdentityCredential, setIdentityToken, setGuestName, getForwardingAudience, setForwardingAudience, isMixedContentBlocked } from './connection';
9
9
  export { AccountClient, AccountError, DEFAULT_ACCOUNT_URL, getAccountUrlOverride, setAccountUrlOverride, resolveAccountUrl, } from './account';
10
+ export { guestPrincipal, localPrincipal, principalId, mintIdentityKeypair, signIdentity, decodeIdentity, verifyIdentity, verifyRevocations, signRevocations, principalFromClaims, unverifiedPrincipalFromClaims, } from './identity';
11
+ export { DEFAULT_INSTANCE_CONFIG, } from './provenance';
12
+ export { authorize, isEmailAuthoritative, } from './authorize';
10
13
  export { snapshotText, paragraphBlocks, textSnapshot, appendTextToSnapshot, appendBlocksToSnapshot } from './content';
11
14
  export { snapshotBlocks, contentHash, computeBlockMtimes, stampSnapshotMtimes, latestBlockMtime, } from './mtime';
15
+ export { computeBlockAuthors, stampSnapshotAuthors, latestSnapshotAuthor } from './authors';
12
16
  export { pageToBookHtml, bookHtmlToPage, readBookHtmlMeta, slugify, } from './bookfile';
13
17
  export { spaceToBookFiles, parseBookFolder, SPACE_BUNDLE_FILE, } from './bookFolder';
14
18
  export { canonicalDigest, generateRegistryKeys, signPlugin, verifyPlugin, validateManifest, OPENBOOK_REGISTRY, } from './plugins';
15
19
  export { buildSampleDocument, seedSampleDocument, SAMPLE_DOCUMENT_NAME } from './sampleDocument';
16
20
  export { PAGE_TEMPLATES, instantiateTemplate } from './templates';
17
- export { BACKUP_VERSION, remapBundle, } from './backup';
18
- export { providerSettings } from './ai';
21
+ export { BACKUP_VERSION, BACKUP_CADENCES, BACKUP_CADENCE_MS, DEFAULT_BACKUP_CONFIG, remapBundle, } from './backup';
22
+ export { providerSettings, isPaidProvider } from './ai';
19
23
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,iBAAiB,EAAC,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAC,GAAG,EAAgB,MAAM,UAAU,CAAC;AAE5C,OAAO,EAAC,cAAc,EAAC,MAAM,UAAU,CAAC;AACxC,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,eAAe,EACf,eAAe,GAKhB,MAAM,cAAc,CAAC;AAgDtB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,cAAc,EACd,aAAa,EACb,OAAO,EACP,qBAAqB,EACrB,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,cAAc,EACd,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,OAAO,EACP,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,UAAU,EACV,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,YAAY,GAGb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,GAExB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,oBAAoB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,qBAAqB,EAAC,MAAM,cAAc,CAAC;AAC/I,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,GAElB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAC,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,oBAAoB,EAAE,sBAAsB,EAAmB,MAAM,WAAW,CAAC;AACtI,OAAO,EACL,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,GAEjB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,OAAO,GAER,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,GAGlB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,GAMlB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAC,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAC,MAAM,kBAAkB,CAAC;AAa/F,OAAO,EAAC,cAAc,EAAE,mBAAmB,EAAoB,MAAM,aAAa,CAAC;AACnF,OAAO,EACL,cAAc,EACd,WAAW,GAKZ,MAAM,UAAU,CAAC;AAkBlB,OAAO,EAAC,gBAAgB,EAAC,MAAM,MAAM,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Multi-user instance policy + change provenance (OB-165). The contract the
3
+ * server and clients share for: the guest-access gate, the set of trusted
4
+ * identity issuers, and the durable per-change edit log.
5
+ *
6
+ * Design: `docs/multi-user-and-backups-2026-06.md`.
7
+ */
8
+ import type { Jwks, Principal, RevocationSet, VerifiedVia } from './identity';
9
+ import type { MemberRole, PageVisibility } from './types';
10
+ /** What an unauthenticated (guest) caller may do on this instance. */
11
+ export type GuestAccess =
12
+ /** Guests are rejected entirely (sign-in required). */
13
+ 'off'
14
+ /** Guests may read, but not write. */
15
+ | 'read'
16
+ /** Guests may read and write (the default — same as a no-login workspace today). */
17
+ | 'write';
18
+ /** An identity issuer this instance trusts (issuer-rooted federation). */
19
+ export interface TrustedIssuerConfig {
20
+ /** The `iss` claim this config authorizes. */
21
+ issuer: string;
22
+ /** Where to (re)fetch the issuer's JWKS for online refresh. */
23
+ jwksUrl?: string;
24
+ /** Inline / cached JWKS — makes verification offline-capable (and is how the
25
+ * dev issuer ships its key). */
26
+ jwks?: Jwks;
27
+ /**
28
+ * Where to (re)fetch the issuer's revocation document (OB-106) — an EdDSA-signed
29
+ * JWS verified against the issuer's JWKS. Polled + cached like {@link jwksUrl},
30
+ * with a last-good offline fallback. Absent ⇒ this issuer publishes no
31
+ * revocations and every signature-valid, in-window token is honoured.
32
+ */
33
+ revocationsUrl?: string;
34
+ /**
35
+ * Inline / cached revocation set — config-trusted (like an inline {@link jwks}),
36
+ * so it needs no signature check. Mainly for the dev issuer and tests; the real
37
+ * account issuer ships a signed document via {@link revocationsUrl}.
38
+ */
39
+ revocations?: RevocationSet;
40
+ }
41
+ /** The instance's multi-user policy, persisted in the `settings` table. */
42
+ export interface InstanceConfig {
43
+ guestAccess: GuestAccess;
44
+ /** The principal subject that administers this instance, once claimed. */
45
+ ownerSubject?: string;
46
+ trustedIssuers: TrustedIssuerConfig[];
47
+ /**
48
+ * This server's own audience identifier (OB-177). When set, an identity token
49
+ * scoped to a *different* audience is rejected, and clients should request a
50
+ * token bound to this value. Leave unset for the single-server model.
51
+ */
52
+ audience?: string;
53
+ /** Require every identity token to be audience-bound to {@link audience}
54
+ * (reject unscoped tokens). Multi-server hardening. */
55
+ requireAudience?: boolean;
56
+ /**
57
+ * Default audience scope a page's `visibility='inherit'` resolves to at the root
58
+ * (OB-182 §2.4, Fork 1). Set to `'members'` (private) when the instance is
59
+ * claimed; an unclaimed instance never reaches the access path. Never `'inherit'`.
60
+ */
61
+ defaultVisibility?: Exclude<PageVisibility, 'inherit'>;
62
+ /**
63
+ * The ONE issuer whose `email` claim is trusted for persona / email-ACL matching
64
+ * (OB-182 §2.4, B1). Subject-based grants work for any {@link trustedIssuers}
65
+ * entry, but only a token from `emailAuthority` can satisfy an email persona or
66
+ * an email ACL. Must be one of {@link trustedIssuers} or every email grant
67
+ * silently (and safely) stops matching. Defaults to account.book.pub.
68
+ */
69
+ emailAuthority?: string;
70
+ /**
71
+ * When this instance is a MANAGED workspace (OB-199), the account workspace it
72
+ * is bound to. Set, the periodic roster sync projects that workspace's roster
73
+ * (admins / viewers + the workspace owner) into the local `members` table so
74
+ * `members`-scope + admin/viewer roles resolve for direct (non-edge) access too.
75
+ * Unset ⇒ a standalone instance; the sync is inert. Additive — absence is the
76
+ * pre-OB-199 single-instance behaviour. Holds non-secret COORDINATES only; the
77
+ * credential the instance presents to read the roster is supplied out-of-band
78
+ * (never persisted in policy). See {@link WorkspaceBinding}.
79
+ */
80
+ workspaceBinding?: WorkspaceBinding;
81
+ }
82
+ /**
83
+ * Binds a managed instance to an account workspace (OB-199). Non-secret
84
+ * coordinates only — the roster-read credential is injected at runtime, never
85
+ * stored here. Set by the owner (via the instance-policy route) or learned during
86
+ * the forwarding/claim flow.
87
+ */
88
+ export interface WorkspaceBinding {
89
+ /** The account workspace id this instance serves. */
90
+ workspaceId: string;
91
+ /**
92
+ * Base URL of the account that owns the workspace (where the roster lives).
93
+ * Defaults to the instance `emailAuthority` (account.book.pub) when omitted.
94
+ */
95
+ accountBaseUrl?: string;
96
+ }
97
+ /**
98
+ * One entry of the account workspace roster (OB-197 contract), as consumed by the
99
+ * OB-199 sync. Identifies a member by a bound `subject` (`iss#sub`) and/or a
100
+ * persona `email`, with the workspace role. The account is the producer; the
101
+ * instance only reads this shape (it never writes the account).
102
+ */
103
+ export interface WorkspaceRosterEntry {
104
+ /** Bound `iss#sub` of the member, when the account exposes it. */
105
+ subject?: string;
106
+ /** Persona email (any case; lowercased on sync). */
107
+ email?: string;
108
+ role: MemberRole;
109
+ }
110
+ /**
111
+ * The account workspace roster returned by `GET /api/workspaces/:id/members`
112
+ * (OB-197), as consumed by the OB-199 sync. `ownerSubject` is the workspace
113
+ * owner's bound subject (`iss#sub`) — admitted as an admin even when it differs
114
+ * from the instance's own site owner (OB-198 F2), so the workspace owner is never
115
+ * locked out of a workspace they own.
116
+ */
117
+ export interface WorkspaceRoster {
118
+ workspaceId: string;
119
+ /** Bound `iss#sub` of the workspace owner (admitted as admin). */
120
+ ownerSubject?: string;
121
+ members: WorkspaceRosterEntry[];
122
+ }
123
+ export declare const DEFAULT_INSTANCE_CONFIG: InstanceConfig;
124
+ /**
125
+ * Public view of the instance policy returned by `GET /api/instance` — issuer
126
+ * URLs only (never private JWKS material), plus the principal resolved for the
127
+ * *current* request, so a client can render "you are signed in as …" / "guest".
128
+ */
129
+ export interface InstanceInfo {
130
+ guestAccess: GuestAccess;
131
+ ownerSubject: string | null;
132
+ trustedIssuers: string[];
133
+ /** This server's audience identifier, so a client can request an `aud`-scoped
134
+ * identity token (OB-177). `null` for the single-server (unscoped) model. */
135
+ audience: string | null;
136
+ /** Whether this instance *requires* every identity token to be bound to
137
+ * {@link audience} (OB-202). Lets a client short-circuit the audience-bind on
138
+ * relaunch: when the server already persisted `audience==host && requireAudience`
139
+ * it only needs to ensure its own token is scoped, never to relax + re-assert.
140
+ * Optional: absent (e.g. a pre-OB-202 server / a test fixture) is treated as `false`. */
141
+ requireAudience?: boolean;
142
+ /** Who the server resolved you to be on this request. */
143
+ you: Principal;
144
+ /**
145
+ * Your active-persona roster role on this request (OB-182 §1.1), or `null` if
146
+ * you aren't an active member. Lets a client gate manager-only UI (the per-page
147
+ * Share dialog) without a per-page probe: `admin` (and the owner / loopback,
148
+ * derivable from {@link you} + {@link ownerSubject}) manage sharing.
149
+ * Optional: absent (a pre-OB-203 server / a test fixture) is treated as `null`.
150
+ */
151
+ youRole?: MemberRole | null;
152
+ }
153
+ /** One recorded change — a row of the append-only edit log. */
154
+ export interface StoredEdit {
155
+ id: string;
156
+ pageId: string | null;
157
+ authorSubject: string;
158
+ authorIssuer: string;
159
+ authorName: string;
160
+ verifiedVia: VerifiedVia;
161
+ /** What kind of change: `page.save`, `page.create`, `page.delete`, `row.update`, … */
162
+ kind: string;
163
+ /** The signed credential that authorized it (users only). */
164
+ assertionKid: string | null;
165
+ assertionJti: string | null;
166
+ summary: string;
167
+ createdAt: string;
168
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Multi-user instance policy + change provenance (OB-165). The contract the
3
+ * server and clients share for: the guest-access gate, the set of trusted
4
+ * identity issuers, and the durable per-change edit log.
5
+ *
6
+ * Design: `docs/multi-user-and-backups-2026-06.md`.
7
+ */
8
+ import { DEFAULT_ACCOUNT_URL } from './account';
9
+ export const DEFAULT_INSTANCE_CONFIG = {
10
+ guestAccess: 'write',
11
+ // Trust account.book.pub out of the box — it's the OpenBook identity authority
12
+ // (the shared root that makes identities federate across instances). Only ever
13
+ // consulted when an `iss=account.book.pub` assertion is actually presented; the
14
+ // JWKS is fetched + cached lazily. Override or extend in instance settings.
15
+ trustedIssuers: [
16
+ {
17
+ issuer: DEFAULT_ACCOUNT_URL,
18
+ jwksUrl: `${DEFAULT_ACCOUNT_URL}/api/identity/jwks`,
19
+ // Consult account.book.pub's revocation list (OB-106) — signed against the
20
+ // same JWKS, cached with a last-good offline fallback.
21
+ revocationsUrl: `${DEFAULT_ACCOUNT_URL}/api/identity/revocations`,
22
+ },
23
+ ],
24
+ // `inherit` at the root resolves here. Private-by-default once claimed (Fork 1);
25
+ // an unclaimed instance short-circuits before this is ever consulted (rule 0).
26
+ defaultVisibility: 'members',
27
+ // account.book.pub is the default email-authority — the one issuer whose `email`
28
+ // claim drives persona / email-ACL matching (B1). It is already trusted above.
29
+ emailAuthority: DEFAULT_ACCOUNT_URL,
30
+ };
31
+ //# sourceMappingURL=provenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance.js","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAC,mBAAmB,EAAC,MAAM,WAAW,CAAC;AA2H9C,MAAM,CAAC,MAAM,uBAAuB,GAAmB;IACrD,WAAW,EAAE,OAAO;IACpB,+EAA+E;IAC/E,+EAA+E;IAC/E,gFAAgF;IAChF,4EAA4E;IAC5E,cAAc,EAAE;QACd;YACE,MAAM,EAAE,mBAAmB;YAC3B,OAAO,EAAE,GAAG,mBAAmB,oBAAoB;YACnD,2EAA2E;YAC3E,uDAAuD;YACvD,cAAc,EAAE,GAAG,mBAAmB,2BAA2B;SAClE;KACF;IACD,iFAAiF;IACjF,+EAA+E;IAC/E,iBAAiB,EAAE,SAAS;IAC5B,iFAAiF;IACjF,+EAA+E;IAC/E,cAAc,EAAE,mBAAmB;CACpC,CAAC"}
package/dist/routes.d.ts CHANGED
@@ -82,7 +82,60 @@ export declare const API: {
82
82
  readonly comments: (pageId: string) => string;
83
83
  /** A single comment: `DELETE`. */
84
84
  readonly comment: (id: string) => string;
85
+ /**
86
+ * On-demand heavy database compaction (`POST`): VACUUM FULL to physically
87
+ * reclaim heap bloat. Embedded (PGlite) only — a server backed by external
88
+ * Postgres answers 409. See OB-164.
89
+ */
90
+ readonly compact: "/api/maintenance/compact";
91
+ /**
92
+ * Instance multi-user policy: `GET` returns {@link InstanceInfo} (guest
93
+ * policy, trusted issuer URLs, and the principal resolved for *this* request);
94
+ * `PUT` updates the policy (owner only).
95
+ */
96
+ readonly instance: "/api/instance";
97
+ /** A page's change provenance (the edit log), newest first: `GET`. */
98
+ readonly pageEdits: (id: string) => string;
99
+ /**
100
+ * The member roster: `GET` (list) / `POST` (invite by email or handle/subject).
101
+ * Instance-writer (owner/admin/loopback) only — managing or even seeing the
102
+ * roster is a privileged action.
103
+ */
104
+ readonly members: "/api/members";
105
+ /** A single roster row: `PATCH` (role/status) / `DELETE` (revoke). */
106
+ readonly member: (id: string) => string;
107
+ /**
108
+ * A page's per-page ACL grants: `GET` (list) / `POST` (share to an email or
109
+ * handle/subject) / `DELETE` (`?subject=` | `?email=` to revoke). Gated on
110
+ * write of the page itself (you manage sharing of pages you can write).
111
+ */
112
+ readonly pageAcl: (id: string) => string;
113
+ /**
114
+ * A page's audience-scope visibility (OB-182 §1.1): `GET` returns
115
+ * `{visibility}` (read-gated); `PUT` `{visibility}` sets it (write-gated — same
116
+ * "you manage sharing of pages you can write" rule as the ACL).
117
+ */
118
+ readonly pageVisibility: (id: string) => string;
119
+ /**
120
+ * On-demand roster sync of a managed instance: `GET` reports the binding +
121
+ * last-sync status; `POST` pulls the bound workspace roster from the account and
122
+ * reconciles it into the local roster (managed rows only). Instance-writer
123
+ * (owner/admin/loopback) only. The same sync also runs periodically.
124
+ */
125
+ readonly workspaceSync: "/api/workspace/sync";
126
+ /** Scheduled-backup policy: `GET` returns {@link BackupStatus}; `PUT` updates
127
+ * the policy and returns the new status. */
128
+ readonly backups: "/api/backups";
129
+ /** Run a backup immediately: `POST` `{cadence?}` → the written file's name. */
130
+ readonly backupRun: "/api/backups/run";
85
131
  };
132
+ /** Result of a {@link API.compact} run: the database's on-disk size before/after,
133
+ * in bytes, and how much was reclaimed. */
134
+ export interface CompactResult {
135
+ before: number;
136
+ after: number;
137
+ reclaimed: number;
138
+ }
86
139
  /** Error body shape returned by the API for non-2xx responses. */
87
140
  export interface ApiError {
88
141
  error: string;