@bitcobblers/wod-wiki-engine 0.37.2139 → 0.38.2141

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/index.cjs CHANGED
@@ -617,16 +617,34 @@ function csvToSessionRows(csv) {
617
617
  }
618
618
 
619
619
  // src/version.ts
620
- var VERSION = "0.37.2139";
621
- var GIT_SHA = "491ec71";
622
- var BUILD_TIME = "2026-10-17T15:36:01.834Z";
620
+ var VERSION = "0.38.2141";
621
+ var GIT_SHA = "b9b40a7";
622
+ var BUILD_TIME = "2026-10-19T12:09:48.802Z";
623
623
  var SEMVER = {
624
- version: "0.37.2139",
625
- gitSha: "491ec71",
626
- buildTime: "2026-10-17T15:36:01.834Z"
624
+ version: "0.38.2141",
625
+ gitSha: "b9b40a7",
626
+ buildTime: "2026-10-19T12:09:48.802Z"
627
627
  };
628
628
  var SEED_SCHEMA = 9;
629
629
  var SEED_REGISTERED_WIDGETS = wodWikiCore.KNOWN_SECTION_WIDGETS;
630
+ var SEED_PRECEDENCE_RANK = {
631
+ core: 0,
632
+ community: 1,
633
+ imported: 2,
634
+ user: 3
635
+ };
636
+ function seedSourceTier(sourceIdOrMetaKey, explicitTier) {
637
+ if (explicitTier) return explicitTier;
638
+ if (!sourceIdOrMetaKey) return "core";
639
+ if (sourceIdOrMetaKey === "user") return "user";
640
+ const id = sourceIdOrMetaKey.startsWith("seed:") ? sourceIdOrMetaKey.slice(5) : sourceIdOrMetaKey;
641
+ if (id === "core" || id === "efforts" || id === "equipment") return "core";
642
+ if (id === "community" || id.startsWith("community-") || id === "common") return "community";
643
+ return "imported";
644
+ }
645
+ function seedPrecedenceRank(sourceIdOrMetaKey, explicitTier) {
646
+ return SEED_PRECEDENCE_RANK[seedSourceTier(sourceIdOrMetaKey, explicitTier)];
647
+ }
630
648
  var SEED_BROADCAST_CHANNEL = "wodwiki.seed";
631
649
  var EFFORTS_CHUNK_ID = "efforts";
632
650
  var EQUIPMENT_CHUNK_ID = "equipment";
@@ -768,36 +786,79 @@ function refreshedBlocks(existing, rawContent, sourceRevision) {
768
786
  let ordinal = 0;
769
787
  return wodWikiCore.reconcileNoteBlocks(rawContent, { sourceRevision, blocks: mapped, registeredWidgets: SEED_REGISTERED_WIDGETS, createId: () => `seed:${existing.id}:r${sourceRevision}:${ordinal++}` });
770
788
  }
771
- async function applyDefinitionChunk(defStore, parse, family, rows, ids, owned, existingById, allIds) {
789
+ async function applyDefinitionChunk(defStore, noteStore, parse, family, seedSource, incomingRank, otherCheckpoints, priorIds, rows, ids, owned, existingById, allIds) {
790
+ const priorIdSet = new Set(priorIds);
791
+ const maxOtherRankForNote = (noteId) => {
792
+ let max = -1;
793
+ for (const cp of otherCheckpoints) {
794
+ if (cp.noteIds.has(noteId) && cp.rank > max) max = cp.rank;
795
+ }
796
+ return max;
797
+ };
772
798
  const projections = [];
773
799
  for (const [i, row] of rows.entries()) {
774
800
  if (!owned.has(ids[i])) continue;
775
801
  const parsed = parse(row.content);
776
802
  if (!parsed) continue;
777
- projections.push({ ...parsed, registrySource: "bundled", ownerNoteId: ids[i], sourceId: family, sourcePath: row.path });
803
+ projections.push({ ...parsed, registrySource: "bundled", ownerNoteId: ids[i], sourceId: seedSource, sourcePath: row.path });
778
804
  }
779
805
  const prior = await defStore.getMany(projections.map((p) => p.slug));
780
- for (const [i, p] of projections.entries()) {
806
+ const changed = projections.filter((p, i) => {
781
807
  const before = prior[i];
782
- if (before?.registrySource === "bundled" && before.ownerNoteId && before.ownerNoteId !== p.ownerNoteId) {
783
- throw new Error(`Seed definition collision: '${p.slug}' is already owned by another seed source (note ${before.ownerNoteId})`);
808
+ if (!before) return true;
809
+ if (before.registrySource !== "bundled") return false;
810
+ let beforeRank;
811
+ if (before.ownerNoteId === p.ownerNoteId || before.ownerNoteId && priorIdSet.has(before.ownerNoteId) && maxOtherRankForNote(before.ownerNoteId) < incomingRank) {
812
+ beforeRank = incomingRank;
813
+ } else {
814
+ const cpRank = before.ownerNoteId ? maxOtherRankForNote(before.ownerNoteId) : -1;
815
+ beforeRank = cpRank >= 0 ? cpRank : seedPrecedenceRank(before.sourceId);
784
816
  }
785
- }
786
- const changed = projections.filter((p, i) => (!prior[i] || prior[i]?.registrySource === "bundled") && !equal(p, prior[i]));
817
+ return incomingRank >= beforeRank && !equal(p, before);
818
+ });
787
819
  if (changed.length) await defStore.putMany(changed);
788
820
  const wantedSlugs = new Set(projections.map((p) => p.slug));
789
821
  const removedBySlug = /* @__PURE__ */ new Map();
790
822
  for (const id of allIds) {
791
- if (!owned.has(id)) continue;
792
823
  const note = existingById.get(id);
793
- const slug = note ? parse(note.rawContent)?.slug : void 0;
824
+ if (!note || note.seedOrigin !== "seed") continue;
825
+ const slug = parse(note.rawContent)?.slug;
794
826
  if (slug && !wantedSlugs.has(slug)) removedBySlug.set(slug, id);
795
827
  }
796
828
  const removedSlugs = [...removedBySlug.keys()];
797
- const old = await defStore.getMany(removedSlugs);
798
- for (const [i, row] of old.entries()) {
799
- if (row?.registrySource === "bundled" && removedBySlug.get(removedSlugs[i]) === row.ownerNoteId) {
800
- await defStore.delete(removedSlugs[i]);
829
+ if (removedSlugs.length) {
830
+ const old = await defStore.getMany(removedSlugs);
831
+ for (const [i, row] of old.entries()) {
832
+ const slug = removedSlugs[i];
833
+ if (!row || row.registrySource !== "bundled") continue;
834
+ const removedNoteId = removedBySlug.get(slug);
835
+ const isOwnedByThisSource = row.ownerNoteId === removedNoteId && (!row.sourceId || row.sourceId === seedSource || row.sourceId === family);
836
+ if (!isOwnedByThisSource) continue;
837
+ let restored = false;
838
+ for (const cp of otherCheckpoints) {
839
+ const candidateIds = cp.meta.chunks?.[family]?.noteIds ?? [];
840
+ if (!candidateIds.length) continue;
841
+ const candidateNotes = await noteStore.getMany(candidateIds);
842
+ for (const candidateNote of candidateNotes) {
843
+ if (!candidateNote || candidateNote.seedOrigin !== "seed") continue;
844
+ const parsed = parse(candidateNote.rawContent);
845
+ if (parsed && parsed.slug === slug) {
846
+ await defStore.put({
847
+ ...parsed,
848
+ registrySource: "bundled",
849
+ ownerNoteId: candidateNote.id,
850
+ sourceId: cp.sourceId,
851
+ sourcePath: candidateNote.sourcePath ?? ""
852
+ });
853
+ restored = true;
854
+ break;
855
+ }
856
+ }
857
+ if (restored) break;
858
+ }
859
+ if (!restored) {
860
+ await defStore.delete(slug);
861
+ }
801
862
  }
802
863
  }
803
864
  return changed.length;
@@ -838,30 +899,41 @@ async function applySeedChunk(storage, write) {
838
899
  const allIds = [.../* @__PURE__ */ new Set([...ids, ...goneIds])];
839
900
  const stored = await noteStore.getMany(allIds);
840
901
  const existingById = new Map(allIds.map((id, i) => [id, stored[i]]));
902
+ const seedSource = write.meta.key.startsWith("seed:") ? write.meta.key.slice(5) : write.meta.key;
903
+ const incomingRank = seedPrecedenceRank(write.meta.key, write.meta.tier);
904
+ const otherCheckpoints = [];
905
+ for (const row of await metaStore.getAll()) {
906
+ const meta = row;
907
+ if (!meta || typeof meta.key !== "string" || !meta.key.startsWith("seed:") || meta.key === write.meta.key) continue;
908
+ const noteIds = /* @__PURE__ */ new Set();
909
+ for (const chunk of Object.values(meta.chunks ?? {})) {
910
+ for (const noteId of chunk.noteIds ?? []) noteIds.add(noteId);
911
+ }
912
+ otherCheckpoints.push({
913
+ key: meta.key,
914
+ sourceId: meta.key.slice(5),
915
+ rank: seedPrecedenceRank(meta.key, meta.tier),
916
+ meta,
917
+ noteIds
918
+ });
919
+ }
920
+ otherCheckpoints.sort((a, b) => b.rank - a.rank);
921
+ const maxOtherRankForNote = (noteId) => {
922
+ let max = -1;
923
+ for (const cp of otherCheckpoints) {
924
+ if (cp.noteIds.has(noteId) && cp.rank > max) max = cp.rank;
925
+ }
926
+ return max;
927
+ };
841
928
  const ownedIds = allIds.filter((id) => {
842
929
  const note = existingById.get(id);
843
- return !note || note.seedOrigin === "seed" && (declared.has(id) || note.seedChunkId === write.chunkId);
930
+ if (!note) return declared.has(id);
931
+ if (note.seedOrigin !== "seed") return false;
932
+ const otherRank = maxOtherRankForNote(id);
933
+ if (declared.has(id)) return incomingRank >= otherRank;
934
+ return otherRank < 0 && note.seedChunkId === write.chunkId;
844
935
  });
845
936
  const owned = new Set(ownedIds);
846
- {
847
- let checkpoints;
848
- for (const [i, id] of ids.entries()) {
849
- const existing = existingById.get(id);
850
- if (!existing || existing.seedOrigin !== "seed") continue;
851
- if (checkpoints === void 0) {
852
- checkpoints = [];
853
- for (const row of await metaStore.getAll()) {
854
- const meta = row;
855
- if (!meta || typeof meta.key !== "string" || !meta.key.startsWith("seed:") || meta.key === write.meta.key) continue;
856
- const noteIds = /* @__PURE__ */ new Set();
857
- for (const chunk of Object.values(meta.chunks ?? {})) for (const noteId of chunk.noteIds ?? []) noteIds.add(noteId);
858
- checkpoints.push({ key: meta.key, noteIds });
859
- }
860
- }
861
- const owner = checkpoints.find((checkpoint) => checkpoint.noteIds.has(id));
862
- if (owner) throw new Error(`Seed note collision: '${write.rows[i].path}' is already owned by ${owner.key}`);
863
- }
864
- }
865
937
  const revisionStore = tx.readwrite("block_revisions");
866
938
  const historyIds = ids.filter((id, i) => owned.has(id) && existingById.get(id)?.rawContent !== write.rows[i].content);
867
939
  const histories = await revisionStore.getAllFromIndexMany("by-note", historyIds);
@@ -883,7 +955,7 @@ async function applySeedChunk(storage, write) {
883
955
  for (const [i, row] of write.rows.entries()) {
884
956
  const id = ids[i], existing = existingById.get(id);
885
957
  if (!owned.has(id)) {
886
- result.skippedUserOwned++;
958
+ if (existing && existing.seedOrigin !== "seed") result.skippedUserOwned++;
887
959
  continue;
888
960
  }
889
961
  if (!existing) result.addedNotes++;
@@ -983,10 +1055,10 @@ async function applySeedChunk(storage, write) {
983
1055
  result.deleted++;
984
1056
  }
985
1057
  if (write.chunkId === EFFORTS_CHUNK_ID) {
986
- result.totalEfforts = await applyDefinitionChunk(tx.readwrite("efforts"), wodWikiLang.parseEffortFile, "efforts", write.rows, ids, owned, existingById, allIds);
1058
+ result.totalEfforts = await applyDefinitionChunk(tx.readwrite("efforts"), noteStore, wodWikiLang.parseEffortFile, "efforts", seedSource, incomingRank, otherCheckpoints, priorIds, write.rows, ids, owned, existingById, allIds);
987
1059
  }
988
1060
  if (write.chunkId === EQUIPMENT_CHUNK_ID) {
989
- result.totalEquipment = await applyDefinitionChunk(tx.readwrite("equipment"), wodWikiLang.parseEquipmentFile, "equipment", write.rows, ids, owned, existingById, allIds);
1061
+ result.totalEquipment = await applyDefinitionChunk(tx.readwrite("equipment"), noteStore, wodWikiLang.parseEquipmentFile, "equipment", seedSource, incomingRank, otherCheckpoints, priorIds, write.rows, ids, owned, existingById, allIds);
990
1062
  }
991
1063
  if (changedNotes.length) await noteStore.putMany(changedNotes);
992
1064
  if (revisions.length) await revisionStore.putMany(revisions);
@@ -1042,6 +1114,10 @@ Object.defineProperty(exports, "ButtonBehavior", {
1042
1114
  enumerable: true,
1043
1115
  get: function () { return wodWikiLang.ButtonBehavior; }
1044
1116
  });
1117
+ Object.defineProperty(exports, "CATALOG_PRECEDENCE_RANK", {
1118
+ enumerable: true,
1119
+ get: function () { return wodWikiLang.CATALOG_PRECEDENCE_RANK; }
1120
+ });
1045
1121
  Object.defineProperty(exports, "CONSUMED_HINTS", {
1046
1122
  enumerable: true,
1047
1123
  get: function () { return wodWikiLang.CONSUMED_HINTS; }
@@ -1442,6 +1518,10 @@ Object.defineProperty(exports, "createParser", {
1442
1518
  enumerable: true,
1443
1519
  get: function () { return wodWikiLang.createParser; }
1444
1520
  });
1521
+ Object.defineProperty(exports, "dedupeEntitiesByPrecedence", {
1522
+ enumerable: true,
1523
+ get: function () { return wodWikiLang.dedupeEntitiesByPrecedence; }
1524
+ });
1445
1525
  Object.defineProperty(exports, "dialectRegistry", {
1446
1526
  enumerable: true,
1447
1527
  get: function () { return wodWikiLang.dialectRegistry; }
@@ -1574,6 +1654,22 @@ Object.defineProperty(exports, "renderMetric", {
1574
1654
  enumerable: true,
1575
1655
  get: function () { return wodWikiLang.renderMetric; }
1576
1656
  });
1657
+ Object.defineProperty(exports, "resolveEntityRank", {
1658
+ enumerable: true,
1659
+ get: function () { return wodWikiLang.resolveEntityRank; }
1660
+ });
1661
+ Object.defineProperty(exports, "resolveEntityTier", {
1662
+ enumerable: true,
1663
+ get: function () { return wodWikiLang.resolveEntityTier; }
1664
+ });
1665
+ Object.defineProperty(exports, "resolveSourceRank", {
1666
+ enumerable: true,
1667
+ get: function () { return wodWikiLang.resolveSourceRank; }
1668
+ });
1669
+ Object.defineProperty(exports, "resolveSourceTier", {
1670
+ enumerable: true,
1671
+ get: function () { return wodWikiLang.resolveSourceTier; }
1672
+ });
1577
1673
  Object.defineProperty(exports, "strategyRegistry", {
1578
1674
  enumerable: true,
1579
1675
  get: function () { return wodWikiLang.strategyRegistry; }
@@ -1702,6 +1798,10 @@ Object.defineProperty(exports, "DEFAULT_DASHBOARD_TITLE", {
1702
1798
  enumerable: true,
1703
1799
  get: function () { return wodWikiWql.DEFAULT_DASHBOARD_TITLE; }
1704
1800
  });
1801
+ Object.defineProperty(exports, "DEFAULT_NOTEBOOK_SLUGS", {
1802
+ enumerable: true,
1803
+ get: function () { return wodWikiWql.DEFAULT_NOTEBOOK_SLUGS; }
1804
+ });
1705
1805
  Object.defineProperty(exports, "PLANNED_WIDGET_TYPES", {
1706
1806
  enumerable: true,
1707
1807
  get: function () { return wodWikiWql.PLANNED_WIDGET_TYPES; }
@@ -1830,6 +1930,10 @@ Object.defineProperty(exports, "isFindQuery", {
1830
1930
  enumerable: true,
1831
1931
  get: function () { return wodWikiWql.isFindQuery; }
1832
1932
  });
1933
+ Object.defineProperty(exports, "isNoteEditable", {
1934
+ enumerable: true,
1935
+ get: function () { return wodWikiWql.isNoteEditable; }
1936
+ });
1833
1937
  Object.defineProperty(exports, "isPipelineQuery", {
1834
1938
  enumerable: true,
1835
1939
  get: function () { return wodWikiWql.isPipelineQuery; }
@@ -1838,6 +1942,14 @@ Object.defineProperty(exports, "normalizeWql", {
1838
1942
  enumerable: true,
1839
1943
  get: function () { return wodWikiWql.normalizeWql; }
1840
1944
  });
1945
+ Object.defineProperty(exports, "notebookOfItem", {
1946
+ enumerable: true,
1947
+ get: function () { return wodWikiWql.notebookOfItem; }
1948
+ });
1949
+ Object.defineProperty(exports, "notebookSlugFromId", {
1950
+ enumerable: true,
1951
+ get: function () { return wodWikiWql.notebookSlugFromId; }
1952
+ });
1841
1953
  Object.defineProperty(exports, "parseQuery", {
1842
1954
  enumerable: true,
1843
1955
  get: function () { return wodWikiWql.parseQuery; }
@@ -1866,6 +1978,10 @@ Object.defineProperty(exports, "substituteTokens", {
1866
1978
  enumerable: true,
1867
1979
  get: function () { return wodWikiWql.substituteTokens; }
1868
1980
  });
1981
+ Object.defineProperty(exports, "toNotebookId", {
1982
+ enumerable: true,
1983
+ get: function () { return wodWikiWql.toNotebookId; }
1984
+ });
1869
1985
  Object.defineProperty(exports, "unknownTokensMessage", {
1870
1986
  enumerable: true,
1871
1987
  get: function () { return wodWikiWql.unknownTokensMessage; }
@@ -1898,6 +2014,7 @@ exports.EQUIPMENT_CHUNK_ID = EQUIPMENT_CHUNK_ID;
1898
2014
  exports.GIT_SHA = GIT_SHA;
1899
2015
  exports.NOTE_ID_FRONTMATTER_KEY = NOTE_ID_FRONTMATTER_KEY;
1900
2016
  exports.SEED_BROADCAST_CHANNEL = SEED_BROADCAST_CHANNEL;
2017
+ exports.SEED_PRECEDENCE_RANK = SEED_PRECEDENCE_RANK;
1901
2018
  exports.SEED_REGISTERED_WIDGETS = SEED_REGISTERED_WIDGETS;
1902
2019
  exports.SEED_SCHEMA = SEED_SCHEMA;
1903
2020
  exports.SEMVER = SEMVER;
@@ -1932,6 +2049,8 @@ exports.registerLanguagePack = registerLanguagePack;
1932
2049
  exports.seedMetaKey = seedMetaKey;
1933
2050
  exports.seedNoteId = seedNoteId;
1934
2051
  exports.seedNoteSourceId = seedNoteSourceId;
2052
+ exports.seedPrecedenceRank = seedPrecedenceRank;
2053
+ exports.seedSourceTier = seedSourceTier;
1935
2054
  exports.sessionToCsv = sessionToCsv;
1936
2055
  exports.splitCsvRecords = splitCsvRecords;
1937
2056
  exports.statementToNode = statementToNode;