@xtrable-ltd/nanoesis 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter-azure-blob.js +1 -1
- package/dist/{chunk-G2UEZTYC.js → chunk-22WHPW5E.js} +25 -0
- package/dist/editor-api.d.ts +32 -2
- package/dist/editor-api.js +142 -1
- package/dist/index.d.ts +66 -34
- package/dist/index.js +5 -1
- package/editor/assets/{TemplatesPane-5qsDAK_B.js → TemplatesPane-zK8lIC02.js} +7 -7
- package/editor/assets/{cssMode-CGp4MIjR.js → cssMode-Dx60SobP.js} +1 -1
- package/editor/assets/{freemarker2-CJkwxmPv.js → freemarker2-DGQjpiaU.js} +1 -1
- package/editor/assets/{handlebars-CKb5i2nM.js → handlebars-BltQV8dV.js} +1 -1
- package/editor/assets/{html-DyMbQx0w.js → html-Dcoxpshq.js} +1 -1
- package/editor/assets/{htmlMode-DVPeqtn-.js → htmlMode-CVqSJo7C.js} +1 -1
- package/editor/assets/{index-DJmSgobK.js → index-BSlglIW6.js} +76 -70
- package/editor/assets/{index-CbuWEnUB.css → index-Dj_8wB_d.css} +1 -1
- package/editor/assets/{javascript-Bp1Qh9wR.js → javascript-Bl74P5-A.js} +1 -1
- package/editor/assets/{jsonMode-FLEeVtx7.js → jsonMode-CTxdbzE_.js} +1 -1
- package/editor/assets/{liquid-Bh8c534t.js → liquid-TXEIIcAb.js} +1 -1
- package/editor/assets/{mdx-BUbo8M9l.js → mdx-C7X2Fz3X.js} +1 -1
- package/editor/assets/{python-CuJlk8g3.js → python-BIiW5QXV.js} +1 -1
- package/editor/assets/{razor-CuQT_1Ku.js → razor-CUdWEQ3M.js} +1 -1
- package/editor/assets/{tsMode-CT2HUNtN.js → tsMode-D_2_BwYS.js} +1 -1
- package/editor/assets/{typescript-CtMx97cn.js → typescript-BdSyn6PC.js} +1 -1
- package/editor/assets/{xml-CyfpINj_.js → xml-JVU5PVkk.js} +1 -1
- package/editor/assets/{yaml-BBWmgfMA.js → yaml-D2YDV-us.js} +1 -1
- package/editor/index.html +2 -2
- package/package.json +1 -1
|
@@ -182,6 +182,16 @@ async function saveIndex(store, prev, nextKeys) {
|
|
|
182
182
|
await store.put(INDEX_KEY, serialize(next));
|
|
183
183
|
return next;
|
|
184
184
|
}
|
|
185
|
+
async function reconcileIndex(store, actualKeys) {
|
|
186
|
+
const prev = await loadIndex(store);
|
|
187
|
+
const keys = [...new Set(actualKeys.filter((key) => !key.startsWith(RESERVED_PREFIX)))].sort();
|
|
188
|
+
const prevKeys = new Set(prev.keys);
|
|
189
|
+
const nextKeys = new Set(keys);
|
|
190
|
+
const added = keys.filter((key) => !prevKeys.has(key));
|
|
191
|
+
const removed = prev.keys.filter((key) => !nextKeys.has(key));
|
|
192
|
+
if (added.length === 0 && removed.length === 0) return { index: prev, added, removed };
|
|
193
|
+
return { index: await saveIndex(store, prev, keys), added, removed };
|
|
194
|
+
}
|
|
185
195
|
function freezeIndex(version, keys) {
|
|
186
196
|
const sorted = [...new Set(keys)].sort();
|
|
187
197
|
return { version, keys: sorted, checksum: checksumOf(version, sorted) };
|
|
@@ -312,6 +322,19 @@ var IndexedStore = class {
|
|
|
312
322
|
this.index = await saveIndex(this.store, index, next);
|
|
313
323
|
return { ok: true };
|
|
314
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Rebuild this store's index from the *actual* keys the underlying store holds (DESIGN
|
|
327
|
+
* §11d), recovering files that arrived by a path that bypassed the index. A
|
|
328
|
+
* {@link BlobStore} cannot enumerate itself, so the caller supplies the real key set
|
|
329
|
+
* from an adapter that can (e.g. `BlobContainer.list`). Unlike calling
|
|
330
|
+
* {@link reconcileIndex} on a fresh store, this also refreshes the cached in-memory
|
|
331
|
+
* index, so this live instance sees the recovered files immediately.
|
|
332
|
+
*/
|
|
333
|
+
async reconcile(actualKeys) {
|
|
334
|
+
const result = await reconcileIndex(this.store, actualKeys);
|
|
335
|
+
this.index = result.index;
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
315
338
|
};
|
|
316
339
|
function guarded(key) {
|
|
317
340
|
if (key === "" || key.startsWith(RESERVED_PREFIX)) {
|
|
@@ -2485,9 +2508,11 @@ export {
|
|
|
2485
2508
|
parseContentItem,
|
|
2486
2509
|
parseSortFile,
|
|
2487
2510
|
InMemoryBlobStore,
|
|
2511
|
+
RESERVED_PREFIX,
|
|
2488
2512
|
emptyIndex,
|
|
2489
2513
|
loadIndex,
|
|
2490
2514
|
saveIndex,
|
|
2515
|
+
reconcileIndex,
|
|
2491
2516
|
IndexedStore,
|
|
2492
2517
|
InMemoryContentSource,
|
|
2493
2518
|
parseRedirects,
|
package/dist/editor-api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WorkingStore, IdentityProvider, PublishResult, AuthEndpoints, UserAdminEndpoints, AuthorOption, UserSummary, AuthorDirectory } from '@nanoesis/engine';
|
|
1
|
+
import { WorkingStore, IdentityProvider, PublishResult, ReconcileResult, AuthEndpoints, UserAdminEndpoints, AuthorOption, UserSummary, AuthorDirectory } from '@nanoesis/engine';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Editor white-labelling storage (DESIGN §11, Phase B). This is the *editor app's*
|
|
@@ -100,6 +100,15 @@ interface ApiDeps {
|
|
|
100
100
|
readonly identity: IdentityProvider;
|
|
101
101
|
/** Run the publish pipeline (host binds source/sink/purge). */
|
|
102
102
|
readonly publish: () => Promise<PublishResult>;
|
|
103
|
+
/**
|
|
104
|
+
* Optional index-reconcile (DESIGN §11d): rebuild the working store's content index
|
|
105
|
+
* from the keys actually present, recovering files that arrived by a path that
|
|
106
|
+
* bypassed the index (the silent-bootstrap failure). When present, the router mounts
|
|
107
|
+
* the admin-gated `POST /api/reconcile`. The host binds it because enumerating the
|
|
108
|
+
* real key set needs the adapter's listing (`BlobContainer.list`), which the engine's
|
|
109
|
+
* `BlobStore` deliberately lacks. Omitted on stores that cannot enumerate.
|
|
110
|
+
*/
|
|
111
|
+
readonly reconcile?: () => Promise<ReconcileResult>;
|
|
103
112
|
/**
|
|
104
113
|
* Optional credential-management surface (DESIGN §11). When present, the router
|
|
105
114
|
* mounts `/api/login`, `/api/refresh`, `/api/logout`, and `/api/auth/state`,
|
|
@@ -195,4 +204,25 @@ declare function readMcpResource(uri: string): {
|
|
|
195
204
|
readonly mimeType: string;
|
|
196
205
|
} | undefined;
|
|
197
206
|
|
|
198
|
-
|
|
207
|
+
/**
|
|
208
|
+
* The first-run starter site (DESIGN §14): a minimal, self-contained set of files that
|
|
209
|
+
* turns an empty working store into a real, publishable site. It is the *blessed* way to
|
|
210
|
+
* get initial content in — written through the editor API (so the content index stays
|
|
211
|
+
* authoritative by construction, never the bypassing path that silently breaks a store,
|
|
212
|
+
* §11d) and bundled here as **pure data**, so the engine's purity is untouched and the
|
|
213
|
+
* scaffold works identically for every host and the MCP server with no per-host wiring.
|
|
214
|
+
*
|
|
215
|
+
* Deliberately minimal (the owner's call, distinct from the fuller `examples/starter`):
|
|
216
|
+
* one home page, a page template, the document shell, and a stylesheet. It is gate-clean
|
|
217
|
+
* by construction — no collection loops (nothing to point at yet), no custom components,
|
|
218
|
+
* no required fields left unset — so a fresh adopter can publish it immediately, and the
|
|
219
|
+
* home page is a **draft** (`isPublished: false`) so going live is a deliberate act.
|
|
220
|
+
*/
|
|
221
|
+
/**
|
|
222
|
+
* The starter files, keyed by working-store path. Written through the store's `write`
|
|
223
|
+
* (so the index records each), in this order — templates and styles before the content
|
|
224
|
+
* that depends on them, though the store has no cross-file ordering requirement.
|
|
225
|
+
*/
|
|
226
|
+
declare const SCAFFOLD_FILES: Readonly<Record<string, string>>;
|
|
227
|
+
|
|
228
|
+
export { type ApiDeps, type ApiRequest, type ApiResponse, type BrandingLogo, type BrandingLogoMeta, type BrandingState, type BrandingStore, FileBrandingStore, InMemoryBrandingStore, MCP_RESOURCES, MCP_TOOLS, type McpCallOptions, type McpResourceDef, type McpToolDef, type McpToolResult, SCAFFOLD_FILES, authorDirectory, authorOptions, callMcpTool, handleApi, readMcpResource };
|
package/dist/editor-api.js
CHANGED
|
@@ -8,7 +8,111 @@ import {
|
|
|
8
8
|
loadTemplate,
|
|
9
9
|
renderReferenceMarkdown,
|
|
10
10
|
validateSite
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-22WHPW5E.js";
|
|
12
|
+
|
|
13
|
+
// ../editor-api/src/scaffold.ts
|
|
14
|
+
var DOCUMENT_HTML = `<!doctype html>
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="utf-8" />
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
19
|
+
<title>{title}</title>
|
|
20
|
+
<meta name="description" content="{meta_description}" />
|
|
21
|
+
<link rel="stylesheet" href="/styles.css" />
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<header class="site-header">
|
|
25
|
+
<a class="brand" href="/">Your site</a>
|
|
26
|
+
</header>
|
|
27
|
+
<main>
|
|
28
|
+
<slot></slot>
|
|
29
|
+
</main>
|
|
30
|
+
<footer class="site-footer">
|
|
31
|
+
<p>Built with nanoesis \u2014 static HTML, no runtime.</p>
|
|
32
|
+
</footer>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
|
35
|
+
`;
|
|
36
|
+
var HOME_HTML = `<section class="hero">
|
|
37
|
+
<h1>{title}</h1>
|
|
38
|
+
<p class="lead">{lead}</p>
|
|
39
|
+
</section>
|
|
40
|
+
<div class="prose" data-type="richtext">{body}</div>
|
|
41
|
+
`;
|
|
42
|
+
var HOME_JSON = `${JSON.stringify(
|
|
43
|
+
{
|
|
44
|
+
template: "home",
|
|
45
|
+
title: "Welcome",
|
|
46
|
+
isPublished: false,
|
|
47
|
+
fields: {
|
|
48
|
+
lead: "Edit this page in the nanoesis editor, then publish when you are ready.",
|
|
49
|
+
body: "<p>This is your new site. It compiles to plain static HTML \u2014 there is no server and no client framework, and nothing of the editor survives into production.</p>"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
null,
|
|
53
|
+
2
|
|
54
|
+
)}
|
|
55
|
+
`;
|
|
56
|
+
var STYLES_CSS = `:root {
|
|
57
|
+
--ink: #1a1a2e;
|
|
58
|
+
--muted: #555;
|
|
59
|
+
--accent: #4f46e5;
|
|
60
|
+
--max: 42rem;
|
|
61
|
+
font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
62
|
+
line-height: 1.6;
|
|
63
|
+
color: var(--ink);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
body {
|
|
67
|
+
margin: 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.site-header,
|
|
71
|
+
main,
|
|
72
|
+
.site-footer {
|
|
73
|
+
max-width: var(--max);
|
|
74
|
+
margin-inline: auto;
|
|
75
|
+
padding: 1.5rem 1.25rem;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.site-header .brand {
|
|
79
|
+
font-weight: 700;
|
|
80
|
+
text-decoration: none;
|
|
81
|
+
color: var(--ink);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.hero h1 {
|
|
85
|
+
font-size: 2.25rem;
|
|
86
|
+
letter-spacing: -0.01em;
|
|
87
|
+
margin: 0 0 0.5rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.lead {
|
|
91
|
+
font-size: 1.2rem;
|
|
92
|
+
color: var(--muted);
|
|
93
|
+
margin: 0 0 2rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.prose {
|
|
97
|
+
font-size: 1.05rem;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
a {
|
|
101
|
+
color: var(--accent);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.site-footer {
|
|
105
|
+
color: var(--muted);
|
|
106
|
+
font-size: 0.9rem;
|
|
107
|
+
border-top: 1px solid #eee;
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
var SCAFFOLD_FILES = {
|
|
111
|
+
"templates/document.html": DOCUMENT_HTML,
|
|
112
|
+
"templates/home.html": HOME_HTML,
|
|
113
|
+
"public/styles.css": STYLES_CSS,
|
|
114
|
+
"content/index.json": HOME_JSON
|
|
115
|
+
};
|
|
12
116
|
|
|
13
117
|
// ../editor-api/src/api.ts
|
|
14
118
|
var MAX_LOGO_BYTES = 1024 * 1024;
|
|
@@ -283,6 +387,42 @@ async function handleApi(deps, req) {
|
|
|
283
387
|
if (result.ok) return json(200, { ok: true, written: result.written.length });
|
|
284
388
|
return json(422, { ok: false, errors: result.validation.errors.map((e) => e.message) });
|
|
285
389
|
}
|
|
390
|
+
case "/api/scaffold": {
|
|
391
|
+
if (req.method !== "POST") return methodNotAllowed();
|
|
392
|
+
if (!hasRole(principal, "admin")) {
|
|
393
|
+
return json(403, { ok: false, error: "admin role required" });
|
|
394
|
+
}
|
|
395
|
+
if ((await deps.store.list("content")).length > 0) {
|
|
396
|
+
return json(409, { ok: false, error: "site already has content" });
|
|
397
|
+
}
|
|
398
|
+
const created = [];
|
|
399
|
+
const skipped = [];
|
|
400
|
+
for (const [path, content] of Object.entries(SCAFFOLD_FILES)) {
|
|
401
|
+
if (await deps.store.exists(path)) {
|
|
402
|
+
skipped.push(path);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
await deps.store.write(path, new TextEncoder().encode(content));
|
|
406
|
+
created.push(path);
|
|
407
|
+
}
|
|
408
|
+
return json(200, { ok: true, created, skipped });
|
|
409
|
+
}
|
|
410
|
+
case "/api/reconcile": {
|
|
411
|
+
if (req.method !== "POST") return methodNotAllowed();
|
|
412
|
+
if (deps.reconcile === void 0) {
|
|
413
|
+
return json(404, { ok: false, error: "reconcile is not available on this host" });
|
|
414
|
+
}
|
|
415
|
+
if (!hasRole(principal, "admin")) {
|
|
416
|
+
return json(403, { ok: false, error: "admin role required" });
|
|
417
|
+
}
|
|
418
|
+
const result = await deps.reconcile();
|
|
419
|
+
return json(200, {
|
|
420
|
+
ok: true,
|
|
421
|
+
added: result.added.length,
|
|
422
|
+
removed: result.removed.length,
|
|
423
|
+
total: result.index.keys.length
|
|
424
|
+
});
|
|
425
|
+
}
|
|
286
426
|
case "/api/me/password": {
|
|
287
427
|
if (req.method !== "POST") return methodNotAllowed();
|
|
288
428
|
if (deps.authEndpoints === void 0) {
|
|
@@ -584,6 +724,7 @@ export {
|
|
|
584
724
|
InMemoryBrandingStore,
|
|
585
725
|
MCP_RESOURCES,
|
|
586
726
|
MCP_TOOLS,
|
|
727
|
+
SCAFFOLD_FILES,
|
|
587
728
|
authorDirectory,
|
|
588
729
|
authorOptions,
|
|
589
730
|
callMcpTool,
|
package/dist/index.d.ts
CHANGED
|
@@ -203,6 +203,62 @@ interface WorkingStore extends ContentSource {
|
|
|
203
203
|
rename(from: string, to: string): Promise<RenameResult>;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
/**
|
|
207
|
+
* The content index (DESIGN §11d): the sorted set of every key in the working store,
|
|
208
|
+
* the directory listing a flat blob store cannot give cheaply, lifted into one object
|
|
209
|
+
* we own. Enumeration (the editor tree, compile) reads this, so the adopter's store
|
|
210
|
+
* stays get/put/delete with no `list`. Persisted under a reserved key with a fixed-size
|
|
211
|
+
* backup ring for integrity.
|
|
212
|
+
*/
|
|
213
|
+
interface ContentIndex {
|
|
214
|
+
/** Monotonic, bumped on every save; orders the backup ring during recovery. */
|
|
215
|
+
readonly version: number;
|
|
216
|
+
/** Every key that exists, sorted and de-duplicated (deterministic, CLAUDE §2). */
|
|
217
|
+
readonly keys: readonly string[];
|
|
218
|
+
/** Checksum over version + keys, so a corrupt stored index is caught on read. */
|
|
219
|
+
readonly checksum: string;
|
|
220
|
+
}
|
|
221
|
+
/** Reserved key prefix for the index and its backups; excluded from enumeration. */
|
|
222
|
+
declare const RESERVED_PREFIX = ".nanoesis/";
|
|
223
|
+
/** The empty index of a fresh store: version 0, no keys. */
|
|
224
|
+
declare function emptyIndex(): ContentIndex;
|
|
225
|
+
/**
|
|
226
|
+
* Load the index, recovering through the backup ring if the live copy is missing or
|
|
227
|
+
* corrupt (DESIGN §11d): the highest valid version among the ring slots wins. Returns
|
|
228
|
+
* the empty index when nothing valid is found, a fresh store, or the accepted residual
|
|
229
|
+
* case where the live index and every backup are lost (the files still exist by key,
|
|
230
|
+
* but cannot be enumerated until something rewrites the index).
|
|
231
|
+
*/
|
|
232
|
+
declare function loadIndex(store: BlobStore): Promise<ContentIndex>;
|
|
233
|
+
/**
|
|
234
|
+
* Write a new index whose keys are `nextKeys`, backing up the one it replaces first
|
|
235
|
+
* (DESIGN §11d). The previous index goes into its ring slot (`version % ring`, oldest
|
|
236
|
+
* overwritten), then the new index is written to the live key, a constant two writes
|
|
237
|
+
* per save regardless of ring size. Returns the new index (the caller's next `prev`).
|
|
238
|
+
*/
|
|
239
|
+
declare function saveIndex(store: BlobStore, prev: ContentIndex, nextKeys: readonly string[]): Promise<ContentIndex>;
|
|
240
|
+
/** What a {@link reconcileIndex} did, for a maintenance UI/CLI and the startup signal. */
|
|
241
|
+
interface ReconcileResult {
|
|
242
|
+
/** The index after reconciling (the prior one unchanged when nothing differed). */
|
|
243
|
+
readonly index: ContentIndex;
|
|
244
|
+
/** Keys now in the index that the prior index lacked (orphaned blobs, recovered). */
|
|
245
|
+
readonly added: readonly string[];
|
|
246
|
+
/** Keys the prior index held that no longer exist in the store (stale entries dropped). */
|
|
247
|
+
readonly removed: readonly string[];
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Rebuild the index from the store's *actual* keys (DESIGN §11d): the safety net for a
|
|
251
|
+
* store that got files by a path that bypassed the index, where the files are present
|
|
252
|
+
* by key but unenumerable. The engine cannot list a {@link BlobStore} (none is required
|
|
253
|
+
* to, §11c), so the caller supplies the real key set, an adapter that *can* enumerate
|
|
254
|
+
* (e.g. `BlobContainer.list`) provides it; the rebuild stays pure index logic here.
|
|
255
|
+
*
|
|
256
|
+
* The reserved namespace is never indexed (the index is not its own content). When the
|
|
257
|
+
* resulting key set matches the existing index this is a no-op, no write, no version
|
|
258
|
+
* bump, so reconciling a healthy store is cheap and idempotent.
|
|
259
|
+
*/
|
|
260
|
+
declare function reconcileIndex(store: BlobStore, actualKeys: readonly string[]): Promise<ReconcileResult>;
|
|
261
|
+
|
|
206
262
|
/**
|
|
207
263
|
* A {@link ContentSource} backed by the content index (DESIGN §11d) over a
|
|
208
264
|
* {@link BlobStore}: enumeration (`list`/`exists`) is synthesised from the index's key
|
|
@@ -251,41 +307,17 @@ declare class IndexedStore implements WorkingStore {
|
|
|
251
307
|
* still throws.)
|
|
252
308
|
*/
|
|
253
309
|
rename(from: string, to: string): Promise<RenameResult>;
|
|
310
|
+
/**
|
|
311
|
+
* Rebuild this store's index from the *actual* keys the underlying store holds (DESIGN
|
|
312
|
+
* §11d), recovering files that arrived by a path that bypassed the index. A
|
|
313
|
+
* {@link BlobStore} cannot enumerate itself, so the caller supplies the real key set
|
|
314
|
+
* from an adapter that can (e.g. `BlobContainer.list`). Unlike calling
|
|
315
|
+
* {@link reconcileIndex} on a fresh store, this also refreshes the cached in-memory
|
|
316
|
+
* index, so this live instance sees the recovered files immediately.
|
|
317
|
+
*/
|
|
318
|
+
reconcile(actualKeys: readonly string[]): Promise<ReconcileResult>;
|
|
254
319
|
}
|
|
255
320
|
|
|
256
|
-
/**
|
|
257
|
-
* The content index (DESIGN §11d): the sorted set of every key in the working store,
|
|
258
|
-
* the directory listing a flat blob store cannot give cheaply, lifted into one object
|
|
259
|
-
* we own. Enumeration (the editor tree, compile) reads this, so the adopter's store
|
|
260
|
-
* stays get/put/delete with no `list`. Persisted under a reserved key with a fixed-size
|
|
261
|
-
* backup ring for integrity.
|
|
262
|
-
*/
|
|
263
|
-
interface ContentIndex {
|
|
264
|
-
/** Monotonic, bumped on every save; orders the backup ring during recovery. */
|
|
265
|
-
readonly version: number;
|
|
266
|
-
/** Every key that exists, sorted and de-duplicated (deterministic, CLAUDE §2). */
|
|
267
|
-
readonly keys: readonly string[];
|
|
268
|
-
/** Checksum over version + keys, so a corrupt stored index is caught on read. */
|
|
269
|
-
readonly checksum: string;
|
|
270
|
-
}
|
|
271
|
-
/** The empty index of a fresh store: version 0, no keys. */
|
|
272
|
-
declare function emptyIndex(): ContentIndex;
|
|
273
|
-
/**
|
|
274
|
-
* Load the index, recovering through the backup ring if the live copy is missing or
|
|
275
|
-
* corrupt (DESIGN §11d): the highest valid version among the ring slots wins. Returns
|
|
276
|
-
* the empty index when nothing valid is found, a fresh store, or the accepted residual
|
|
277
|
-
* case where the live index and every backup are lost (the files still exist by key,
|
|
278
|
-
* but cannot be enumerated until something rewrites the index).
|
|
279
|
-
*/
|
|
280
|
-
declare function loadIndex(store: BlobStore): Promise<ContentIndex>;
|
|
281
|
-
/**
|
|
282
|
-
* Write a new index whose keys are `nextKeys`, backing up the one it replaces first
|
|
283
|
-
* (DESIGN §11d). The previous index goes into its ring slot (`version % ring`, oldest
|
|
284
|
-
* overwritten), then the new index is written to the live key, a constant two writes
|
|
285
|
-
* per save regardless of ring size. Returns the new index (the caller's next `prev`).
|
|
286
|
-
*/
|
|
287
|
-
declare function saveIndex(store: BlobStore, prev: ContentIndex, nextKeys: readonly string[]): Promise<ContentIndex>;
|
|
288
|
-
|
|
289
321
|
/**
|
|
290
322
|
* The authors byline (DESIGN §6.11). An `authors` field stores an ordered list of
|
|
291
323
|
* author refs; the compiler renders them as one grammatical line. Everything here
|
|
@@ -1235,4 +1267,4 @@ declare function escapeJsonStringContent(value: string): string;
|
|
|
1235
1267
|
*/
|
|
1236
1268
|
declare function sanitizeUrl(url: string): string;
|
|
1237
1269
|
|
|
1238
|
-
export { type Artifact, type ArtifactSink, type AuthEndpoints, type AuthResult, type AuthorDirectory, type AuthorEntry, type AuthorOption, type AuthorRef, type AuthoringReference, type BlobStore, type BoundItem, type ChangePasswordRequest, type ChangePasswordSuccess, type CollectionConfig, type CollectionQuery, type CompileInput, type CompilePageOptions, type CompileSiteOptions, type CompiledPage, type ComponentMap, type ContentIndex, type ContentItem, ContentParseError, type ContentSource, type CreateTokenSuccess, type CreateUserRequest, DEFAULT_DIRS, DOCUMENT_SHELL, type DerivedField, type Diagnostic, type DirEntry, type DirNode, type EncodeRequest, type EncodedImage, type EncodedVariant, type EntryKind, FIELD_TYPES, type FieldPrimitive, type FieldRecord, type FieldType, type FieldTypeDef, type FieldValue, type IdentityProvider, type ImageEncoder, type ImageFormat, type ImageInfo, InMemoryArtifactSink, InMemoryBlobStore, InMemoryContentSource, IndexedStore, type ItemNode, type LengthConstraints, type LoginRequest, type LoginSuccess, type MediaResolver, type PageEntry, type PreBuildHook, type Principal, type PublishOptions, type PublishResult, type PurgeService, type RedirectRule, type ReferenceContext, type ReferenceEntry, type ReferenceSection, type RefreshSuccess, type RenameResult, type ResetPasswordRequest, type ResolveContext, type Role, type RssOptions, type Scope, type Severity, type SiteConfig, type SortFile, type TemplateAnalysis, type TokenContext, type TokenRef, type TreeNode, type UpdateUserRequest, type UserAdminEndpoints, type UserSummary, type ValidationResult, type ValueKind, type WorkingStore, analyzeTemplate, buildAuthoringReference, buildContentIndex, buildPictureMarkup, buildRedirects, buildResolveContext, buildRss, buildSitemap, canEdit, compilePage, compileSite, compileTemplate, contentHash, contentTypeFor, deriveFields, emptyIndex, escapeHtmlAttribute, escapeHtmlText, escapeJsonStringContent, findTokens, hasRole, humanize, inferControl, isFieldType, joinAuthors, loadComponentScripts, loadComponentStyles, loadComponents, loadContentTree, loadDocumentShell, loadIndex, loadRedirects, loadSiteConfig, loadTemplate, noopPurgeService, outputPathForItem, parseContentItem, parseRedirects, parseSortFile, processImage, publishSite, renderAuthors, renderReferenceMarkdown, sanitizeUrl, saveIndex, slugify, textContent, toAuthorRefs, urlForItem, validateSite, valueKindOf, wholeValueToken };
|
|
1270
|
+
export { type Artifact, type ArtifactSink, type AuthEndpoints, type AuthResult, type AuthorDirectory, type AuthorEntry, type AuthorOption, type AuthorRef, type AuthoringReference, type BlobStore, type BoundItem, type ChangePasswordRequest, type ChangePasswordSuccess, type CollectionConfig, type CollectionQuery, type CompileInput, type CompilePageOptions, type CompileSiteOptions, type CompiledPage, type ComponentMap, type ContentIndex, type ContentItem, ContentParseError, type ContentSource, type CreateTokenSuccess, type CreateUserRequest, DEFAULT_DIRS, DOCUMENT_SHELL, type DerivedField, type Diagnostic, type DirEntry, type DirNode, type EncodeRequest, type EncodedImage, type EncodedVariant, type EntryKind, FIELD_TYPES, type FieldPrimitive, type FieldRecord, type FieldType, type FieldTypeDef, type FieldValue, type IdentityProvider, type ImageEncoder, type ImageFormat, type ImageInfo, InMemoryArtifactSink, InMemoryBlobStore, InMemoryContentSource, IndexedStore, type ItemNode, type LengthConstraints, type LoginRequest, type LoginSuccess, type MediaResolver, type PageEntry, type PreBuildHook, type Principal, type PublishOptions, type PublishResult, type PurgeService, RESERVED_PREFIX, type ReconcileResult, type RedirectRule, type ReferenceContext, type ReferenceEntry, type ReferenceSection, type RefreshSuccess, type RenameResult, type ResetPasswordRequest, type ResolveContext, type Role, type RssOptions, type Scope, type Severity, type SiteConfig, type SortFile, type TemplateAnalysis, type TokenContext, type TokenRef, type TreeNode, type UpdateUserRequest, type UserAdminEndpoints, type UserSummary, type ValidationResult, type ValueKind, type WorkingStore, analyzeTemplate, buildAuthoringReference, buildContentIndex, buildPictureMarkup, buildRedirects, buildResolveContext, buildRss, buildSitemap, canEdit, compilePage, compileSite, compileTemplate, contentHash, contentTypeFor, deriveFields, emptyIndex, escapeHtmlAttribute, escapeHtmlText, escapeJsonStringContent, findTokens, hasRole, humanize, inferControl, isFieldType, joinAuthors, loadComponentScripts, loadComponentStyles, loadComponents, loadContentTree, loadDocumentShell, loadIndex, loadRedirects, loadSiteConfig, loadTemplate, noopPurgeService, outputPathForItem, parseContentItem, parseRedirects, parseSortFile, processImage, publishSite, reconcileIndex, renderAuthors, renderReferenceMarkdown, sanitizeUrl, saveIndex, slugify, textContent, toAuthorRefs, urlForItem, validateSite, valueKindOf, wholeValueToken };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
InMemoryBlobStore,
|
|
8
8
|
InMemoryContentSource,
|
|
9
9
|
IndexedStore,
|
|
10
|
+
RESERVED_PREFIX,
|
|
10
11
|
analyzeTemplate,
|
|
11
12
|
buildAuthoringReference,
|
|
12
13
|
buildContentIndex,
|
|
@@ -48,6 +49,7 @@ import {
|
|
|
48
49
|
parseSortFile,
|
|
49
50
|
processImage,
|
|
50
51
|
publishSite,
|
|
52
|
+
reconcileIndex,
|
|
51
53
|
renderAuthors,
|
|
52
54
|
renderReferenceMarkdown,
|
|
53
55
|
sanitizeUrl,
|
|
@@ -59,7 +61,7 @@ import {
|
|
|
59
61
|
validateSite,
|
|
60
62
|
valueKindOf,
|
|
61
63
|
wholeValueToken
|
|
62
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-22WHPW5E.js";
|
|
63
65
|
export {
|
|
64
66
|
ContentParseError,
|
|
65
67
|
DEFAULT_DIRS,
|
|
@@ -69,6 +71,7 @@ export {
|
|
|
69
71
|
InMemoryBlobStore,
|
|
70
72
|
InMemoryContentSource,
|
|
71
73
|
IndexedStore,
|
|
74
|
+
RESERVED_PREFIX,
|
|
72
75
|
analyzeTemplate,
|
|
73
76
|
buildAuthoringReference,
|
|
74
77
|
buildContentIndex,
|
|
@@ -110,6 +113,7 @@ export {
|
|
|
110
113
|
parseSortFile,
|
|
111
114
|
processImage,
|
|
112
115
|
publishSite,
|
|
116
|
+
reconcileIndex,
|
|
113
117
|
renderAuthors,
|
|
114
118
|
renderReferenceMarkdown,
|
|
115
119
|
sanitizeUrl,
|