@drawnagency/primitives 0.1.114 → 0.1.116

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 (119) hide show
  1. package/dist/chunk-26V4YNOR.js +108 -0
  2. package/dist/{chunk-OAGJBCSH.js → chunk-4WQ36ZP7.js} +19 -3
  3. package/dist/{chunk-PTY2RG2K.js → chunk-67P34WNW.js} +75 -130
  4. package/dist/chunk-APIJPTFG.js +64 -0
  5. package/dist/chunk-CDBURDPX.js +90 -0
  6. package/dist/{chunk-PLANHXS7.js → chunk-CEFFP3CH.js} +2 -2
  7. package/dist/chunk-DFKTF3CH.js +0 -0
  8. package/dist/chunk-DJABADOO.js +131 -0
  9. package/dist/{chunk-IP2SEBAJ.js → chunk-DJOGPSRU.js} +31 -72
  10. package/dist/chunk-DKZCHCV3.js +64 -0
  11. package/dist/chunk-FGQXHUAE.js +39 -0
  12. package/dist/chunk-GNF6KFQ7.js +18 -0
  13. package/dist/{chunk-QHMKIODQ.js → chunk-HHNPSKPT.js} +2 -89
  14. package/dist/{chunk-PZPGJZRG.js → chunk-HUOW3ZV2.js} +3 -3
  15. package/dist/{chunk-Y5QECJX7.js → chunk-L7WTERU5.js} +2 -2
  16. package/dist/{chunk-N3G7DOU3.js → chunk-LNQUUC2S.js} +2 -2
  17. package/dist/{chunk-7SAAJVDE.js → chunk-MSBHMY3C.js} +17 -15
  18. package/dist/{chunk-PNSCDBU7.js → chunk-O37AV27P.js} +6 -49
  19. package/dist/{chunk-5KSAS4VY.js → chunk-RIITGTV3.js} +1 -1
  20. package/dist/chunk-S7QRHUWO.js +8 -0
  21. package/dist/chunk-VY3IFGE3.js +70 -0
  22. package/dist/{chunk-VUYCRBJK.js → chunk-W72BPGR3.js} +7 -5
  23. package/dist/collab/rebase.d.ts.map +1 -1
  24. package/dist/collab/rebase.js +15 -15
  25. package/dist/components/editor/index.js +8 -8
  26. package/dist/components/primitives/index.js +14 -9
  27. package/dist/components/sections/brand-guide.js +12 -7
  28. package/dist/components/sections/register-schemas.js +17 -12
  29. package/dist/components/sections/register.js +17 -12
  30. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  31. package/dist/deck-builder/index.js +6 -6
  32. package/dist/hooks/useEditorPublish.d.ts +4 -1
  33. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  34. package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
  35. package/dist/index.js +78 -49
  36. package/dist/lib/dexie.d.ts +7 -1
  37. package/dist/lib/dexie.d.ts.map +1 -1
  38. package/dist/lib/dexie.js +3 -2
  39. package/dist/lib/document-refs.d.ts +8 -0
  40. package/dist/lib/document-refs.d.ts.map +1 -1
  41. package/dist/lib/document-refs.js +14 -0
  42. package/dist/lib/image-variant-plan.d.ts +42 -0
  43. package/dist/lib/image-variant-plan.d.ts.map +1 -0
  44. package/dist/lib/image-variant-plan.js +53 -0
  45. package/dist/lib/index-ops.d.ts.map +1 -1
  46. package/dist/lib/index-ops.js +20 -16
  47. package/dist/lib/index.d.ts +2 -1
  48. package/dist/lib/index.d.ts.map +1 -1
  49. package/dist/lib/index.js +36 -15
  50. package/dist/lib/loader.d.ts +16 -17
  51. package/dist/lib/loader.d.ts.map +1 -1
  52. package/dist/lib/media-ops.d.ts +73 -0
  53. package/dist/lib/media-ops.d.ts.map +1 -0
  54. package/dist/lib/media-ops.js +60 -0
  55. package/dist/lib/nav-tree.d.ts +6 -0
  56. package/dist/lib/nav-tree.d.ts.map +1 -1
  57. package/dist/lib/pages.d.ts +2 -1
  58. package/dist/lib/pages.d.ts.map +1 -1
  59. package/dist/lib/reference-validation.js +4 -33
  60. package/dist/lib/section-check.d.ts +49 -0
  61. package/dist/lib/section-check.d.ts.map +1 -0
  62. package/dist/lib/section-check.js +14 -0
  63. package/dist/lib/sidecar-diagnostics.d.ts +20 -0
  64. package/dist/lib/sidecar-diagnostics.d.ts.map +1 -0
  65. package/dist/lib/sidecars.d.ts +118 -0
  66. package/dist/lib/sidecars.d.ts.map +1 -0
  67. package/dist/lib/sidecars.js +23 -0
  68. package/dist/lib/site-validation.d.ts +123 -0
  69. package/dist/lib/site-validation.d.ts.map +1 -0
  70. package/dist/lib/site-validation.js +230 -0
  71. package/dist/lib/slug.d.ts +2 -0
  72. package/dist/lib/slug.d.ts.map +1 -0
  73. package/dist/lib/storage-tier.d.ts +17 -0
  74. package/dist/lib/storage-tier.d.ts.map +1 -0
  75. package/dist/lib/storage-tier.js +29 -0
  76. package/dist/lib/tags.d.ts +6 -0
  77. package/dist/lib/tags.d.ts.map +1 -1
  78. package/dist/media/index.js +15 -15
  79. package/dist/media/queue.d.ts +2 -0
  80. package/dist/media/queue.d.ts.map +1 -1
  81. package/dist/media/worker.d.ts +1 -35
  82. package/dist/media/worker.d.ts.map +1 -1
  83. package/dist/schemas/index.js +18 -12
  84. package/dist/schemas/media.d.ts +4 -0
  85. package/dist/schemas/media.d.ts.map +1 -1
  86. package/dist/storage/index.js +2 -1
  87. package/dist/storage/memory.d.ts +21 -0
  88. package/dist/storage/memory.d.ts.map +1 -0
  89. package/dist/storage/memory.js +129 -0
  90. package/dist/storage/types.d.ts +9 -0
  91. package/dist/storage/types.d.ts.map +1 -1
  92. package/package.json +34 -1
  93. package/src/collab/rebase.ts +12 -16
  94. package/src/components/shell/EditorShell.tsx +7 -4
  95. package/src/hooks/useEditorPublish.ts +9 -4
  96. package/src/hooks/useMediaPipeline.ts +29 -23
  97. package/src/lib/dexie.ts +9 -1
  98. package/src/lib/document-refs.ts +30 -0
  99. package/src/lib/image-variant-plan.ts +92 -0
  100. package/src/lib/index-ops.ts +9 -18
  101. package/src/lib/index.ts +15 -0
  102. package/src/lib/loader.ts +18 -77
  103. package/src/lib/media-ops.ts +112 -0
  104. package/src/lib/nav-tree.ts +33 -4
  105. package/src/lib/pages.ts +2 -3
  106. package/src/lib/section-check.ts +166 -0
  107. package/src/lib/sidecar-diagnostics.ts +29 -0
  108. package/src/lib/sidecars.ts +221 -0
  109. package/src/lib/site-validation.ts +269 -0
  110. package/src/lib/slug.ts +6 -0
  111. package/src/lib/storage-tier.ts +38 -0
  112. package/src/lib/tags.ts +20 -3
  113. package/src/media/queue.ts +3 -0
  114. package/src/media/utils.ts +1 -1
  115. package/src/media/worker.ts +17 -8
  116. package/src/schemas/media.ts +7 -2
  117. package/src/storage/memory.ts +178 -0
  118. package/src/storage/types.ts +15 -2
  119. /package/dist/{chunk-45FA7Z55.js → chunk-UUUSJDIG.js} +0 -0
@@ -1,5 +1,8 @@
1
1
  import { type Section } from "../schemas/sections";
2
2
  import { type SiteIndex, type SectionMeta } from "../schemas/site-config";
3
+ import type { NavEntry } from "../schemas/nav";
4
+ import type { TagEntry } from "../schemas/tags";
5
+ import type { SidecarRead } from "./sidecars";
3
6
  export interface LoadedSection {
4
7
  section: Section;
5
8
  meta: SectionMeta;
@@ -10,39 +13,35 @@ export interface LoadedSection {
10
13
  export interface SiteContent {
11
14
  sections: LoadedSection[];
12
15
  index: SiteIndex;
13
- /** True when nav.json was present but held entries this package version could
14
- * not represent (unknown kinds, invalid shapes) — the returned nav is missing
15
- * them. Writers must treat a degraded nav as read-only: wholesale-replacing
16
- * nav.json from a degraded read permanently destroys the entries this
17
- * version dropped. */
16
+ /** A Degraded read of nav.json (see SidecarRead): the returned nav is missing
17
+ * entries, so writers treat it as read-only — wholesale-replacing nav.json
18
+ * from it permanently destroys the entries this version dropped. */
18
19
  navDegraded: boolean;
19
20
  /** Same contract as navDegraded, for tags.json: a degraded read is
20
21
  * read-only for tags. */
21
22
  tagsDegraded: boolean;
22
23
  }
23
24
  /**
24
- * Whether a load looked for tags.json. Not loaded ⇒ no `index.tags` is attached
25
- * and writers leave the file alone; loaded ⇒ `file` is its parsed contents,
26
- * with null/undefined meaning absent (an empty registry). Unlike nav, the
27
- * difference is load-bearing — an attached `[]` that a writer saves back
28
- * deletes every tag — hence an explicit flag rather than undefined-vs-null.
25
+ * The Sidecars a load read, from the Sidecar module's readers. A Sidecar the
26
+ * load did not look for is omitted. Tags then stay unattached ("not loaded":
27
+ * writers leave tags.json alone, where an attached `[]` saved back would delete
28
+ * every tag). Nav is attached as `[]` either way — the editor has no nav gate
29
+ * yet to make "not loaded" safe for nav (exploration B).
29
30
  */
30
- export type TagsSidecar = {
31
- loaded: false;
32
- } | {
33
- loaded: true;
34
- file: unknown;
31
+ export type SidecarReads = {
32
+ nav?: SidecarRead<NavEntry>;
33
+ tags?: SidecarRead<TagEntry>;
35
34
  };
36
35
  /**
37
36
  * Merge a validated index with raw section file contents.
38
37
  * Validates each section file against its Zod schema.
39
38
  * Returns sections in the concatenated order of every page's order.
40
39
  */
41
- export declare function mergeSiteContent(index: SiteIndex, sectionFiles: Record<string, unknown>, navFile?: unknown, tagsSidecar?: TagsSidecar): SiteContent;
40
+ export declare function mergeSiteContent(index: SiteIndex, sectionFiles: Record<string, unknown>, sidecars?: SidecarReads): SiteContent;
42
41
  /**
43
42
  * Build a SiteContent from a Vite `import.meta.glob` result.
44
43
  * Callers glob the section JSON files at build time, pass the parsed index, and
45
44
  * receive sections merged across every page's order.
46
45
  */
47
- export declare function loadStaticSiteContent(index: SiteIndex, sectionGlob: Record<string, unknown>, navFile?: unknown, tagsSidecar?: TagsSidecar): SiteContent;
46
+ export declare function loadStaticSiteContent(index: SiteIndex, sectionGlob: Record<string, unknown>, sidecars?: SidecarReads): SiteContent;
48
47
  //# sourceMappingURL=loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/lib/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAOvF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB;+DAC2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB;;;;2BAIuB;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB;8BAC0B;IAC1B,YAAY,EAAE,OAAO,CAAC;CACvB;AAyDD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,EAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,OAAO,CAAC,EAAE,OAAO,EACjB,WAAW,GAAE,WAA+B,GAC3C,WAAW,CA4Db;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,EAAE,OAAO,EACjB,WAAW,GAAE,WAA+B,GAC3C,WAAW,CAQb"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/lib/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIvF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB;+DAC2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB;;yEAEqE;IACrE,WAAW,EAAE,OAAO,CAAC;IACrB;8BAC0B;IAC1B,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,GAAG,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAC;AAEzF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,EAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,QAAQ,GAAE,YAAiB,GAC1B,WAAW,CA2Db;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,GAAE,YAAiB,GAC1B,WAAW,CAQb"}
@@ -0,0 +1,73 @@
1
+ import type { MediaItem, MediaManifest } from "../schemas/media";
2
+ import type { DocumentManifest, DocumentManifestEntry } from "../schemas/documents";
3
+ export type MediaBlob = {
4
+ path: string;
5
+ base64: string;
6
+ };
7
+ export type MediaOp =
8
+ /**
9
+ * A new image and its variant files, keyed by its id (the content hash).
10
+ * `alt` is the caller's alt text, if it sent one — the only alt applied when
11
+ * the image turns out to be in the library already (`entry.alt` is just the
12
+ * new entry's default).
13
+ */
14
+ {
15
+ op: "addImage";
16
+ entry: MediaItem;
17
+ blobs: MediaBlob[];
18
+ alt?: string;
19
+ } | {
20
+ op: "setImageAlt";
21
+ imageId: string;
22
+ alt: string;
23
+ } | {
24
+ op: "deleteImage";
25
+ imageId: string;
26
+ }
27
+ /**
28
+ * A document's manifest entry, with its bytes when they ride in the commit
29
+ * (git tier; bucket-tier bytes are uploaded beforehand). For an id already in
30
+ * the library — git-tier ids are the content hash, so the same bytes — only
31
+ * the filename is applied: its stored bytes and path stay. That is how a
32
+ * rename lands.
33
+ */
34
+ | {
35
+ op: "putDocument";
36
+ documentId: string;
37
+ entry: DocumentManifestEntry;
38
+ blob?: MediaBlob;
39
+ };
40
+ /**
41
+ * Per op, in order. `existed` means `addImage` found the image already in the
42
+ * library: its bytes are not committed again, and only a differing alt text is
43
+ * applied.
44
+ */
45
+ export type MediaOpOutcome = "added" | "existed" | "updated" | "deleted";
46
+ export type AppliedMediaOps = {
47
+ ok: true;
48
+ images: MediaManifest;
49
+ /** Null when no op touched documents, so the write leaves that file alone. */
50
+ documents: DocumentManifest | null;
51
+ uploads: {
52
+ item: {
53
+ id: string;
54
+ folder: string;
55
+ };
56
+ blobs: MediaBlob[];
57
+ }[];
58
+ /** Images whose variant folders the write deletes. */
59
+ deletions: {
60
+ id: string;
61
+ folder: string;
62
+ }[];
63
+ outcomes: MediaOpOutcome[];
64
+ };
65
+ export declare function applyMediaOps(manifests: {
66
+ images: MediaManifest;
67
+ documents: DocumentManifest;
68
+ }, ops: MediaOp[]): AppliedMediaOps | {
69
+ ok: false;
70
+ code: "not_found";
71
+ error: string;
72
+ };
73
+ //# sourceMappingURL=media-ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-ops.d.ts","sourceRoot":"","sources":["../../src/lib/media-ops.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AASpF,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,MAAM,OAAO;AACjB;;;;;GAKG;AACD;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACxC;;;;;;GAMG;GACD;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,qBAAqB,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE9F;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEzE,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,aAAa,CAAC;IACtB,8EAA8E;IAC9E,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,OAAO,EAAE;QAAE,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,KAAK,EAAE,SAAS,EAAE,CAAA;KAAE,EAAE,CAAC;IACxE,sDAAsD;IACtD,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B,CAAC;AAEF,wBAAgB,aAAa,CAC3B,SAAS,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,gBAAgB,CAAA;CAAE,EACjE,GAAG,EAAE,OAAO,EAAE,GACb,eAAe,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA2DnE"}
@@ -0,0 +1,60 @@
1
+ import "../chunk-JSBRDJBE.js";
2
+
3
+ // src/lib/media-ops.ts
4
+ function applyMediaOps(manifests, ops) {
5
+ const images = { ...manifests.images, images: { ...manifests.images.images } };
6
+ let documents = null;
7
+ const uploads = [];
8
+ const deletions = [];
9
+ const outcomes = [];
10
+ const keyOf = (imageId) => imageId in images.images ? imageId : Object.keys(images.images).find((key) => images.images[key].id === imageId);
11
+ const notFound = (imageId) => ({ ok: false, code: "not_found", error: `No media with imageId "${imageId}" in the site's media library.` });
12
+ for (const op of ops) {
13
+ switch (op.op) {
14
+ case "addImage": {
15
+ const key = keyOf(op.entry.id);
16
+ if (key === void 0) {
17
+ images.images[op.entry.id] = op.entry;
18
+ uploads.push({ item: { id: op.entry.id, folder: op.entry.folder }, blobs: op.blobs });
19
+ outcomes.push("added");
20
+ } else {
21
+ if (op.alt !== void 0) images.images[key] = { ...images.images[key], alt: op.alt };
22
+ outcomes.push("existed");
23
+ }
24
+ break;
25
+ }
26
+ case "setImageAlt": {
27
+ const key = keyOf(op.imageId);
28
+ if (key === void 0) return notFound(op.imageId);
29
+ images.images[key] = { ...images.images[key], alt: op.alt };
30
+ outcomes.push("updated");
31
+ break;
32
+ }
33
+ case "deleteImage": {
34
+ const key = keyOf(op.imageId);
35
+ if (key === void 0) return notFound(op.imageId);
36
+ deletions.push({ id: key, folder: images.images[key].folder });
37
+ delete images.images[key];
38
+ outcomes.push("deleted");
39
+ break;
40
+ }
41
+ case "putDocument": {
42
+ documents ??= { ...manifests.documents };
43
+ const existing = documents[op.documentId];
44
+ if (existing) {
45
+ documents[op.documentId] = { ...existing, filename: op.entry.filename };
46
+ outcomes.push(existing.filename === op.entry.filename ? "existed" : "updated");
47
+ } else {
48
+ documents[op.documentId] = op.entry;
49
+ if (op.blob) uploads.push({ item: { id: op.documentId, folder: op.blob.path.split("/")[2] ?? "" }, blobs: [op.blob] });
50
+ outcomes.push("added");
51
+ }
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ return { ok: true, images, documents, uploads, deletions, outcomes };
57
+ }
58
+ export {
59
+ applyMediaOps
60
+ };
@@ -1,5 +1,6 @@
1
1
  import type { NavEntry, NavGroupEntry } from "../schemas/nav";
2
2
  import type { Page, SiteIndex } from "../schemas/site-config";
3
+ import { type SidecarDiagnostic } from "./sidecar-diagnostics";
3
4
  /**
4
5
  * Repair an authored nav against the current page set.
5
6
  *
@@ -18,6 +19,11 @@ import type { Page, SiteIndex } from "../schemas/site-config";
18
19
  * prior state and defeat identity-based re-render checks.
19
20
  */
20
21
  export declare function reconcileNav(entries: NavEntry[], pages: Page[]): NavEntry[];
22
+ /** reconcileNav plus what the repair changed — what a validator reports. */
23
+ export declare function reconcileNavReport(entries: NavEntry[], pages: Page[]): {
24
+ entries: NavEntry[];
25
+ diagnostics: SidecarDiagnostic[];
26
+ };
21
27
  /**
22
28
  * The ONLY sanctioned way to read the nav. Always reconciles, so callers never
23
29
  * have to reason about whether index.nav is present, stale, or authored by an
@@ -1 +1 @@
1
- {"version":3,"file":"nav-tree.d.ts","sourceRoot":"","sources":["../../src/lib/nav-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,CAwD3E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,EAAE,CAEvD;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE,CAexD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAKlF;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAIxC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAMrB,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAKrE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAIvF;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,SAAS,CAI5G;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAUxE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,GAAG,SAAS,CAgC5F;AAqBD,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAkD5G"}
1
+ {"version":3,"file":"nav-tree.d.ts","sourceRoot":"","sources":["../../src/lib/nav-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAErF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,CAE3E;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,QAAQ,EAAE,EACnB,KAAK,EAAE,IAAI,EAAE,GACZ;IAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAAC,WAAW,EAAE,iBAAiB,EAAE,CAAA;CAAE,CA4E3D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,EAAE,CAEvD;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE,CAexD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAKlF;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAIxC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAMrB,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAKrE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAIvF;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,SAAS,CAI5G;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAUxE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,GAAG,SAAS,CAgC5F;AAqBD,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAkD5G"}
@@ -1,12 +1,13 @@
1
1
  import type { Page, SiteIndex, SectionMeta } from "../schemas/site-config";
2
2
  import { type DocumentOptions } from "../document/engine/settings";
3
+ import { slugifyPageSlug } from "./slug";
3
4
  /**
4
5
  * Display fallback for blank page titles. addPage creates pages with an empty
5
6
  * title (the editor prompts for one), and closing the modal can leave it blank
6
7
  * — every UI that renders a page title must go through this.
7
8
  */
8
9
  export declare function pageDisplayTitle(title: string): string;
9
- export declare function slugifyPageSlug(input: string): string;
10
+ export { slugifyPageSlug };
10
11
  export declare function uniquePageSlug(base: string, existing: string[]): string;
11
12
  export declare function pageById(index: SiteIndex, id: string): Page | undefined;
12
13
  export declare function homePage(index: SiteIndex): Page;
@@ -1 +1 @@
1
- {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/lib/pages.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/lib/pages.ts"],"names":[],"mappings":"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"}
@@ -1,38 +1,9 @@
1
1
  import {
2
- REFERENCE_TYPE
3
- } from "../chunk-5GFACGSN.js";
2
+ describeReferenceProblem,
3
+ referenceProblems
4
+ } from "../chunk-FGQXHUAE.js";
5
+ import "../chunk-5GFACGSN.js";
4
6
  import "../chunk-JSBRDJBE.js";
5
-
6
- // src/lib/reference-validation.ts
7
- var strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
8
- function referenceProblems(sections, index, tagIds) {
9
- const onPage = new Set(index.pages.flatMap((p) => p.order));
10
- const problems = [];
11
- for (const { id, content } of sections) {
12
- const body = content;
13
- if (body?.type !== REFERENCE_TYPE && index.sections[id]?.type !== REFERENCE_TYPE) continue;
14
- const picks = strings(body?.content?.sectionIds).filter((pick) => pick !== id);
15
- const problem = {
16
- referenceId: id,
17
- unknownTagIds: tagIds ? strings(body?.content?.tagIds).filter((tag) => !tagIds.has(tag)) : [],
18
- unplacedSectionIds: picks.filter((pick) => !onPage.has(pick)),
19
- referencePickIds: picks.filter((pick) => onPage.has(pick) && index.sections[pick]?.type === REFERENCE_TYPE),
20
- picksItself: strings(body?.content?.sectionIds).includes(id)
21
- };
22
- if (problem.unknownTagIds.length || problem.unplacedSectionIds.length || problem.referencePickIds.length || problem.picksItself) problems.push(problem);
23
- }
24
- return problems;
25
- }
26
- function describeReferenceProblem(problem) {
27
- const list = (ids) => ids.map((id) => `"${id}"`).join(", ");
28
- const issues = [
29
- ...problem.unknownTagIds.length ? [`tagIds ${list(problem.unknownTagIds)} are not tags on this site`] : [],
30
- ...problem.unplacedSectionIds.length ? [`sectionIds ${list(problem.unplacedSectionIds)} are not top-level sections on any page (a container's child cannot be picked \u2014 pick the container)`] : [],
31
- ...problem.referencePickIds.length ? [`sectionIds ${list(problem.referencePickIds)} are References, which a Reference never shows`] : [],
32
- ...problem.picksItself ? ["sectionIds includes the Reference itself"] : []
33
- ];
34
- return `Reference "${problem.referenceId}": ${issues.join("; ")}.`;
35
- }
36
7
  export {
37
8
  describeReferenceProblem,
38
9
  referenceProblems
@@ -0,0 +1,49 @@
1
+ import type { ZodError } from "zod";
2
+ /**
3
+ * The first thing wrong with one section body: schema, then layout envelope,
4
+ * then nesting depth, then a Reference nested in a container. Only ever one — a
5
+ * body failing its schema is not also judged on its layout — so the write
6
+ * path's `errors[0]` stays the first failure it has always reported.
7
+ */
8
+ export type SectionCheckError = {
9
+ code: "schema";
10
+ zodError: ZodError;
11
+ } | {
12
+ code: "layout";
13
+ zodError: ZodError;
14
+ } | {
15
+ code: "depth";
16
+ } | {
17
+ code: "reference-in-container";
18
+ };
19
+ /** HTML entities found in one plain-text field, by path relative to the section. */
20
+ export interface EntityFinding {
21
+ path: string;
22
+ entities: string[];
23
+ }
24
+ export interface SectionCheck {
25
+ /**
26
+ * No schema is registered for the type, so only the nesting bound was
27
+ * checked. Whether that is acceptable (a site-local type) or an unknown type
28
+ * is the caller's call.
29
+ */
30
+ unregistered: boolean;
31
+ error: SectionCheckError | null;
32
+ /** Empty whenever `error` is set. */
33
+ entities: EntityFinding[];
34
+ }
35
+ /**
36
+ * Judge one section body against `type`'s registered schema — the write path's
37
+ * (`validateContent`) per-section rules, kept here so the site validators can
38
+ * apply the same ones.
39
+ * Reads the schema registry only: callers register the schemas first.
40
+ */
41
+ export declare function checkSection(type: string, body: unknown): SectionCheck;
42
+ /**
43
+ * The write path's sentence for a section check's error, shared with
44
+ * validate_site so a dry run words a failure exactly as the save it predicts.
45
+ */
46
+ export declare function sectionCheckMessage(sectionId: string, type: string, code: SectionCheckError["code"]): string;
47
+ /** The write path's warning for one entity finding, shared with validate_site. */
48
+ export declare function entityWarning(sectionId: string, { path, entities }: EntityFinding): string;
49
+ //# sourceMappingURL=section-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-check.d.ts","sourceRoot":"","sources":["../../src/lib/section-check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAKpC;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,wBAAwB,CAAA;CAAE,CAAC;AAEvC,oFAAoF;AACpF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAChC,qCAAqC;IACrC,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,YAAY,CAgCtE;AAsED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,MAAM,CAW5G;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,aAAa,GAAG,MAAM,CAG1F"}
@@ -0,0 +1,14 @@
1
+ import {
2
+ checkSection,
3
+ entityWarning,
4
+ sectionCheckMessage
5
+ } from "../chunk-26V4YNOR.js";
6
+ import "../chunk-5GFACGSN.js";
7
+ import "../chunk-FTPETWXE.js";
8
+ import "../chunk-NSCT3AMV.js";
9
+ import "../chunk-JSBRDJBE.js";
10
+ export {
11
+ checkSection,
12
+ entityWarning,
13
+ sectionCheckMessage
14
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * What a Sidecar reconcile changed. Reconcile repairs silently on every read, so
3
+ * these are only ever warnings: a validator reports them, nothing rejects on them.
4
+ * - dangling: ids of pages/sections the index does not have, dropped
5
+ * - duplicate-id: a group/tag id used again, later uses dropped
6
+ * - duplicate-member: a page placed twice / a section tagged twice, later placements dropped
7
+ * - unlisted: pages missing from the nav, appended to its end (nav only)
8
+ *
9
+ * Its own leaf so nav-tree and tags can report without importing the Sidecar
10
+ * module that imports them.
11
+ */
12
+ export type SidecarDiagnostic = {
13
+ code: "dangling" | "duplicate-id" | "duplicate-member" | "unlisted";
14
+ ids: string[];
15
+ };
16
+ export declare function diagnosticsCollector(): {
17
+ add(code: SidecarDiagnostic["code"], id: string): void;
18
+ list(): SidecarDiagnostic[];
19
+ };
20
+ //# sourceMappingURL=sidecar-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecar-diagnostics.d.ts","sourceRoot":"","sources":["../../src/lib/sidecar-diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,UAAU,GAAG,cAAc,GAAG,kBAAkB,GAAG,UAAU,CAAC;IACpE,GAAG,EAAE,MAAM,EAAE,CAAC;CACf,CAAC;AAEF,wBAAgB,oBAAoB;cAGtB,iBAAiB,CAAC,MAAM,CAAC,MAAM,MAAM;YAKvC,iBAAiB,EAAE;EAI9B"}
@@ -0,0 +1,118 @@
1
+ import type { ZodType } from "zod";
2
+ import { type NavEntry } from "../schemas/nav";
3
+ import { type TagEntry } from "../schemas/tags";
4
+ import type { SiteIndex } from "../schemas/site-config";
5
+ import type { SidecarDiagnostic } from "./sidecar-diagnostics";
6
+ export type { SidecarDiagnostic };
7
+ /**
8
+ * One definition per Sidecar — a content file kept beside index.json rather than
9
+ * on it, so a writer that predates it cannot drop it (CONTEXT.md). Every rule a
10
+ * caller would otherwise re-implement per file lives behind these: lenient
11
+ * parse, lifting the wire key off an index before IndexSchema strips it, and the
12
+ * two places the Sidecars genuinely differ — how a list is repaired against the
13
+ * index, and how concurrent edits rebase. Pure and browser-safe: the editor uses
14
+ * it during hydration, and callers do their own I/O.
15
+ */
16
+ export interface SidecarDefinition<E> {
17
+ /** Also the key the Sidecar travels under on the wire (`index.nav`, `index.tags`). */
18
+ name: "nav" | "tags";
19
+ path: string;
20
+ /** The key holding the entry list inside the file. */
21
+ fileKey: "entries" | "tags";
22
+ entrySchema: ZodType<E>;
23
+ fileSchema: ZodType<unknown>;
24
+ /** Total, pure and idempotent; also reports what it repaired. */
25
+ reconcile(entries: E[], index: SiteIndex): {
26
+ entries: E[];
27
+ diagnostics: SidecarDiagnostic[];
28
+ };
29
+ /** The list after a collab rebase; `undefined` when no side carries one. */
30
+ rebase(args: {
31
+ base: E[] | undefined;
32
+ local: E[] | undefined;
33
+ remote: E[] | undefined;
34
+ }): E[] | undefined;
35
+ /** Words for a declined write's warning. */
36
+ words: {
37
+ /** What the file holds: "navigation entries". */
38
+ entries: string;
39
+ /** What did not land: "Page grouping changes". */
40
+ changes: string;
41
+ /** What a valid payload is: "a valid navigation tree". */
42
+ valid: string;
43
+ /** The expected wire shape, for an agent that sent the wrong one. */
44
+ shape: string;
45
+ };
46
+ }
47
+ export declare const NAV: SidecarDefinition<NavEntry>;
48
+ export declare const TAGS: SidecarDefinition<TagEntry>;
49
+ export declare const SIDECARS: readonly SidecarDefinition<unknown>[];
50
+ /**
51
+ * A Sidecar as read. `degraded` means the file was present but held something
52
+ * this package version could not represent, so `entries` is missing it: the read
53
+ * is a Degraded read, never to be cached, posted back, or written over the file.
54
+ */
55
+ export type SidecarRead<E> = {
56
+ entries: E[];
57
+ degraded: boolean;
58
+ };
59
+ /** Read a parsed Sidecar file. Absent (null/undefined) is an empty list, not degraded. */
60
+ export declare function readSidecar<E>(def: SidecarDefinition<E>, file: unknown): SidecarRead<E>;
61
+ /**
62
+ * Read a Sidecar file's raw text. Present-but-unparseable JSON is degraded, not
63
+ * absent: a site whose nav.json is corrupt still has groups, and treating it as
64
+ * "never had any" would let a writer replace them.
65
+ */
66
+ export declare function readSidecarText<E>(def: SidecarDefinition<E>, text: string | undefined): SidecarRead<E>;
67
+ /**
68
+ * Lift the Sidecars off an index as it arrives on the wire, BEFORE anything
69
+ * parses it with IndexSchema — the parse strips unknown keys, and an index
70
+ * round-tripped through it has lost its Sidecars. A key the index does not carry
71
+ * is `undefined` (omitted: writers leave the file alone); a carried key is read
72
+ * with the file's per-entry leniency, into fresh objects that never alias the
73
+ * caller's.
74
+ */
75
+ export declare function liftSidecars(rawIndex: unknown): {
76
+ nav?: SidecarRead<NavEntry>;
77
+ tags?: SidecarRead<TagEntry>;
78
+ };
79
+ /** The Sidecar file on the branch a write lands on, as the writer read it. */
80
+ export type SidecarFileState = {
81
+ kind: "absent";
82
+ } | {
83
+ kind: "present";
84
+ text: string;
85
+ }
86
+ /** The read itself failed, so nothing is known about the file. */
87
+ | {
88
+ kind: "unreadable";
89
+ };
90
+ export type SidecarWritePlan = {
91
+ action: "untouched";
92
+ } | {
93
+ action: "write";
94
+ path: string;
95
+ content: string;
96
+ }
97
+ /** Declined. The rest of the write still lands, so the warning is what tells the caller. */
98
+ | {
99
+ action: "skip";
100
+ warning: string;
101
+ };
102
+ /**
103
+ * What a write does to one Sidecar file, given what was posted (from
104
+ * liftSidecars) and the file on the branch. Every Sidecar write REPLACES the
105
+ * file, and the posted list was built from what this package version could
106
+ * READ — so a file holding anything this version cannot fully parse (an entry
107
+ * from a newer package, or a corrupt file) is read-only: replacing it would
108
+ * destroy those entries with a clean write. The same holds for a posted
109
+ * Degraded read.
110
+ *
111
+ * Emptiness is judged on the POSTED list, before reconcile: an empty list never
112
+ * creates a file (every editor save carries the Sidecars, and nav's reconcile
113
+ * would turn [] into the page list), while an empty list over an existing file
114
+ * replaces it wholesale. A written list is reconciled against the index being
115
+ * written, so it never names a page or section that write removed.
116
+ */
117
+ export declare function planSidecarWrite<E>(def: SidecarDefinition<E>, posted: SidecarRead<E> | undefined, branch: SidecarFileState, index: SiteIndex): SidecarWritePlan;
118
+ //# sourceMappingURL=sidecars.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecars.d.ts","sourceRoot":"","sources":["../../src/lib/sidecars.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import {
2
+ NAV,
3
+ SIDECARS,
4
+ TAGS,
5
+ liftSidecars,
6
+ planSidecarWrite,
7
+ readSidecar,
8
+ readSidecarText
9
+ } from "../chunk-DJABADOO.js";
10
+ import "../chunk-DJOGPSRU.js";
11
+ import "../chunk-4WQ36ZP7.js";
12
+ import "../chunk-GNF6KFQ7.js";
13
+ import "../chunk-4Y2JQQZL.js";
14
+ import "../chunk-JSBRDJBE.js";
15
+ export {
16
+ NAV,
17
+ SIDECARS,
18
+ TAGS,
19
+ liftSidecars,
20
+ planSidecarWrite,
21
+ readSidecar,
22
+ readSidecarText
23
+ };