@lucern/graph-primitives 0.3.0-alpha.0 → 0.3.0-alpha.10

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 (141) hide show
  1. package/dist/{beliefDecay-Q_26RTc-.d.ts → beliefDecay-DZ6tkLYq.d.ts} +1 -1
  2. package/dist/beliefDecay.d.ts +1 -1
  3. package/dist/beliefDecay.js +188 -1144
  4. package/dist/beliefDecay.js.map +1 -1
  5. package/dist/{beliefEvidenceLinks-42FlR48t.d.ts → beliefEvidenceLinks-CWOXxxJg.d.ts} +1 -1
  6. package/dist/beliefEvidenceLinks.d.ts +1 -1
  7. package/dist/beliefEvidenceLinks.js +186 -871
  8. package/dist/beliefEvidenceLinks.js.map +1 -1
  9. package/dist/{beliefLifecycle-C-AehZgF.d.ts → beliefLifecycle-y8WLXqQj.d.ts} +1 -1
  10. package/dist/beliefLifecycle.d.ts +1 -1
  11. package/dist/confidencePropagationDispatch.d.ts +4 -4
  12. package/dist/confidencePropagationDispatch.js +31 -311
  13. package/dist/confidencePropagationDispatch.js.map +1 -1
  14. package/dist/{contradictions-Hdwl7zid.d.ts → contradictions-51VLsESq.d.ts} +1 -1
  15. package/dist/contradictions.d.ts +1 -1
  16. package/dist/contradictions.js +67 -800
  17. package/dist/contradictions.js.map +1 -1
  18. package/dist/debug.d.ts +4 -0
  19. package/dist/debug.js +34 -0
  20. package/dist/debug.js.map +1 -0
  21. package/dist/edges/contradicts.js +1 -122
  22. package/dist/edges/contradicts.js.map +1 -1
  23. package/dist/edges/dependsOn.js +14 -172
  24. package/dist/edges/dependsOn.js.map +1 -1
  25. package/dist/edges/elaborates.js +1 -49
  26. package/dist/edges/elaborates.js.map +1 -1
  27. package/dist/edges/index.js +15 -280
  28. package/dist/edges/index.js.map +1 -1
  29. package/dist/edges/informs.js +2 -65
  30. package/dist/edges/informs.js.map +1 -1
  31. package/dist/edges/propagationTypes.d.ts +2 -2
  32. package/dist/edges/propagationTypes.js.map +1 -1
  33. package/dist/edges/refutes.js +2 -65
  34. package/dist/edges/refutes.js.map +1 -1
  35. package/dist/edges/supports.js +1 -122
  36. package/dist/edges/supports.js.map +1 -1
  37. package/dist/edges/utils.d.ts +7 -7
  38. package/dist/edges/utils.js +2 -133
  39. package/dist/edges/utils.js.map +1 -1
  40. package/dist/embeddingTrigger.js +21 -1
  41. package/dist/embeddingTrigger.js.map +1 -1
  42. package/dist/entityBridge.js +3 -18
  43. package/dist/entityBridge.js.map +1 -1
  44. package/dist/{entityLifecycle-BkhRJ-XI.d.ts → entityLifecycle-CvgSK5FV.d.ts} +1 -1
  45. package/dist/entityLifecycle.d.ts +1 -1
  46. package/dist/entityLifecycle.js +193 -892
  47. package/dist/entityLifecycle.js.map +1 -1
  48. package/dist/{epistemicAnswers-DSP1slZ9.d.ts → epistemicAnswers-C5ib4z6_.d.ts} +1 -1
  49. package/dist/epistemicAnswers.d.ts +1 -1
  50. package/dist/epistemicAnswers.js +73 -810
  51. package/dist/epistemicAnswers.js.map +1 -1
  52. package/dist/{epistemicBeliefs-DtFVTp-k.d.ts → epistemicBeliefs-DzKjZAeC.d.ts} +3 -3
  53. package/dist/epistemicBeliefs.d.ts +2 -2
  54. package/dist/epistemicBeliefs.js +404 -1698
  55. package/dist/epistemicBeliefs.js.map +1 -1
  56. package/dist/epistemicContractHelpers.js +1 -318
  57. package/dist/epistemicContractHelpers.js.map +1 -1
  58. package/dist/epistemicContracts.d.ts +1 -1
  59. package/dist/epistemicContracts.js +417 -1980
  60. package/dist/epistemicContracts.js.map +1 -1
  61. package/dist/{epistemicEdges-DcA8ErUG.d.ts → epistemicEdges-CD5vxmlH.d.ts} +3 -3
  62. package/dist/epistemicEdges.d.ts +1 -1
  63. package/dist/epistemicEdges.js +248 -919
  64. package/dist/epistemicEdges.js.map +1 -1
  65. package/dist/{epistemicEvidence-Bo638XDP.d.ts → epistemicEvidence-xw6UUrwh.d.ts} +1 -1
  66. package/dist/epistemicEvidence.d.ts +1 -1
  67. package/dist/epistemicEvidence.js +229 -1087
  68. package/dist/epistemicEvidence.js.map +1 -1
  69. package/dist/{epistemicHelpers-Bd9xbaib.d.ts → epistemicHelpers-DevrYgPN.d.ts} +1 -1
  70. package/dist/epistemicHelpers.d.ts +1 -1
  71. package/dist/{epistemicLinking-CyeLOIzN.d.ts → epistemicLinking-CfE00tHJ.d.ts} +1 -1
  72. package/dist/epistemicLinking.d.ts +1 -1
  73. package/dist/epistemicLinking.js +3 -786
  74. package/dist/epistemicLinking.js.map +1 -1
  75. package/dist/{epistemicNodes-BpD6Koud.d.ts → epistemicNodes-NBrPW7fk.d.ts} +2 -2
  76. package/dist/epistemicNodes.d.ts +1 -1
  77. package/dist/epistemicNodes.js +172 -899
  78. package/dist/epistemicNodes.js.map +1 -1
  79. package/dist/{epistemicQuestions-CmEeY6zQ.d.ts → epistemicQuestions-B_nUclrH.d.ts} +1 -1
  80. package/dist/epistemicQuestions.d.ts +1 -1
  81. package/dist/epistemicQuestions.js +369 -1125
  82. package/dist/epistemicQuestions.js.map +1 -1
  83. package/dist/{epistemicSources-ZazxHOK1.d.ts → epistemicSources-dlKj58Jp.d.ts} +1 -1
  84. package/dist/epistemicSources.d.ts +1 -1
  85. package/dist/epistemicSources.js +86 -886
  86. package/dist/epistemicSources.js.map +1 -1
  87. package/dist/evaluators/index.js +417 -1980
  88. package/dist/evaluators/index.js.map +1 -1
  89. package/dist/evaluators/lintCheckerEvaluator.js.map +1 -1
  90. package/dist/evaluators/sentryCheckerEvaluator.js.map +1 -1
  91. package/dist/evaluators/shared.js +20 -1
  92. package/dist/evaluators/shared.js.map +1 -1
  93. package/dist/evaluators/testRunnerEvaluator.js +20 -1
  94. package/dist/evaluators/testRunnerEvaluator.js.map +1 -1
  95. package/dist/evaluators/tscCheckerEvaluator.js.map +1 -1
  96. package/dist/index.d.ts +20 -20
  97. package/dist/index.js +965 -3004
  98. package/dist/index.js.map +1 -1
  99. package/dist/{ontology-matching-Buhu23ss.d.ts → ontology-matching-C6rrz2VP.d.ts} +1 -1
  100. package/dist/ontology-matching.d.ts +1 -1
  101. package/dist/ontology-matching.js +1 -344
  102. package/dist/ontology-matching.js.map +1 -1
  103. package/dist/{ontologyApproval-Ba0Jjk1k.d.ts → ontologyApproval-CFYmqKmk.d.ts} +1 -1
  104. package/dist/ontologyApproval.d.ts +1 -1
  105. package/dist/ontologyApproval.js +1 -13
  106. package/dist/ontologyApproval.js.map +1 -1
  107. package/dist/ontologyDefinitions.js +6 -20
  108. package/dist/ontologyDefinitions.js.map +1 -1
  109. package/dist/ontologyHelpers.d.ts +1 -1
  110. package/dist/ontologyHelpers.js +4 -3
  111. package/dist/ontologyHelpers.js.map +1 -1
  112. package/dist/ontologyRegistry.js +2 -17
  113. package/dist/ontologyRegistry.js.map +1 -1
  114. package/dist/{projectionReconciliation-CxrXYGaB.d.ts → projectionReconciliation-jww2fBI0.d.ts} +1 -1
  115. package/dist/projectionReconciliation.d.ts +1 -1
  116. package/dist/projectionReconciliation.js +16 -37
  117. package/dist/projectionReconciliation.js.map +1 -1
  118. package/dist/{projectionStaleness-CAdpIsaW.d.ts → projectionStaleness-CmdbpjVK.d.ts} +1 -1
  119. package/dist/projectionStaleness.d.ts +1 -1
  120. package/dist/{questionEvidenceLinks-BdQD0TkM.d.ts → questionEvidenceLinks-DFlyPpAj.d.ts} +1 -1
  121. package/dist/questionEvidenceLinks.d.ts +1 -1
  122. package/dist/questionEvidenceLinks.js +199 -881
  123. package/dist/questionEvidenceLinks.js.map +1 -1
  124. package/dist/resolvers.js +86 -37
  125. package/dist/resolvers.js.map +1 -1
  126. package/dist/scopeResolverCompat.js +64 -7
  127. package/dist/scopeResolverCompat.js.map +1 -1
  128. package/dist/{text-matching-CMn2WnVD.d.ts → text-matching-DNg4M5Wd.d.ts} +1 -1
  129. package/dist/text-matching.d.ts +1 -1
  130. package/dist/text-matching.js +1 -244
  131. package/dist/text-matching.js.map +1 -1
  132. package/dist/topicProjectOverlay.js +56 -13
  133. package/dist/topicProjectOverlay.js.map +1 -1
  134. package/dist/topicScope.js +55 -6
  135. package/dist/topicScope.js.map +1 -1
  136. package/dist/workflowBridge.d.ts +27 -0
  137. package/dist/workflowBridge.js +352 -0
  138. package/dist/workflowBridge.js.map +1 -0
  139. package/dist/workspaceIsolation.js +56 -57
  140. package/dist/workspaceIsolation.js.map +1 -1
  141. package/package.json +6 -5
@@ -1,246 +1,3 @@
1
- // ../../packages/contracts/src/text-matching.contract.ts
2
- var TOKEN_SPLIT_REGEX = /[^a-z0-9]+/;
3
- var NON_ALPHANUMERIC_REGEX = /[^a-z0-9]/g;
4
- var STOP_WORDS = /* @__PURE__ */ new Set([
5
- "the",
6
- "a",
7
- "an",
8
- "and",
9
- "or",
10
- "but",
11
- "in",
12
- "on",
13
- "at",
14
- "to",
15
- "for",
16
- "of",
17
- "with",
18
- "by",
19
- "from",
20
- "is",
21
- "it",
22
- "as",
23
- "be",
24
- "was",
25
- "are",
26
- "this",
27
- "that",
28
- "has",
29
- "had",
30
- "have",
31
- "not",
32
- "all",
33
- "can",
34
- "do",
35
- "its",
36
- "may",
37
- "will",
38
- "how",
39
- "what",
40
- "which",
41
- "who",
42
- "when",
43
- "where",
44
- "than",
45
- "then",
46
- "each",
47
- "into",
48
- "such",
49
- "any",
50
- "been",
51
- "if",
52
- "would",
53
- "about",
54
- "should",
55
- "these",
56
- "those",
57
- "their",
58
- "we",
59
- "our",
60
- "so"
61
- ]);
62
- function tokenizeSearchText(text) {
63
- return text.toLowerCase().split(TOKEN_SPLIT_REGEX).filter((token) => token.length >= 2 && !STOP_WORDS.has(token));
64
- }
65
- function stemToken(word) {
66
- if (word.length <= 4) {
67
- return word;
68
- }
69
- if (word.endsWith("ation")) {
70
- return word.slice(0, -5);
71
- }
72
- if (word.endsWith("ment")) {
73
- return word.slice(0, -4);
74
- }
75
- if (word.endsWith("ness")) {
76
- return word.slice(0, -4);
77
- }
78
- if (word.endsWith("ical")) {
79
- return word.slice(0, -4);
80
- }
81
- if (word.endsWith("tion")) {
82
- return word.slice(0, -4);
83
- }
84
- if (word.endsWith("sion")) {
85
- return word.slice(0, -4);
86
- }
87
- if (word.endsWith("ing")) {
88
- return word.slice(0, -3);
89
- }
90
- if (word.endsWith("ous")) {
91
- return word.slice(0, -3);
92
- }
93
- if (word.endsWith("ive")) {
94
- return word.slice(0, -3);
95
- }
96
- if (word.endsWith("ity")) {
97
- return word.slice(0, -3);
98
- }
99
- if (word.endsWith("ics")) {
100
- return word.slice(0, -3);
101
- }
102
- if (word.endsWith("ly")) {
103
- return word.slice(0, -2);
104
- }
105
- if (word.endsWith("ed")) {
106
- return word.slice(0, -2);
107
- }
108
- if (word.endsWith("er")) {
109
- return word.slice(0, -2);
110
- }
111
- if (word.endsWith("es")) {
112
- return word.slice(0, -2);
113
- }
114
- if (word.endsWith("al")) {
115
- return word.slice(0, -2);
116
- }
117
- if (word.endsWith("ic")) {
118
- return word.slice(0, -2);
119
- }
120
- if (word.endsWith("s") && !word.endsWith("ss")) {
121
- return word.slice(0, -1);
122
- }
123
- return word;
124
- }
125
- function tokenOverlapScore(queryTokens, textTokens) {
126
- if (queryTokens.length === 0 || textTokens.length === 0) {
127
- return 0;
128
- }
129
- const stemmedText = new Set(textTokens.map(stemToken));
130
- let matchCount = 0;
131
- for (const queryToken of queryTokens) {
132
- const stemmedQuery = stemToken(queryToken);
133
- if (stemmedText.has(stemmedQuery)) {
134
- matchCount += 1;
135
- continue;
136
- }
137
- for (const textToken of stemmedText) {
138
- if (textToken.startsWith(stemmedQuery) || stemmedQuery.startsWith(textToken)) {
139
- matchCount += 0.5;
140
- break;
141
- }
142
- }
143
- }
144
- return matchCount / queryTokens.length;
145
- }
146
- function bigramTokenize(text) {
147
- const normalized = text.toLowerCase().replace(NON_ALPHANUMERIC_REGEX, "");
148
- const bigrams = /* @__PURE__ */ new Set();
149
- for (let i = 0; i < normalized.length - 1; i++) {
150
- bigrams.add(normalized.slice(i, i + 2));
151
- }
152
- return bigrams;
153
- }
154
- function wordTokenize(text) {
155
- return text.toLowerCase().split(TOKEN_SPLIT_REGEX).filter((token) => token.length > 1);
156
- }
157
- function jaccardSimilarity(setA, setB) {
158
- if (setA.size === 0 && setB.size === 0) {
159
- return 0;
160
- }
161
- let intersectionSize = 0;
162
- const smaller = setA.size <= setB.size ? setA : setB;
163
- const larger = setA.size <= setB.size ? setB : setA;
164
- for (const item of smaller) {
165
- if (larger.has(item)) {
166
- intersectionSize++;
167
- }
168
- }
169
- const unionSize = setA.size + setB.size - intersectionSize;
170
- return unionSize === 0 ? 0 : intersectionSize / unionSize;
171
- }
172
- function wordOverlapScore(inputWords, typeWords) {
173
- if (typeWords.length === 0) {
174
- return 0;
175
- }
176
- let matches = 0;
177
- for (const word of typeWords) {
178
- if (inputWords.includes(word)) {
179
- matches++;
180
- }
181
- }
182
- return matches / typeWords.length;
183
- }
184
- function prepareLexicalQuery(query) {
185
- return {
186
- raw: query,
187
- tokens: tokenizeSearchText(query),
188
- words: wordTokenize(query),
189
- bigrams: bigramTokenize(query)
190
- };
191
- }
192
- function scoreLexicalSignal(query, signal) {
193
- const text = signal.text?.trim();
194
- if (!text) {
195
- return 0;
196
- }
197
- switch (signal.strategy ?? "tokenOverlap") {
198
- case "bigramJaccard":
199
- return jaccardSimilarity(query.bigrams, bigramTokenize(text));
200
- case "wordOverlap":
201
- return wordOverlapScore(query.words, wordTokenize(text));
202
- default:
203
- return tokenOverlapScore(query.tokens, tokenizeSearchText(text));
204
- }
205
- }
206
- function scoreLexicalSignals(query, signals) {
207
- let weightedScore = 0;
208
- let totalWeight = 0;
209
- for (const signal of signals) {
210
- if (!signal.text?.trim() || signal.weight <= 0) {
211
- continue;
212
- }
213
- weightedScore += scoreLexicalSignal(query, signal) * signal.weight;
214
- totalWeight += signal.weight;
215
- }
216
- return totalWeight === 0 ? 0 : weightedScore / totalWeight;
217
- }
218
- function rankWindowScore(index, total) {
219
- if (total <= 1) {
220
- return 1;
221
- }
222
- const clampedIndex = Math.max(0, Math.min(index, total - 1));
223
- return 1 - clampedIndex / (total - 1);
224
- }
225
- function rerankLexicalWindow(query, items, getText, options) {
226
- const preparedQuery = prepareLexicalQuery(query);
227
- if (preparedQuery.tokens.length === 0 || items.length <= 1) {
228
- return items;
229
- }
230
- const lexicalWeight = options?.lexicalWeight ?? 0.65;
231
- const rankWeight = options?.rankWeight ?? 0.35;
232
- return items.map((item, index) => {
233
- const lexicalScore = scoreLexicalSignals(preparedQuery, [
234
- { text: getText(item) ?? "", weight: 1, strategy: "tokenOverlap" }
235
- ]);
236
- const rankScore = rankWindowScore(index, items.length);
237
- return {
238
- item,
239
- combinedScore: lexicalScore * lexicalWeight + rankScore * rankWeight
240
- };
241
- }).sort((left, right) => right.combinedScore - left.combinedScore).map(({ item }) => item);
242
- }
243
-
244
- export { bigramTokenize, jaccardSimilarity, prepareLexicalQuery, rankWindowScore, rerankLexicalWindow, scoreLexicalSignal, scoreLexicalSignals, stemToken, tokenOverlapScore, tokenizeSearchText, wordOverlapScore, wordTokenize };
1
+ export { bigramTokenize, jaccardSimilarity, prepareLexicalQuery, rankWindowScore, rerankLexicalWindow, scoreLexicalSignal, scoreLexicalSignals, stemToken, tokenOverlapScore, tokenizeSearchText, wordOverlapScore, wordTokenize } from '@lucern/contracts/text-matching.contract';
245
2
  //# sourceMappingURL=text-matching.js.map
246
3
  //# sourceMappingURL=text-matching.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../packages/contracts/src/text-matching.contract.ts"],"names":[],"mappings":";AA4BA,IAAM,iBAAA,GAAoB,YAAA;AAC1B,IAAM,sBAAA,GAAyB,YAAA;AAG/B,IAAM,UAAA,uBAAiB,GAAA,CAAI;AAAA,EACzB,KAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAC,CAAA;AAGM,SAAS,mBAAmB,IAAA,EAAwB;AACzD,EAAA,OAAO,KACJ,WAAA,EAAY,CACZ,KAAA,CAAM,iBAAiB,EACvB,MAAA,CAAO,CAAC,KAAA,KAAU,KAAA,CAAM,UAAU,CAAA,IAAK,CAAC,UAAA,CAAW,GAAA,CAAI,KAAK,CAAC,CAAA;AAClE;AAGO,SAAS,UAAU,IAAA,EAAsB;AAC9C,EAAA,IAAI,IAAA,CAAK,UAAU,CAAA,EAAG;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA,EAAG;AAC1B,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACvB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACvB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACvB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACvB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACvB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACvB,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,CAAK,SAAS,GAAG,CAAA,IAAK,CAAC,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AAC9C,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACzB;AACA,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,iBAAA,CACd,aACA,UAAA,EACQ;AACR,EAAA,IAAI,WAAA,CAAY,MAAA,KAAW,CAAA,IAAK,UAAA,CAAW,WAAW,CAAA,EAAG;AACvD,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,cAAc,IAAI,GAAA,CAAI,UAAA,CAAW,GAAA,CAAI,SAAS,CAAC,CAAA;AACrD,EAAA,IAAI,UAAA,GAAa,CAAA;AAEjB,EAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,IAAA,MAAM,YAAA,GAAe,UAAU,UAAU,CAAA;AAEzC,IAAA,IAAI,WAAA,CAAY,GAAA,CAAI,YAAY,CAAA,EAAG;AACjC,MAAA,UAAA,IAAc,CAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,aAAa,WAAA,EAAa;AACnC,MAAA,IACE,UAAU,UAAA,CAAW,YAAY,KACjC,YAAA,CAAa,UAAA,CAAW,SAAS,CAAA,EACjC;AACA,QAAA,UAAA,IAAc,GAAA;AACd,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,aAAa,WAAA,CAAY,MAAA;AAClC;AAMO,SAAS,eAAe,IAAA,EAA2B;AACxD,EAAA,MAAM,aAAa,IAAA,CAAK,WAAA,EAAY,CAAE,OAAA,CAAQ,wBAAwB,EAAE,CAAA;AACxE,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,UAAA,CAAW,MAAA,GAAS,GAAG,CAAA,EAAA,EAAK;AAC9C,IAAA,OAAA,CAAQ,IAAI,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,CAAC,CAAC,CAAA;AAAA,EACxC;AACA,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,aAAa,IAAA,EAAwB;AACnD,EAAA,OAAO,IAAA,CACJ,WAAA,EAAY,CACZ,KAAA,CAAM,iBAAiB,CAAA,CACvB,MAAA,CAAO,CAAC,KAAA,KAAU,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AACvC;AAGO,SAAS,iBAAA,CACd,MACA,IAAA,EACQ;AACR,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,CAAA,IAAK,IAAA,CAAK,SAAS,CAAA,EAAG;AACtC,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,IAAI,gBAAA,GAAmB,CAAA;AACvB,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,OAAO,IAAA,GAAO,IAAA;AAChD,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,OAAO,IAAA,GAAO,IAAA;AAE/C,EAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,IAAA,IAAI,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA,EAAG;AACpB,MAAA,gBAAA,EAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,IAAA,GAAO,gBAAA;AAC1C,EAAA,OAAO,SAAA,KAAc,CAAA,GAAI,CAAA,GAAI,gBAAA,GAAmB,SAAA;AAClD;AAGO,SAAS,gBAAA,CACd,YACA,SAAA,EACQ;AACR,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC5B,IAAA,IAAI,UAAA,CAAW,QAAA,CAAS,IAAI,CAAA,EAAG;AAC7B,MAAA,OAAA,EAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,UAAU,SAAA,CAAU,MAAA;AAC7B;AAGO,SAAS,oBAAoB,KAAA,EAAqC;AACvE,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,KAAA;AAAA,IACL,MAAA,EAAQ,mBAAmB,KAAK,CAAA;AAAA,IAChC,KAAA,EAAO,aAAa,KAAK,CAAA;AAAA,IACzB,OAAA,EAAS,eAAe,KAAK;AAAA,GAC/B;AACF;AAGO,SAAS,kBAAA,CACd,OACA,MAAA,EACQ;AACR,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,EAAM,IAAA,EAAK;AAC/B,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,QAAQ,MAAA,CAAO,YAAY,cAAA;AAAgB,IACzC,KAAK,eAAA;AACH,MAAA,OAAO,iBAAA,CAAkB,KAAA,CAAM,OAAA,EAAS,cAAA,CAAe,IAAI,CAAC,CAAA;AAAA,IAC9D,KAAK,aAAA;AACH,MAAA,OAAO,gBAAA,CAAiB,KAAA,CAAM,KAAA,EAAO,YAAA,CAAa,IAAI,CAAC,CAAA;AAAA,IACzD;AACE,MAAA,OAAO,iBAAA,CAAkB,KAAA,CAAM,MAAA,EAAQ,kBAAA,CAAmB,IAAI,CAAC,CAAA;AAAA;AAErE;AAGO,SAAS,mBAAA,CACd,OACA,OAAA,EACQ;AACR,EAAA,IAAI,aAAA,GAAgB,CAAA;AACpB,EAAA,IAAI,WAAA,GAAc,CAAA;AAElB,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,CAAC,MAAA,CAAO,IAAA,EAAM,MAAK,IAAK,MAAA,CAAO,UAAU,CAAA,EAAG;AAC9C,MAAA;AAAA,IACF;AACA,IAAA,aAAA,IAAiB,kBAAA,CAAmB,KAAA,EAAO,MAAM,CAAA,GAAI,MAAA,CAAO,MAAA;AAC5D,IAAA,WAAA,IAAe,MAAA,CAAO,MAAA;AAAA,EACxB;AAEA,EAAA,OAAO,WAAA,KAAgB,CAAA,GAAI,CAAA,GAAI,aAAA,GAAgB,WAAA;AACjD;AAGO,SAAS,eAAA,CAAgB,OAAe,KAAA,EAAuB;AACpE,EAAA,IAAI,SAAS,CAAA,EAAG;AACd,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,MAAM,YAAA,GAAe,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,KAAA,EAAO,KAAA,GAAQ,CAAC,CAAC,CAAA;AAC3D,EAAA,OAAO,CAAA,GAAI,gBAAgB,KAAA,GAAQ,CAAA,CAAA;AACrC;AAGO,SAAS,mBAAA,CACd,KAAA,EACA,KAAA,EACA,OAAA,EACA,OAAA,EACK;AACL,EAAA,MAAM,aAAA,GAAgB,oBAAoB,KAAK,CAAA;AAC/C,EAAA,IAAI,cAAc,MAAA,CAAO,MAAA,KAAW,CAAA,IAAK,KAAA,CAAM,UAAU,CAAA,EAAG;AAC1D,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,aAAA,GAAgB,SAAS,aAAA,IAAiB,IAAA;AAChD,EAAA,MAAM,UAAA,GAAa,SAAS,UAAA,IAAc,IAAA;AAE1C,EAAA,OAAO,KAAA,CACJ,GAAA,CAAI,CAAC,IAAA,EAAM,KAAA,KAAU;AACpB,IAAA,MAAM,YAAA,GAAe,oBAAoB,aAAA,EAAe;AAAA,MACtD,EAAE,MAAM,OAAA,CAAQ,IAAI,KAAK,EAAA,EAAI,MAAA,EAAQ,CAAA,EAAG,QAAA,EAAU,cAAA;AAAe,KAClE,CAAA;AACD,IAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,KAAA,EAAO,KAAA,CAAM,MAAM,CAAA;AAErD,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,aAAA,EAAe,YAAA,GAAe,aAAA,GAAgB,SAAA,GAAY;AAAA,KAC5D;AAAA,EACF,CAAC,CAAA,CACA,IAAA,CAAK,CAAC,IAAA,EAAM,UAAU,KAAA,CAAM,aAAA,GAAgB,IAAA,CAAK,aAAa,EAC9D,GAAA,CAAI,CAAC,EAAE,IAAA,OAAW,IAAI,CAAA;AAC3B","file":"text-matching.js","sourcesContent":["/**\n * Shared lexical matching primitives used across MCP handlers and graph utilities.\n *\n * The goal is not to replace downstream LLM scoring. It provides a fast,\n * deterministic substrate for candidate generation, reranking, and light\n * classification across belief/question/evidence/entity surfaces.\n */\n\nexport type LexicalStrategy = \"tokenOverlap\" | \"bigramJaccard\" | \"wordOverlap\";\n\nexport type PreparedLexicalQuery = {\n raw: string;\n tokens: string[];\n words: string[];\n bigrams: Set<string>;\n};\n\nexport type LexicalSignal = {\n strategy?: LexicalStrategy;\n text: string | null | undefined;\n weight: number;\n};\n\nexport type LexicalRerankOptions = {\n lexicalWeight?: number;\n rankWeight?: number;\n};\n\nconst TOKEN_SPLIT_REGEX = /[^a-z0-9]+/;\nconst NON_ALPHANUMERIC_REGEX = /[^a-z0-9]/g;\n\n/** Stop words that add noise to scoring. */\nconst STOP_WORDS = new Set([\n \"the\",\n \"a\",\n \"an\",\n \"and\",\n \"or\",\n \"but\",\n \"in\",\n \"on\",\n \"at\",\n \"to\",\n \"for\",\n \"of\",\n \"with\",\n \"by\",\n \"from\",\n \"is\",\n \"it\",\n \"as\",\n \"be\",\n \"was\",\n \"are\",\n \"this\",\n \"that\",\n \"has\",\n \"had\",\n \"have\",\n \"not\",\n \"all\",\n \"can\",\n \"do\",\n \"its\",\n \"may\",\n \"will\",\n \"how\",\n \"what\",\n \"which\",\n \"who\",\n \"when\",\n \"where\",\n \"than\",\n \"then\",\n \"each\",\n \"into\",\n \"such\",\n \"any\",\n \"been\",\n \"if\",\n \"would\",\n \"about\",\n \"should\",\n \"these\",\n \"those\",\n \"their\",\n \"we\",\n \"our\",\n \"so\",\n]);\n\n/** Tokenize a string into lowercase words, removing stop words. */\nexport function tokenizeSearchText(text: string): string[] {\n return text\n .toLowerCase()\n .split(TOKEN_SPLIT_REGEX)\n .filter((token) => token.length >= 2 && !STOP_WORDS.has(token));\n}\n\n/** Simple stemmer: strip common English suffixes for fuzzy matching. */\nexport function stemToken(word: string): string {\n if (word.length <= 4) {\n return word;\n }\n if (word.endsWith(\"ation\")) {\n return word.slice(0, -5);\n }\n if (word.endsWith(\"ment\")) {\n return word.slice(0, -4);\n }\n if (word.endsWith(\"ness\")) {\n return word.slice(0, -4);\n }\n if (word.endsWith(\"ical\")) {\n return word.slice(0, -4);\n }\n if (word.endsWith(\"tion\")) {\n return word.slice(0, -4);\n }\n if (word.endsWith(\"sion\")) {\n return word.slice(0, -4);\n }\n if (word.endsWith(\"ing\")) {\n return word.slice(0, -3);\n }\n if (word.endsWith(\"ous\")) {\n return word.slice(0, -3);\n }\n if (word.endsWith(\"ive\")) {\n return word.slice(0, -3);\n }\n if (word.endsWith(\"ity\")) {\n return word.slice(0, -3);\n }\n if (word.endsWith(\"ics\")) {\n return word.slice(0, -3);\n }\n if (word.endsWith(\"ly\")) {\n return word.slice(0, -2);\n }\n if (word.endsWith(\"ed\")) {\n return word.slice(0, -2);\n }\n if (word.endsWith(\"er\")) {\n return word.slice(0, -2);\n }\n if (word.endsWith(\"es\")) {\n return word.slice(0, -2);\n }\n if (word.endsWith(\"al\")) {\n return word.slice(0, -2);\n }\n if (word.endsWith(\"ic\")) {\n return word.slice(0, -2);\n }\n if (word.endsWith(\"s\") && !word.endsWith(\"ss\")) {\n return word.slice(0, -1);\n }\n return word;\n}\n\n/** Compute token overlap score between query tokens and text tokens. */\nexport function tokenOverlapScore(\n queryTokens: string[],\n textTokens: string[]\n): number {\n if (queryTokens.length === 0 || textTokens.length === 0) {\n return 0;\n }\n\n const stemmedText = new Set(textTokens.map(stemToken));\n let matchCount = 0;\n\n for (const queryToken of queryTokens) {\n const stemmedQuery = stemToken(queryToken);\n\n if (stemmedText.has(stemmedQuery)) {\n matchCount += 1;\n continue;\n }\n\n for (const textToken of stemmedText) {\n if (\n textToken.startsWith(stemmedQuery) ||\n stemmedQuery.startsWith(textToken)\n ) {\n matchCount += 0.5;\n break;\n }\n }\n }\n\n return matchCount / queryTokens.length;\n}\n\n/**\n * Extract character bigrams from text. Normalizes to lowercase, removes\n * non-alphanumeric characters, and generates overlapping pairs.\n */\nexport function bigramTokenize(text: string): Set<string> {\n const normalized = text.toLowerCase().replace(NON_ALPHANUMERIC_REGEX, \"\");\n const bigrams = new Set<string>();\n for (let i = 0; i < normalized.length - 1; i++) {\n bigrams.add(normalized.slice(i, i + 2));\n }\n return bigrams;\n}\n\n/**\n * Extract word-level tokens from text (for coarser matching).\n * Normalizes to lowercase, splits on non-alphanumeric.\n */\nexport function wordTokenize(text: string): string[] {\n return text\n .toLowerCase()\n .split(TOKEN_SPLIT_REGEX)\n .filter((token) => token.length > 1);\n}\n\n/** Jaccard similarity between two sets: |A ∩ B| / |A ∪ B|. */\nexport function jaccardSimilarity(\n setA: Set<string>,\n setB: Set<string>\n): number {\n if (setA.size === 0 && setB.size === 0) {\n return 0;\n }\n\n let intersectionSize = 0;\n const smaller = setA.size <= setB.size ? setA : setB;\n const larger = setA.size <= setB.size ? setB : setA;\n\n for (const item of smaller) {\n if (larger.has(item)) {\n intersectionSize++;\n }\n }\n\n const unionSize = setA.size + setB.size - intersectionSize;\n return unionSize === 0 ? 0 : intersectionSize / unionSize;\n}\n\n/** Exact word overlap score: fraction of type words found in input text. */\nexport function wordOverlapScore(\n inputWords: string[],\n typeWords: string[]\n): number {\n if (typeWords.length === 0) {\n return 0;\n }\n let matches = 0;\n for (const word of typeWords) {\n if (inputWords.includes(word)) {\n matches++;\n }\n }\n return matches / typeWords.length;\n}\n\n/** Pre-compute reusable lexical structures for a query. */\nexport function prepareLexicalQuery(query: string): PreparedLexicalQuery {\n return {\n raw: query,\n tokens: tokenizeSearchText(query),\n words: wordTokenize(query),\n bigrams: bigramTokenize(query),\n };\n}\n\n/** Score a single lexical signal against a prepared query. */\nexport function scoreLexicalSignal(\n query: PreparedLexicalQuery,\n signal: LexicalSignal\n): number {\n const text = signal.text?.trim();\n if (!text) {\n return 0;\n }\n\n switch (signal.strategy ?? \"tokenOverlap\") {\n case \"bigramJaccard\":\n return jaccardSimilarity(query.bigrams, bigramTokenize(text));\n case \"wordOverlap\":\n return wordOverlapScore(query.words, wordTokenize(text));\n default:\n return tokenOverlapScore(query.tokens, tokenizeSearchText(text));\n }\n}\n\n/** Weighted lexical score across multiple textual signals. */\nexport function scoreLexicalSignals(\n query: PreparedLexicalQuery,\n signals: LexicalSignal[]\n): number {\n let weightedScore = 0;\n let totalWeight = 0;\n\n for (const signal of signals) {\n if (!signal.text?.trim() || signal.weight <= 0) {\n continue;\n }\n weightedScore += scoreLexicalSignal(query, signal) * signal.weight;\n totalWeight += signal.weight;\n }\n\n return totalWeight === 0 ? 0 : weightedScore / totalWeight;\n}\n\n/** Map a candidate's original rank position into a 0..1 prior. */\nexport function rankWindowScore(index: number, total: number): number {\n if (total <= 1) {\n return 1;\n }\n const clampedIndex = Math.max(0, Math.min(index, total - 1));\n return 1 - clampedIndex / (total - 1);\n}\n\n/** Rerank a candidate window by lexical overlap while preserving original-rank prior. */\nexport function rerankLexicalWindow<T>(\n query: string,\n items: T[],\n getText: (item: T) => string | null | undefined,\n options?: LexicalRerankOptions\n): T[] {\n const preparedQuery = prepareLexicalQuery(query);\n if (preparedQuery.tokens.length === 0 || items.length <= 1) {\n return items;\n }\n\n const lexicalWeight = options?.lexicalWeight ?? 0.65;\n const rankWeight = options?.rankWeight ?? 0.35;\n\n return items\n .map((item, index) => {\n const lexicalScore = scoreLexicalSignals(preparedQuery, [\n { text: getText(item) ?? \"\", weight: 1, strategy: \"tokenOverlap\" },\n ]);\n const rankScore = rankWindowScore(index, items.length);\n\n return {\n item,\n combinedScore: lexicalScore * lexicalWeight + rankScore * rankWeight,\n };\n })\n .sort((left, right) => right.combinedScore - left.combinedScore)\n .map(({ item }) => item);\n}\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"text-matching.js","sourcesContent":[]}
@@ -4,6 +4,18 @@ import { componentsGeneric, anyApi } from 'convex/server';
4
4
  var api = anyApi;
5
5
  componentsGeneric();
6
6
 
7
+ // src/debug.ts
8
+ function isGraphPrimitiveDebugEnabled() {
9
+ const env = globalThis.process?.env;
10
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
11
+ }
12
+ function debugGraphPrimitiveFallback(message, context) {
13
+ if (!isGraphPrimitiveDebugEnabled()) {
14
+ return;
15
+ }
16
+ console.debug(message, context ?? {});
17
+ }
18
+
7
19
  // src/topicProjectOverlay.ts
8
20
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
9
21
  function readNonEmptyString(value) {
@@ -49,19 +61,37 @@ function isProjectLikeTopic(topic) {
49
61
  return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
50
62
  }
51
63
  function isMissingLucernChildComponentError(error) {
52
- const message = error instanceof Error ? error.message : String(error);
64
+ const message = getErrorMessage(error);
53
65
  return message.includes(
54
66
  'Child component ComponentName(Identifier("lucern")) not found'
55
67
  ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
56
68
  }
69
+ function getErrorMessage(error) {
70
+ if (error instanceof Error) {
71
+ return error.message;
72
+ }
73
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
74
+ return error.message;
75
+ }
76
+ return "unknown error";
77
+ }
57
78
  async function resolveTopicDoc(ctx, scopeId) {
58
79
  if (ctx?.db && typeof ctx.db.get === "function") {
59
80
  try {
60
- const directTopic = await ctx.db.get(scopeId);
81
+ const directTopic = await ctx.db.get(
82
+ scopeId
83
+ );
61
84
  if (directTopic) {
62
85
  return directTopic;
63
86
  }
64
- } catch {
87
+ } catch (error) {
88
+ debugGraphPrimitiveFallback(
89
+ "[topicProjectOverlay] Failed to resolve topic by direct ID",
90
+ {
91
+ error,
92
+ scopeId
93
+ }
94
+ );
65
95
  }
66
96
  }
67
97
  if (typeof ctx.runQuery !== "function") {
@@ -74,7 +104,14 @@ async function resolveTopicDoc(ctx, scopeId) {
74
104
  if (topic?.name !== void 0 && topic?.type !== void 0) {
75
105
  return topic;
76
106
  }
77
- } catch {
107
+ } catch (error) {
108
+ debugGraphPrimitiveFallback(
109
+ "[topicProjectOverlay] Failed to resolve topic by ID query",
110
+ {
111
+ error,
112
+ scopeId
113
+ }
114
+ );
78
115
  }
79
116
  try {
80
117
  const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
@@ -83,7 +120,11 @@ async function resolveTopicDoc(ctx, scopeId) {
83
120
  if (topic?.name !== void 0 && topic?.type !== void 0) {
84
121
  return topic;
85
122
  }
86
- } catch {
123
+ } catch (error) {
124
+ debugGraphPrimitiveFallback(
125
+ "[topicProjectOverlay] Failed to resolve topic by legacy scope ID",
126
+ { error, scopeId }
127
+ );
87
128
  }
88
129
  return null;
89
130
  }
@@ -137,7 +178,11 @@ async function listTopicProjectOverlays(ctx, options = {}) {
137
178
  if (ctx?.db?.query && typeof ctx.db.query === "function") {
138
179
  try {
139
180
  allTopics = await ctx.db.query("topics").collect();
140
- } catch {
181
+ } catch (error) {
182
+ debugGraphPrimitiveFallback(
183
+ "[topicProjectOverlay] Failed to read topics table; falling back to API",
184
+ { error }
185
+ );
141
186
  allTopics = [];
142
187
  }
143
188
  }
@@ -232,13 +277,11 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
232
277
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
233
278
  );
234
279
  }
235
- return materializeTopicProjectOverlay(
236
- {
237
- ...topic,
238
- ...patch,
239
- metadata: nextMetadata
240
- }
241
- );
280
+ return materializeTopicProjectOverlay({
281
+ ...topic,
282
+ ...patch,
283
+ metadata: nextMetadata
284
+ });
242
285
  }
243
286
  function matchesTopicProjectOverlayAccess(accessibleProjectIds, project) {
244
287
  return accessibleProjectIds.has(project.storageProjectId || project.topicId) || accessibleProjectIds.has(project.topicId) || typeof project.legacyProjectId === "string" && accessibleProjectIds.has(project.legacyProjectId);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/convex.ts","../src/topicProjectOverlay.ts"],"names":[],"mappings":";;;AAaO,IAAM,GAAA,GAAM,MAAA;AACO,iBAAA;;;ACX1B,IAAM,kBAAA,GAAqB,qBAAA;AA8F3B,SAAS,mBAAmB,KAAA,EAAoC;AAC9D,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA;AAAA,EACF;AACA,EAAA,MAAM,UAAA,GAAa,MAAM,IAAA,EAAK;AAC9B,EAAA,OAAO,UAAA,CAAW,MAAA,GAAS,CAAA,GAAI,UAAA,GAAa,MAAA;AAC9C;AAEA,SAAS,gBAAgB,KAAA,EAA0B;AACjD,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACzB,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,KAAA,CACJ,GAAA,CAAI,CAAC,KAAA,KAAU,kBAAA,CAAmB,KAAK,CAAC,CAAA,CACxC,MAAA,CAAO,CAAC,KAAA,KAA2B,OAAA,CAAQ,KAAK,CAAC,CAAA;AACtD;AAEA,SAAS,aAAa,KAAA,EAA8C;AAClE,EAAA,OAAO,KAAA,CAAM,YAAY,OAAO,KAAA,CAAM,aAAa,QAAA,GAC/C,KAAA,CAAM,WACN,EAAC;AACP;AAEA,SAAS,oBACP,KAAA,EACoB;AACpB,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA;AAAA,EACF;AACA,EAAA,OAAO,kBAAA,CAAmB,KAAA,CAAM,kBAAkB,CAAC,CAAA;AACrD;AAEA,SAAS,iBACP,KAAA,EAC+C;AAC/C,EAAA,OAAO,KAAA,KAAU,SAAA,IACf,KAAA,KAAU,MAAA,IACV,KAAA,KAAU,UACV,KAAA,KAAU,UAAA,IACV,KAAA,KAAU,QAAA,GACR,KAAA,GACA,MAAA;AACN;AAEA,SAAS,aACP,KAAA,EAC2C;AAC3C,EAAA,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,UAAA,IAAc,KAAA,KAAU,aAC3D,KAAA,GACA,MAAA;AACN;AAEA,SAAS,cAAA,CACP,OACA,QAAA,EACQ;AACR,EAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,QAAA,CAAS,WAAW,CAAA;AACxD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,IAAA,OAAO,UAAA;AAAA,EACT;AACA,EAAA,OAAO,kBAAA,CAAmB,KAAA,CAAM,IAAI,CAAA,IAAK,SAAA;AAC3C;AAEA,SAAS,mBAAmB,KAAA,EAA8B;AACxD,EAAA,MAAM,QAAA,GAAW,aAAa,KAAK,CAAA;AACnC,EAAA,OACE,MAAM,IAAA,KAAS,OAAA,IACf,MAAM,IAAA,KAAS,UAAA,IACf,MAAM,IAAA,KAAS,MAAA,IACf,MAAM,IAAA,KAAS,YAAA,IACf,oBAAoB,KAAK,CAAA,KAAM,UAC/B,kBAAA,CAAmB,QAAA,CAAS,WAAW,CAAA,KAAM,MAAA;AAEjD;AAEA,SAAS,mCAAmC,KAAA,EAAyB;AACnE,EAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,EAAA,OACE,OAAA,CAAQ,QAAA;AAAA,IACN;AAAA,GACF,IACC,OAAA,CAAQ,QAAA,CAAS,iBAAiB,CAAA,IACjC,OAAA,CAAQ,QAAA,CAAS,QAAQ,CAAA,IACzB,OAAA,CAAQ,QAAA,CAAS,WAAW,CAAA;AAElC;AAEA,eAAe,eAAA,CACb,KACA,OAAA,EAC8B;AAC9B,EAAA,IAAI,KAAK,EAAA,IAAM,OAAO,GAAA,CAAI,EAAA,CAAG,QAAQ,UAAA,EAAY;AAC/C,IAAA,IAAI;AACF,MAAA,MAAM,WAAA,GAAe,MAAM,GAAA,CAAI,EAAA,CAAG,IAAI,OAAc,CAAA;AACpD,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,OAAO,WAAA;AAAA,MACT;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,IAAI,OAAO,GAAA,CAAI,QAAA,KAAa,UAAA,EAAY;AACtC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,MAAM,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,OAAO,GAAA,EAAY;AAAA,MACtD,EAAA,EAAI,OAAO,OAAO;AAAA,KACnB,CAAA;AACD,IAAA,IAAI,KAAA,EAAO,IAAA,KAAS,KAAA,CAAA,IAAa,KAAA,EAAO,SAAS,KAAA,CAAA,EAAW;AAC1D,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,MAAM,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,OAAO,kBAAA,EAA2B;AAAA,MACrE,SAAA,EAAW,OAAO,OAAO;AAAA,KAC1B,CAAA;AACD,IAAA,IAAI,KAAA,EAAO,IAAA,KAAS,KAAA,CAAA,IAAa,KAAA,EAAO,SAAS,KAAA,CAAA,EAAW;AAC1D,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,8BAAA,CACd,KAAA,EACA,MAAA,GAAwB,QAAA,EACH;AACrB,EAAA,MAAM,QAAA,GAAW,aAAa,KAAK,CAAA;AACnC,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAChC,EAAA,MAAM,eAAA,GACJ,oBAAoB,KAAK,CAAA,IACzB,oBAAoB,QAAQ,CAAA,IAC5B,kBAAA,CAAmB,QAAA,CAAS,eAAe,CAAA;AAC7C,EAAA,MAAM,mBAAmB,eAAA,IAAmB,OAAA;AAC5C,EAAA,MAAM,SAAA,GAAY,MAAA,KAAW,OAAA,GAAU,OAAA,GAAU,gBAAA;AACjD,EAAA,MAAM,UAAA,GACJ,iBAAiB,KAAA,CAAM,UAAU,KACjC,gBAAA,CAAiB,QAAA,CAAS,UAAU,CAAA,IACpC,SAAA;AACF,EAAA,MAAM,MAAA,GACJ,aAAa,KAAA,CAAM,MAAM,KAAK,YAAA,CAAa,QAAA,CAAS,MAAM,CAAA,IAAK,QAAA;AACjE,EAAA,MAAM,SAAA,GACJ,OAAO,KAAA,CAAM,SAAA,KAAc,QAAA,GACvB,KAAA,CAAM,SAAA,GACN,OAAO,KAAA,CAAM,aAAA,KAAkB,QAAA,GAC7B,KAAA,CAAM,aAAA,GACN,CAAA;AACR,EAAA,MAAM,SAAA,GACJ,OAAO,KAAA,CAAM,SAAA,KAAc,QAAA,GACvB,KAAA,CAAM,SAAA,GACN,OAAO,QAAA,CAAS,SAAA,KAAc,QAAA,GAC3B,QAAA,CAAS,SAAA,GACV,SAAA;AAER,EAAA,OAAO;AAAA,IACL,GAAG,QAAA;AAAA,IACH,GAAA,EAAK,SAAA;AAAA,IACL,SAAA,EAAW,SAAA;AAAA,IACX,OAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,IAAA,EAAM,kBAAA,CAAmB,KAAA,CAAM,IAAI,CAAA,IAAK,gBAAA;AAAA,IACxC,IAAA,EAAM,cAAA,CAAe,KAAA,EAAO,QAAQ,CAAA;AAAA,IACpC,WAAA,EAAa,kBAAA,CAAmB,KAAA,CAAM,WAAW,CAAA;AAAA,IACjD,OAAA,EACE,mBAAmB,QAAA,CAAS,OAAO,KACnC,kBAAA,CAAmB,KAAA,CAAM,SAAS,CAAA,IAClC,QAAA;AAAA,IACF,UAAA,EAAY,eAAA,CAAgB,QAAA,CAAS,UAAU,CAAA;AAAA,IAC/C,UAAA;AAAA,IACA,UACE,kBAAA,CAAmB,KAAA,CAAM,QAAQ,CAAA,IACjC,kBAAA,CAAmB,SAAS,QAAQ,CAAA;AAAA,IACtC,aACE,kBAAA,CAAmB,KAAA,CAAM,WAAW,CAAA,IACpC,kBAAA,CAAmB,SAAS,WAAW,CAAA;AAAA,IACzC,MAAA;AAAA,IACA,IAAA,EAAM,eAAA,CAAgB,QAAA,CAAS,IAAI,CAAA;AAAA,IACnC,WACE,OAAO,QAAA,CAAS,SAAA,KAAc,QAAA,GAAY,SAAS,SAAA,GAAuB,CAAA;AAAA,IAC5E,eACE,OAAO,QAAA,CAAS,aAAA,KAAkB,QAAA,GAC7B,SAAS,aAAA,GACV,CAAA;AAAA,IACN,gBACE,OAAO,QAAA,CAAS,cAAA,KAAmB,QAAA,GAC9B,SAAS,cAAA,GACV,SAAA;AAAA,IACN,eACE,OAAO,KAAA,CAAM,aAAA,KAAkB,QAAA,GAAW,MAAM,aAAA,GAAgB,SAAA;AAAA,IAClE,SAAA;AAAA,IACA;AAAA,GACF;AACF;AAEA,eAAsB,0BAAA,CACpB,GAAA,EACA,OAAA,EACA,OAAA,GAGI,EAAC,EACgC;AACrC,EAAA,MAAM,KAAA,GAAQ,MAAM,eAAA,CAAgB,GAAA,EAAK,OAAO,CAAA;AAChD,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAQ,eAAA,KAAoB,KAAA,IAAS,CAAC,kBAAA,CAAmB,KAAK,CAAA,EAAG;AACnE,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,8BAAA,CAA+B,KAAA,EAAO,OAAA,CAAQ,MAAM,CAAA;AAC7D;AAEA,eAAsB,wBAAA,CACpB,GAAA,EACA,OAAA,GAGI,EAAC,EAC2B;AAChC,EAAA,IAAI,YAA4B,EAAC;AAEjC,EAAA,IAAI,KAAK,EAAA,EAAI,KAAA,IAAS,OAAO,GAAA,CAAI,EAAA,CAAG,UAAU,UAAA,EAAY;AACxD,IAAA,IAAI;AACF,MAAA,SAAA,GAAa,MAAM,GAAA,CAAI,EAAA,CAAG,KAAA,CAAM,QAAQ,EAAE,OAAA,EAAQ;AAAA,IACpD,CAAA,CAAA,MAAQ;AACN,MAAA,SAAA,GAAY,EAAC;AAAA,IACf;AAAA,EACF;AAEA,EAAA,IAAI,UAAU,MAAA,KAAW,CAAA,IAAK,OAAO,GAAA,CAAI,aAAa,UAAA,EAAY;AAChE,IAAA,SAAA,GAAA,CACK,MAAM,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,MAAA,CAAO,IAAA,EAAa,EAAE,CAAA,IAAM,EAAC,KACvD,EAAC;AAAA,EACL;AAEA,EAAA,OAAO,SAAA,CACJ,MAAA;AAAA,IACC,CAAC,KAAA,KAAU,OAAA,CAAQ,eAAA,KAAoB,KAAA,IAAS,mBAAmB,KAAK;AAAA,GAC1E,CACC,IAAI,CAAC,KAAA,KAAU,+BAA+B,KAAA,EAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AACzE;AAEA,eAAsB,wBAAA,CACpB,GAAA,EACA,OAAA,EACA,KAAA,EACqC;AACrC,EAAA,MAAM,KAAA,GAAQ,MAAM,eAAA,CAAgB,GAAA,EAAK,OAAO,CAAA;AAChD,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,EAAE,GAAG,YAAA,CAAa,KAAK,CAAA,EAAE;AAC9C,EAAA,MAAM,QAAiC,EAAC;AACxC,EAAA,MAAM,eAAA,GAA2C;AAAA,IAC/C,EAAA,EAAI,MAAA,CAAO,KAAA,CAAM,GAAG;AAAA,GACtB;AAEA,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,QAAQ,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AACnD,IAAA,QAAQ,GAAA;AAAK,MACX,KAAK,KAAA;AAAA,MACL,KAAK,WAAA;AAAA,MACL,KAAK,SAAA;AAAA,MACL,KAAK,iBAAA;AAAA,MACL,KAAK,kBAAA;AACH,QAAA;AAAA,MACF,KAAK,MAAA;AAAA,MACL,KAAK,aAAA;AACH,QAAA,KAAA,CAAM,GAAG,CAAA,GAAI,QAAA;AACb,QAAA,eAAA,CAAgB,GAAG,CAAA,GAAI,QAAA;AACvB,QAAA;AAAA,MACF,KAAK,UAAA;AAAA,MACL,KAAK,aAAA;AAAA,MACL,KAAK,SAAA;AACH,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,0CAA0C,GAAG,CAAA,2BAAA;AAAA,SAC/C;AAAA,MACF,KAAK,QAAA,EAAU;AACb,QAAA,MAAM,MAAA,GAAS,aAAa,QAAQ,CAAA;AACpC,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,KAAA,CAAM,MAAA,GAAS,MAAA;AACf,UAAA,eAAA,CAAgB,MAAA,GAAS,MAAA;AAAA,QAC3B;AACA,QAAA;AAAA,MACF;AAAA,MACA,KAAK,YAAA,EAAc;AACjB,QAAA,MAAM,UAAA,GAAa,iBAAiB,QAAQ,CAAA;AAC5C,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,KAAA,CAAM,UAAA,GAAa,UAAA;AACnB,UAAA,eAAA,CAAgB,UAAA,GAAa,UAAA;AAAA,QAC/B;AACA,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,MAAM,WAAA,GAAc,mBAAmB,QAAQ,CAAA;AAC/C,QAAA,IAAI,WAAA,EAAa;AACf,UAAA,YAAA,CAAa,WAAA,GAAc,WAAA;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,OAAO,YAAA,CAAa,WAAA;AAAA,QACtB;AACA,QAAA;AAAA,MACF;AAAA,MACA,KAAK,WAAA;AAAA,MACL,KAAK,WAAA;AACH,QAAA;AAAA,MACF;AACE,QAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,UAAA,OAAO,aAAa,GAAG,CAAA;AAAA,QACzB,CAAA,MAAO;AACL,UAAA,YAAA,CAAa,GAAG,CAAA,GAAI,QAAA;AAAA,QACtB;AAAA;AACJ,EACF;AAEA,EAAA,KAAA,CAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,EAAA,KAAA,CAAM,QAAA,GAAW,YAAA;AACjB,EAAA,eAAA,CAAgB,QAAA,GAAW,YAAA;AAE3B,EAAA,IAAI,OAAO,GAAA,CAAI,WAAA,KAAgB,UAAA,EAAY;AACzC,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,CAAI,WAAA,CAAY,GAAA,CAAI,MAAA,CAAO,QAAe,eAAe,CAAA;AAAA,IACjE,SAAS,KAAA,EAAO;AACd,MAAA,IACE,CAAC,kCAAA,CAAmC,KAAK,CAAA,IACzC,CAAC,GAAA,EAAK,EAAA,IACN,OAAO,GAAA,CAAI,EAAA,CAAG,KAAA,KAAU,UAAA,EACxB;AACA,QAAA,MAAM,KAAA;AAAA,MACR;AACA,MAAA,MAAM,IAAI,EAAA,CAAG,KAAA,CAAM,OAAO,KAAA,CAAM,GAAG,GAAU,KAAK,CAAA;AAAA,IACpD;AAAA,EACF,WAAW,GAAA,EAAK,EAAA,IAAM,OAAO,GAAA,CAAI,EAAA,CAAG,UAAU,UAAA,EAAY;AACxD,IAAA,MAAM,IAAI,EAAA,CAAG,KAAA,CAAM,OAAO,KAAA,CAAM,GAAG,GAAU,KAAK,CAAA;AAAA,EACpD,CAAA,MAAO;AACL,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,OAAO,8BAAA;AAAA,IACL;AAAA,MACE,GAAG,KAAA;AAAA,MACH,GAAG,KAAA;AAAA,MACH,QAAA,EAAU;AAAA;AACZ,GACF;AACF;AAEO,SAAS,gCAAA,CACd,sBACA,OAAA,EACS;AACT,EAAA,OACE,qBAAqB,GAAA,CAAI,OAAA,CAAQ,oBAAoB,OAAA,CAAQ,OAAO,KACpE,oBAAA,CAAqB,GAAA,CAAI,QAAQ,OAAO,CAAA,IACvC,OAAO,OAAA,CAAQ,eAAA,KAAoB,YAClC,oBAAA,CAAqB,GAAA,CAAI,QAAQ,eAAe,CAAA;AAEtD","file":"topicProjectOverlay.js","sourcesContent":["import {\n actionGeneric,\n anyApi,\n componentsGeneric,\n httpActionGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n mutationGeneric,\n queryGeneric,\n} from \"convex/server\";\nimport type { GenericId } from \"convex/values\";\n\nexport const api = anyApi as any;\nexport const components = componentsGeneric() as any;\nexport const internal = anyApi as any;\n\nexport type TableNames = string;\nexport type Id<TableName extends TableNames = string> = GenericId<TableName>;\nexport type Doc<TableName extends TableNames = string> = any;\nexport type DataModel = any;\nexport type ActionCtx = any;\nexport type DatabaseReader = any;\nexport type DatabaseWriter = any;\nexport type MutationCtx = any;\nexport type QueryCtx = any;\n\nexport const action = actionGeneric as any;\nexport const httpAction = httpActionGeneric as any;\nexport const internalAction = internalActionGeneric as any;\nexport const internalMutation = internalMutationGeneric as any;\nexport const internalQuery = internalQueryGeneric as any;\nexport const mutation = mutationGeneric as any;\nexport const query = queryGeneric as any;\n","import { api } from \"./convex\";\n\ntype OverlayIdMode = \"legacy\" | \"topic\";\nconst LEGACY_SCOPE_FIELD = \"graphScope\" + \"ProjectId\";\n\ntype LegacyProjectThesis = {\n statement: string;\n confidence: number;\n lastUpdated: number;\n};\n\ntype LegacyPillarImportance =\n | \"critical\"\n | \"major\"\n | \"minor\"\n | \"not_applicable\";\n\ntype LegacyThesisPillarConfig = {\n pillarImportance?: Record<string, LegacyPillarImportance | undefined>;\n configuredAt?: number;\n configuredBy?: string;\n aiSuggestion?: {\n suggestedAt: number;\n reasoning: string;\n };\n};\n\ntype LegacyBeliefArchitecture = {\n overallMaturity: number;\n pillarScores: Array<Record<string, unknown>>;\n lastCalculated: number;\n};\n\ntype LegacyOntologyClassification = {\n valueChains: Array<Record<string, unknown>>;\n functions: Array<Record<string, unknown>>;\n overallConfidence: number;\n classifiedAt: number;\n};\n\ntype TopicDocLike = Record<string, unknown> & {\n _id: string;\n _creationTime?: number;\n globalId?: string;\n name?: string;\n description?: string;\n type?: string;\n tenantId?: string;\n workspaceId?: string;\n status?: string;\n visibility?: string;\n createdBy?: string;\n createdAt?: number;\n updatedAt?: number;\n metadata?: Record<string, unknown>;\n};\n\nexport type TopicProjectOverlay = Record<string, unknown> & {\n _id: string;\n projectId: string;\n topicId: string;\n storageProjectId: string;\n legacyProjectId?: string;\n name: string;\n type: string;\n description?: string;\n ownerId: string;\n sharedWith: string[];\n visibility: \"private\" | \"team\" | \"firm\" | \"external\" | \"public\";\n tenantId?: string;\n workspaceId?: string;\n status: \"active\" | \"archived\" | \"watching\";\n tags: string[];\n chatCount: number;\n artifactCount: number;\n lastActivityAt: number;\n thesis?: LegacyProjectThesis;\n wedgeHypothesis?: string;\n founderArchetype?: string;\n investmentCriteria?: string[];\n sprintPhase?:\n | \"pre_sprint\"\n | \"readiness_check\"\n | \"thesis_crystallization\"\n | \"sprint_planning\"\n | \"active_sprint\"\n | \"theme_assembly\"\n | \"evolution\";\n currentSprintIndex?: number;\n thesisPillarConfig?: LegacyThesisPillarConfig;\n beliefArchitecture?: LegacyBeliefArchitecture;\n ontologyClassification?: LegacyOntologyClassification;\n _creationTime: number;\n createdAt: number;\n updatedAt: number;\n};\n\nfunction readNonEmptyString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return;\n }\n const normalized = value.trim();\n return normalized.length > 0 ? normalized : undefined;\n}\n\nfunction readStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value\n .map((entry) => readNonEmptyString(entry))\n .filter((entry): entry is string => Boolean(entry));\n}\n\nfunction readMetadata(topic: TopicDocLike): Record<string, unknown> {\n return topic.metadata && typeof topic.metadata === \"object\"\n ? topic.metadata\n : {};\n}\n\nfunction readLegacyProjectId(\n value: Record<string, unknown> | null | undefined\n): string | undefined {\n if (!value) {\n return;\n }\n return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);\n}\n\nfunction coerceVisibility(\n value: unknown\n): TopicProjectOverlay[\"visibility\"] | undefined {\n return value === \"private\" ||\n value === \"team\" ||\n value === \"firm\" ||\n value === \"external\" ||\n value === \"public\"\n ? value\n : undefined;\n}\n\nfunction coerceStatus(\n value: unknown\n): TopicProjectOverlay[\"status\"] | undefined {\n return value === \"active\" || value === \"archived\" || value === \"watching\"\n ? value\n : undefined;\n}\n\nfunction mapProjectType(\n topic: TopicDocLike,\n metadata: Record<string, unknown>\n): string {\n const explicit = readNonEmptyString(metadata.projectType);\n if (explicit) {\n return explicit;\n }\n if (topic.type === \"theme\") {\n return \"thematic\";\n }\n return readNonEmptyString(topic.type) || \"general\";\n}\n\nfunction isProjectLikeTopic(topic: TopicDocLike): boolean {\n const metadata = readMetadata(topic);\n return (\n topic.type === \"theme\" ||\n topic.type === \"thematic\" ||\n topic.type === \"deal\" ||\n topic.type === \"monitoring\" ||\n readLegacyProjectId(topic) !== undefined ||\n readNonEmptyString(metadata.projectType) !== undefined\n );\n}\n\nfunction isMissingLucernChildComponentError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return (\n message.includes(\n 'Child component ComponentName(Identifier(\"lucern\")) not found'\n ) ||\n (message.includes(\"Child component\") &&\n message.includes(\"lucern\") &&\n message.includes(\"not found\"))\n );\n}\n\nasync function resolveTopicDoc(\n ctx: any,\n scopeId: string\n): Promise<TopicDocLike | null> {\n if (ctx?.db && typeof ctx.db.get === \"function\") {\n try {\n const directTopic = (await ctx.db.get(scopeId as any)) as TopicDocLike | null;\n if (directTopic) {\n return directTopic;\n }\n } catch {\n // Not a direct topics-table id.\n }\n }\n\n if (typeof ctx.runQuery !== \"function\") {\n return null;\n }\n\n try {\n const topic = await ctx.runQuery(api.topics.get as any, {\n id: String(scopeId),\n });\n if (topic?.name !== undefined && topic?.type !== undefined) {\n return topic as TopicDocLike;\n }\n } catch {\n // Fall through to legacy-scope lookup.\n }\n\n try {\n const topic = await ctx.runQuery(api.topics.getByLegacyScopeId as any, {\n projectId: String(scopeId),\n });\n if (topic?.name !== undefined && topic?.type !== undefined) {\n return topic as TopicDocLike;\n }\n } catch {\n // Best-effort compat lookup only.\n }\n\n return null;\n}\n\nexport function materializeTopicProjectOverlay(\n topic: TopicDocLike,\n idMode: OverlayIdMode = \"legacy\"\n): TopicProjectOverlay {\n const metadata = readMetadata(topic);\n const topicId = String(topic._id);\n const legacyProjectId =\n readLegacyProjectId(topic) ||\n readLegacyProjectId(metadata) ||\n readNonEmptyString(metadata.legacyProjectId);\n const storageProjectId = legacyProjectId || topicId;\n const outwardId = idMode === \"topic\" ? topicId : storageProjectId;\n const visibility =\n coerceVisibility(topic.visibility) ||\n coerceVisibility(metadata.visibility) ||\n \"private\";\n const status =\n coerceStatus(topic.status) || coerceStatus(metadata.status) || \"active\";\n const createdAt =\n typeof topic.createdAt === \"number\"\n ? topic.createdAt\n : typeof topic._creationTime === \"number\"\n ? topic._creationTime\n : 0;\n const updatedAt =\n typeof topic.updatedAt === \"number\"\n ? topic.updatedAt\n : typeof metadata.updatedAt === \"number\"\n ? (metadata.updatedAt as number)\n : createdAt;\n\n return {\n ...metadata,\n _id: outwardId,\n projectId: outwardId,\n topicId,\n storageProjectId,\n legacyProjectId,\n name: readNonEmptyString(topic.name) || \"Untitled Theme\",\n type: mapProjectType(topic, metadata),\n description: readNonEmptyString(topic.description),\n ownerId:\n readNonEmptyString(metadata.ownerId) ||\n readNonEmptyString(topic.createdBy) ||\n \"system\",\n sharedWith: readStringArray(metadata.sharedWith),\n visibility,\n tenantId:\n readNonEmptyString(topic.tenantId) ||\n readNonEmptyString(metadata.tenantId),\n workspaceId:\n readNonEmptyString(topic.workspaceId) ||\n readNonEmptyString(metadata.workspaceId),\n status,\n tags: readStringArray(metadata.tags),\n chatCount:\n typeof metadata.chatCount === \"number\" ? (metadata.chatCount as number) : 0,\n artifactCount:\n typeof metadata.artifactCount === \"number\"\n ? (metadata.artifactCount as number)\n : 0,\n lastActivityAt:\n typeof metadata.lastActivityAt === \"number\"\n ? (metadata.lastActivityAt as number)\n : updatedAt,\n _creationTime:\n typeof topic._creationTime === \"number\" ? topic._creationTime : createdAt,\n createdAt,\n updatedAt,\n };\n}\n\nexport async function resolveTopicProjectOverlay(\n ctx: any,\n scopeId: string,\n options: {\n idMode?: OverlayIdMode;\n projectLikeOnly?: boolean;\n } = {}\n): Promise<TopicProjectOverlay | null> {\n const topic = await resolveTopicDoc(ctx, scopeId);\n if (!topic) {\n return null;\n }\n if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {\n return null;\n }\n return materializeTopicProjectOverlay(topic, options.idMode);\n}\n\nexport async function listTopicProjectOverlays(\n ctx: any,\n options: {\n idMode?: OverlayIdMode;\n projectLikeOnly?: boolean;\n } = {}\n): Promise<TopicProjectOverlay[]> {\n let allTopics: TopicDocLike[] = [];\n\n if (ctx?.db?.query && typeof ctx.db.query === \"function\") {\n try {\n allTopics = (await ctx.db.query(\"topics\").collect()) as TopicDocLike[];\n } catch {\n allTopics = [];\n }\n }\n\n if (allTopics.length === 0 && typeof ctx.runQuery === \"function\") {\n allTopics =\n (((await ctx.runQuery(api.topics.list as any, {})) ?? []) as TopicDocLike[]) ||\n [];\n }\n\n return allTopics\n .filter(\n (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)\n )\n .map((topic) => materializeTopicProjectOverlay(topic, options.idMode));\n}\n\nexport async function patchTopicProjectOverlay(\n ctx: any,\n scopeId: string,\n value: Record<string, unknown>\n): Promise<TopicProjectOverlay | null> {\n const topic = await resolveTopicDoc(ctx, scopeId);\n if (!topic) {\n return null;\n }\n\n const nextMetadata = { ...readMetadata(topic) };\n const patch: Record<string, unknown> = {};\n const topicUpdateArgs: Record<string, unknown> = {\n id: String(topic._id),\n };\n\n for (const [key, rawValue] of Object.entries(value)) {\n switch (key) {\n case \"_id\":\n case \"projectId\":\n case \"topicId\":\n case \"legacyProjectId\":\n case \"storageProjectId\":\n break;\n case \"name\":\n case \"description\":\n patch[key] = rawValue;\n topicUpdateArgs[key] = rawValue;\n break;\n case \"tenantId\":\n case \"workspaceId\":\n case \"ownerId\":\n throw new Error(\n `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`\n );\n case \"status\": {\n const status = coerceStatus(rawValue);\n if (status) {\n patch.status = status;\n topicUpdateArgs.status = status;\n }\n break;\n }\n case \"visibility\": {\n const visibility = coerceVisibility(rawValue);\n if (visibility) {\n patch.visibility = visibility;\n topicUpdateArgs.visibility = visibility;\n }\n break;\n }\n case \"type\": {\n const projectType = readNonEmptyString(rawValue);\n if (projectType) {\n nextMetadata.projectType = projectType;\n } else {\n delete nextMetadata.projectType;\n }\n break;\n }\n case \"updatedAt\":\n case \"createdAt\":\n break;\n default:\n if (rawValue === undefined) {\n delete nextMetadata[key];\n } else {\n nextMetadata[key] = rawValue;\n }\n }\n }\n\n patch.updatedAt = Date.now();\n patch.metadata = nextMetadata;\n topicUpdateArgs.metadata = nextMetadata;\n\n if (typeof ctx.runMutation === \"function\") {\n try {\n await ctx.runMutation(api.topics.update as any, topicUpdateArgs);\n } catch (error) {\n if (\n !isMissingLucernChildComponentError(error) ||\n !ctx?.db ||\n typeof ctx.db.patch !== \"function\"\n ) {\n throw error;\n }\n await ctx.db.patch(String(topic._id) as any, patch);\n }\n } else if (ctx?.db && typeof ctx.db.patch === \"function\") {\n await ctx.db.patch(String(topic._id) as any, patch);\n } else {\n throw new Error(\n \"Cannot patch topic without component adapter (ctx.runMutation unavailable)\"\n );\n }\n\n return materializeTopicProjectOverlay(\n {\n ...topic,\n ...patch,\n metadata: nextMetadata,\n } as TopicDocLike\n );\n}\n\nexport function matchesTopicProjectOverlayAccess(\n accessibleProjectIds: Set<string>,\n project: { topicId: string; legacyProjectId?: string; storageProjectId?: string }\n): boolean {\n return (\n accessibleProjectIds.has(project.storageProjectId || project.topicId) ||\n accessibleProjectIds.has(project.topicId) ||\n (typeof project.legacyProjectId === \"string\" &&\n accessibleProjectIds.has(project.legacyProjectId))\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/convex.ts","../src/debug.ts","../src/topicProjectOverlay.ts"],"names":[],"mappings":"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","file":"topicProjectOverlay.js","sourcesContent":["import {\n actionGeneric,\n anyApi,\n componentsGeneric,\n httpActionGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n mutationGeneric,\n queryGeneric,\n} from \"convex/server\";\nimport type { GenericId } from \"convex/values\";\n\nexport const api = anyApi as any;\nexport const components = componentsGeneric() as any;\nexport const internal = anyApi as any;\n\nexport type TableNames = string;\nexport type Id<TableName extends TableNames = string> = GenericId<TableName>;\nexport type Doc<TableName extends TableNames = string> = any;\nexport type DataModel = any;\nexport type ActionCtx = any;\nexport type DatabaseReader = any;\nexport type DatabaseWriter = any;\nexport type MutationCtx = any;\nexport type QueryCtx = any;\n\nexport const action = actionGeneric as any;\nexport const httpAction = httpActionGeneric as any;\nexport const internalAction = internalActionGeneric as any;\nexport const internalMutation = internalMutationGeneric as any;\nexport const internalQuery = internalQueryGeneric as any;\nexport const mutation = mutationGeneric as any;\nexport const query = queryGeneric as any;\n","type GraphPrimitiveDebugEnvironment = {\n process?: {\n env?: Record<string, string | undefined>;\n };\n};\n\nfunction isGraphPrimitiveDebugEnabled(): boolean {\n const env = (globalThis as GraphPrimitiveDebugEnvironment).process?.env;\n return (\n env?.LUCERN_COMPAT_FALLBACK_DEBUG === \"1\" ||\n env?.LUCERN_GRAPH_DEBUG === \"1\"\n );\n}\n\nexport function formatGraphPrimitiveError(error: unknown): string {\n if (error instanceof Error) {\n return `${error.name}: ${error.message}`;\n }\n if (typeof error === \"string\") {\n return error;\n }\n if (error === null) {\n return \"null\";\n }\n if (error === undefined) {\n return \"undefined\";\n }\n try {\n return JSON.stringify(error);\n } catch {\n return Object.prototype.toString.call(error);\n }\n}\n\nexport function debugGraphPrimitiveFallback(\n message: string,\n context?: Record<string, unknown>\n): void {\n if (!isGraphPrimitiveDebugEnabled()) {\n return;\n }\n console.debug(message, context ?? {});\n}\n","import { api } from \"./convex\";\nimport { debugGraphPrimitiveFallback } from \"./debug\";\n\ntype OverlayIdMode = \"legacy\" | \"topic\";\nconst LEGACY_SCOPE_FIELD = \"graphScope\" + \"ProjectId\";\n\ntype LegacyProjectThesis = {\n statement: string;\n confidence: number;\n lastUpdated: number;\n};\n\ntype LegacyPillarImportance = \"critical\" | \"major\" | \"minor\" | \"not_applicable\";\n\ntype LegacyThesisPillarConfig = {\n pillarImportance?: Record<string, LegacyPillarImportance | undefined>;\n configuredAt?: number;\n configuredBy?: string;\n aiSuggestion?: {\n suggestedAt: number;\n reasoning: string;\n };\n};\n\ntype LegacyBeliefArchitecture = {\n overallMaturity: number;\n pillarScores: Array<Record<string, unknown>>;\n lastCalculated: number;\n};\n\ntype LegacyOntologyClassification = {\n valueChains: Array<Record<string, unknown>>;\n functions: Array<Record<string, unknown>>;\n overallConfidence: number;\n classifiedAt: number;\n};\n\ntype TopicDocLike = Record<string, unknown> & {\n _id: string;\n _creationTime?: number;\n globalId?: string;\n name?: string;\n description?: string;\n type?: string;\n tenantId?: string;\n workspaceId?: string;\n status?: string;\n visibility?: string;\n createdBy?: string;\n createdAt?: number;\n updatedAt?: number;\n metadata?: Record<string, unknown>;\n};\n\nexport type TopicProjectOverlay = Record<string, unknown> & {\n _id: string;\n projectId: string;\n topicId: string;\n storageProjectId: string;\n legacyProjectId?: string;\n name: string;\n type: string;\n description?: string;\n ownerId: string;\n sharedWith: string[];\n visibility: \"private\" | \"team\" | \"firm\" | \"external\" | \"public\";\n tenantId?: string;\n workspaceId?: string;\n status: \"active\" | \"archived\" | \"watching\";\n tags: string[];\n chatCount: number;\n artifactCount: number;\n lastActivityAt: number;\n thesis?: LegacyProjectThesis;\n wedgeHypothesis?: string;\n founderArchetype?: string;\n investmentCriteria?: string[];\n sprintPhase?:\n | \"pre_sprint\"\n | \"readiness_check\"\n | \"thesis_crystallization\"\n | \"sprint_planning\"\n | \"active_sprint\"\n | \"theme_assembly\"\n | \"evolution\";\n currentSprintIndex?: number;\n thesisPillarConfig?: LegacyThesisPillarConfig;\n beliefArchitecture?: LegacyBeliefArchitecture;\n ontologyClassification?: LegacyOntologyClassification;\n _creationTime: number;\n createdAt: number;\n updatedAt: number;\n};\n\nfunction readNonEmptyString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return;\n }\n const normalized = value.trim();\n return normalized.length > 0 ? normalized : undefined;\n}\n\nfunction readStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value\n .map((entry) => readNonEmptyString(entry))\n .filter((entry): entry is string => Boolean(entry));\n}\n\nfunction readMetadata(topic: TopicDocLike): Record<string, unknown> {\n return topic.metadata && typeof topic.metadata === \"object\"\n ? topic.metadata\n : {};\n}\n\nfunction readLegacyProjectId(\n value: Record<string, unknown> | null | undefined,\n): string | undefined {\n if (!value) {\n return;\n }\n return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);\n}\n\nfunction coerceVisibility(\n value: unknown,\n): TopicProjectOverlay[\"visibility\"] | undefined {\n return value === \"private\" ||\n value === \"team\" ||\n value === \"firm\" ||\n value === \"external\" ||\n value === \"public\"\n ? value\n : undefined;\n}\n\nfunction coerceStatus(\n value: unknown,\n): TopicProjectOverlay[\"status\"] | undefined {\n return value === \"active\" || value === \"archived\" || value === \"watching\"\n ? value\n : undefined;\n}\n\nfunction mapProjectType(\n topic: TopicDocLike,\n metadata: Record<string, unknown>,\n): string {\n const explicit = readNonEmptyString(metadata.projectType);\n if (explicit) {\n return explicit;\n }\n if (topic.type === \"theme\") {\n return \"thematic\";\n }\n return readNonEmptyString(topic.type) || \"general\";\n}\n\nfunction isProjectLikeTopic(topic: TopicDocLike): boolean {\n const metadata = readMetadata(topic);\n return (\n topic.type === \"theme\" ||\n topic.type === \"thematic\" ||\n topic.type === \"deal\" ||\n topic.type === \"monitoring\" ||\n readLegacyProjectId(topic) !== undefined ||\n readNonEmptyString(metadata.projectType) !== undefined\n );\n}\n\nfunction isMissingLucernChildComponentError(error: unknown): boolean {\n const message = getErrorMessage(error);\n return (\n message.includes(\n 'Child component ComponentName(Identifier(\"lucern\")) not found',\n ) ||\n (message.includes(\"Child component\") &&\n message.includes(\"lucern\") &&\n message.includes(\"not found\"))\n );\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof (error as { message?: unknown }).message === \"string\"\n ) {\n return (error as { message: string }).message;\n }\n return \"unknown error\";\n}\n\nasync function resolveTopicDoc(\n ctx: any,\n scopeId: string,\n): Promise<TopicDocLike | null> {\n if (ctx?.db && typeof ctx.db.get === \"function\") {\n try {\n const directTopic = (await ctx.db.get(\n scopeId as any,\n )) as TopicDocLike | null;\n if (directTopic) {\n return directTopic;\n }\n } catch (error) {\n debugGraphPrimitiveFallback(\n \"[topicProjectOverlay] Failed to resolve topic by direct ID\",\n {\n error,\n scopeId,\n },\n );\n // Not a direct topics-table id.\n }\n }\n\n if (typeof ctx.runQuery !== \"function\") {\n return null;\n }\n\n try {\n const topic = await ctx.runQuery(api.topics.get as any, {\n id: String(scopeId),\n });\n if (topic?.name !== undefined && topic?.type !== undefined) {\n return topic as TopicDocLike;\n }\n } catch (error) {\n debugGraphPrimitiveFallback(\n \"[topicProjectOverlay] Failed to resolve topic by ID query\",\n {\n error,\n scopeId,\n },\n );\n // Fall through to legacy-scope lookup.\n }\n\n try {\n const topic = await ctx.runQuery(api.topics.getByLegacyScopeId as any, {\n projectId: String(scopeId),\n });\n if (topic?.name !== undefined && topic?.type !== undefined) {\n return topic as TopicDocLike;\n }\n } catch (error) {\n debugGraphPrimitiveFallback(\n \"[topicProjectOverlay] Failed to resolve topic by legacy scope ID\",\n { error, scopeId },\n );\n // Best-effort compat lookup only.\n }\n\n return null;\n}\n\nexport function materializeTopicProjectOverlay(\n topic: TopicDocLike,\n idMode: OverlayIdMode = \"legacy\",\n): TopicProjectOverlay {\n const metadata = readMetadata(topic);\n const topicId = String(topic._id);\n const legacyProjectId =\n readLegacyProjectId(topic) ||\n readLegacyProjectId(metadata) ||\n readNonEmptyString(metadata.legacyProjectId);\n const storageProjectId = legacyProjectId || topicId;\n const outwardId = idMode === \"topic\" ? topicId : storageProjectId;\n const visibility =\n coerceVisibility(topic.visibility) ||\n coerceVisibility(metadata.visibility) ||\n \"private\";\n const status =\n coerceStatus(topic.status) || coerceStatus(metadata.status) || \"active\";\n const createdAt =\n typeof topic.createdAt === \"number\"\n ? topic.createdAt\n : typeof topic._creationTime === \"number\"\n ? topic._creationTime\n : 0;\n const updatedAt =\n typeof topic.updatedAt === \"number\"\n ? topic.updatedAt\n : typeof metadata.updatedAt === \"number\"\n ? (metadata.updatedAt as number)\n : createdAt;\n\n return {\n ...metadata,\n _id: outwardId,\n projectId: outwardId,\n topicId,\n storageProjectId,\n legacyProjectId,\n name: readNonEmptyString(topic.name) || \"Untitled Theme\",\n type: mapProjectType(topic, metadata),\n description: readNonEmptyString(topic.description),\n ownerId:\n readNonEmptyString(metadata.ownerId) ||\n readNonEmptyString(topic.createdBy) ||\n \"system\",\n sharedWith: readStringArray(metadata.sharedWith),\n visibility,\n tenantId:\n readNonEmptyString(topic.tenantId) ||\n readNonEmptyString(metadata.tenantId),\n workspaceId:\n readNonEmptyString(topic.workspaceId) ||\n readNonEmptyString(metadata.workspaceId),\n status,\n tags: readStringArray(metadata.tags),\n chatCount:\n typeof metadata.chatCount === \"number\"\n ? (metadata.chatCount as number)\n : 0,\n artifactCount:\n typeof metadata.artifactCount === \"number\"\n ? (metadata.artifactCount as number)\n : 0,\n lastActivityAt:\n typeof metadata.lastActivityAt === \"number\"\n ? (metadata.lastActivityAt as number)\n : updatedAt,\n _creationTime:\n typeof topic._creationTime === \"number\" ? topic._creationTime : createdAt,\n createdAt,\n updatedAt,\n };\n}\n\nexport async function resolveTopicProjectOverlay(\n ctx: any,\n scopeId: string,\n options: {\n idMode?: OverlayIdMode;\n projectLikeOnly?: boolean;\n } = {},\n): Promise<TopicProjectOverlay | null> {\n const topic = await resolveTopicDoc(ctx, scopeId);\n if (!topic) {\n return null;\n }\n if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {\n return null;\n }\n return materializeTopicProjectOverlay(topic, options.idMode);\n}\n\nexport async function listTopicProjectOverlays(\n ctx: any,\n options: {\n idMode?: OverlayIdMode;\n projectLikeOnly?: boolean;\n } = {},\n): Promise<TopicProjectOverlay[]> {\n let allTopics: TopicDocLike[] = [];\n\n if (ctx?.db?.query && typeof ctx.db.query === \"function\") {\n try {\n allTopics = (await ctx.db.query(\"topics\").collect()) as TopicDocLike[];\n } catch (error) {\n debugGraphPrimitiveFallback(\n \"[topicProjectOverlay] Failed to read topics table; falling back to API\",\n { error },\n );\n allTopics = [];\n }\n }\n\n if (allTopics.length === 0 && typeof ctx.runQuery === \"function\") {\n allTopics =\n (((await ctx.runQuery(api.topics.list as any, {})) ??\n []) as TopicDocLike[]) || [];\n }\n\n return allTopics\n .filter(\n (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic),\n )\n .map((topic) => materializeTopicProjectOverlay(topic, options.idMode));\n}\n\nexport async function patchTopicProjectOverlay(\n ctx: any,\n scopeId: string,\n value: Record<string, unknown>,\n): Promise<TopicProjectOverlay | null> {\n const topic = await resolveTopicDoc(ctx, scopeId);\n if (!topic) {\n return null;\n }\n\n const nextMetadata = { ...readMetadata(topic) };\n const patch: Record<string, unknown> = {};\n const topicUpdateArgs: Record<string, unknown> = {\n id: String(topic._id),\n };\n\n for (const [key, rawValue] of Object.entries(value)) {\n switch (key) {\n case \"_id\":\n case \"projectId\":\n case \"topicId\":\n case \"legacyProjectId\":\n case \"storageProjectId\":\n break;\n case \"name\":\n case \"description\":\n patch[key] = rawValue;\n topicUpdateArgs[key] = rawValue;\n break;\n case \"tenantId\":\n case \"workspaceId\":\n case \"ownerId\":\n throw new Error(\n `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`,\n );\n case \"status\": {\n const status = coerceStatus(rawValue);\n if (status) {\n patch.status = status;\n topicUpdateArgs.status = status;\n }\n break;\n }\n case \"visibility\": {\n const visibility = coerceVisibility(rawValue);\n if (visibility) {\n patch.visibility = visibility;\n topicUpdateArgs.visibility = visibility;\n }\n break;\n }\n case \"type\": {\n const projectType = readNonEmptyString(rawValue);\n if (projectType) {\n nextMetadata.projectType = projectType;\n } else {\n delete nextMetadata.projectType;\n }\n break;\n }\n case \"updatedAt\":\n case \"createdAt\":\n break;\n default:\n if (rawValue === undefined) {\n delete nextMetadata[key];\n } else {\n nextMetadata[key] = rawValue;\n }\n }\n }\n\n patch.updatedAt = Date.now();\n patch.metadata = nextMetadata;\n topicUpdateArgs.metadata = nextMetadata;\n\n if (typeof ctx.runMutation === \"function\") {\n try {\n await ctx.runMutation(api.topics.update as any, topicUpdateArgs);\n } catch (error) {\n if (\n !isMissingLucernChildComponentError(error) ||\n !ctx?.db ||\n typeof ctx.db.patch !== \"function\"\n ) {\n throw error;\n }\n await ctx.db.patch(String(topic._id) as any, patch);\n }\n } else if (ctx?.db && typeof ctx.db.patch === \"function\") {\n await ctx.db.patch(String(topic._id) as any, patch);\n } else {\n throw new Error(\n \"Cannot patch topic without component adapter (ctx.runMutation unavailable)\",\n );\n }\n\n return materializeTopicProjectOverlay({\n ...topic,\n ...patch,\n metadata: nextMetadata,\n } as TopicDocLike);\n}\n\nexport function matchesTopicProjectOverlayAccess(\n accessibleProjectIds: Set<string>,\n project: {\n topicId: string;\n legacyProjectId?: string;\n storageProjectId?: string;\n },\n): boolean {\n return (\n accessibleProjectIds.has(project.storageProjectId || project.topicId) ||\n accessibleProjectIds.has(project.topicId) ||\n (typeof project.legacyProjectId === \"string\" &&\n accessibleProjectIds.has(project.legacyProjectId))\n );\n}\n"]}
@@ -5,6 +5,18 @@ import { componentsGeneric, anyApi } from 'convex/server';
5
5
  var api = anyApi;
6
6
  componentsGeneric();
7
7
 
8
+ // src/debug.ts
9
+ function isGraphPrimitiveDebugEnabled() {
10
+ const env = globalThis.process?.env;
11
+ return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
12
+ }
13
+ function debugGraphPrimitiveFallback(message, context) {
14
+ if (!isGraphPrimitiveDebugEnabled()) {
15
+ return;
16
+ }
17
+ console.debug(message, context ?? {});
18
+ }
19
+
8
20
  // src/topicScope.ts
9
21
  var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
10
22
  function asMappedProjectId(topic) {
@@ -47,7 +59,14 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
47
59
  "by_graph_scope_project",
48
60
  (q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
49
61
  ).collect();
50
- } catch {
62
+ } catch (error) {
63
+ debugGraphPrimitiveFallback(
64
+ "[topicScope] Failed to resolve scope alias via index",
65
+ {
66
+ error,
67
+ scopeId
68
+ }
69
+ );
51
70
  const topics = await ctx.db.query("topics").collect();
52
71
  return topics.filter((topic) => {
53
72
  const normalizedGlobalId = normalizeScopeValue(topic.globalId);
@@ -64,7 +83,14 @@ async function tryResolveHostTopicById(ctx, topicId) {
64
83
  return await ctx.runQuery(api.topics.get, {
65
84
  id: topicId
66
85
  }) ?? null;
67
- } catch {
86
+ } catch (error) {
87
+ debugGraphPrimitiveFallback(
88
+ "[topicScope] Failed to resolve topic by host query",
89
+ {
90
+ error,
91
+ topicId
92
+ }
93
+ );
68
94
  return null;
69
95
  }
70
96
  }
@@ -76,7 +102,14 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
76
102
  return await ctx.runQuery(api.topics.getByLegacyScopeId, {
77
103
  projectId: legacyScopeId
78
104
  }) ?? null;
79
- } catch {
105
+ } catch (error) {
106
+ debugGraphPrimitiveFallback(
107
+ "[topicScope] Failed to resolve topic by legacy scope",
108
+ {
109
+ error,
110
+ legacyScopeId
111
+ }
112
+ );
80
113
  return null;
81
114
  }
82
115
  }
@@ -113,8 +146,17 @@ async function resolveTopicProjectScope(ctx, args) {
113
146
  if (args.topicId) {
114
147
  let topic = null;
115
148
  try {
116
- topic = await ctx.db.get(args.topicId);
117
- } catch {
149
+ topic = await ctx.db.get(
150
+ args.topicId
151
+ );
152
+ } catch (error) {
153
+ debugGraphPrimitiveFallback(
154
+ "[topicScope] Failed to load topic by direct id",
155
+ {
156
+ error,
157
+ topicId: args.topicId
158
+ }
159
+ );
118
160
  }
119
161
  if (!topic) {
120
162
  topic = await tryResolveHostTopicById(ctx, String(args.topicId));
@@ -151,7 +193,14 @@ async function resolveTopicProjectScope(ctx, args) {
151
193
  directTopic = await ctx.db.get(
152
194
  args.projectId
153
195
  );
154
- } catch {
196
+ } catch (error) {
197
+ debugGraphPrimitiveFallback(
198
+ "[topicScope] Failed to load direct project topic",
199
+ {
200
+ error,
201
+ projectId: args.projectId
202
+ }
203
+ );
155
204
  }
156
205
  if (directTopic) {
157
206
  const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);