@lucern/graph-primitives 0.1.0-alpha.4 → 0.3.0-alpha.1

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 (78) hide show
  1. package/dist/beliefDecay.js +229 -1115
  2. package/dist/beliefDecay.js.map +1 -1
  3. package/dist/beliefEvidenceLinks.js +53 -834
  4. package/dist/beliefEvidenceLinks.js.map +1 -1
  5. package/dist/confidencePropagationDispatch.d.ts +3 -3
  6. package/dist/confidencePropagationDispatch.js +30 -308
  7. package/dist/confidencePropagationDispatch.js.map +1 -1
  8. package/dist/contradictions.js +5 -797
  9. package/dist/contradictions.js.map +1 -1
  10. package/dist/edges/contradicts.js +1 -122
  11. package/dist/edges/contradicts.js.map +1 -1
  12. package/dist/edges/dependsOn.js +14 -172
  13. package/dist/edges/dependsOn.js.map +1 -1
  14. package/dist/edges/elaborates.js +1 -49
  15. package/dist/edges/elaborates.js.map +1 -1
  16. package/dist/edges/index.js +14 -277
  17. package/dist/edges/index.js.map +1 -1
  18. package/dist/edges/informs.js +1 -62
  19. package/dist/edges/informs.js.map +1 -1
  20. package/dist/edges/propagationTypes.d.ts +2 -2
  21. package/dist/edges/propagationTypes.js.map +1 -1
  22. package/dist/edges/refutes.js +1 -62
  23. package/dist/edges/refutes.js.map +1 -1
  24. package/dist/edges/supports.js +1 -122
  25. package/dist/edges/supports.js.map +1 -1
  26. package/dist/edges/utils.d.ts +6 -6
  27. package/dist/edges/utils.js +1 -130
  28. package/dist/edges/utils.js.map +1 -1
  29. package/dist/entityBridge.js +2 -17
  30. package/dist/entityBridge.js.map +1 -1
  31. package/dist/entityLifecycle.js +62 -848
  32. package/dist/entityLifecycle.js.map +1 -1
  33. package/dist/epistemicAnswers.js +27 -838
  34. package/dist/epistemicAnswers.js.map +1 -1
  35. package/dist/epistemicBeliefs.js +186 -2214
  36. package/dist/epistemicBeliefs.js.map +1 -1
  37. package/dist/epistemicContractHelpers.js +1 -318
  38. package/dist/epistemicContractHelpers.js.map +1 -1
  39. package/dist/epistemicContracts.js +163 -2467
  40. package/dist/epistemicContracts.js.map +1 -1
  41. package/dist/epistemicEdges.js +60 -863
  42. package/dist/epistemicEdges.js.map +1 -1
  43. package/dist/epistemicEvidence.js +116 -1647
  44. package/dist/epistemicEvidence.js.map +1 -1
  45. package/dist/epistemicHelpers.js +3 -2
  46. package/dist/epistemicHelpers.js.map +1 -1
  47. package/dist/epistemicLinking.js +2 -785
  48. package/dist/epistemicLinking.js.map +1 -1
  49. package/dist/epistemicNodes.js +34 -1427
  50. package/dist/epistemicNodes.js.map +1 -1
  51. package/dist/epistemicQuestions.js +88 -1637
  52. package/dist/epistemicQuestions.js.map +1 -1
  53. package/dist/epistemicSources.js +28 -1421
  54. package/dist/epistemicSources.js.map +1 -1
  55. package/dist/evaluators/index.js +163 -2467
  56. package/dist/evaluators/index.js.map +1 -1
  57. package/dist/index.js +486 -3649
  58. package/dist/index.js.map +1 -1
  59. package/dist/ontology-matching.js +1 -344
  60. package/dist/ontology-matching.js.map +1 -1
  61. package/dist/ontologyApproval.js +1 -13
  62. package/dist/ontologyApproval.js.map +1 -1
  63. package/dist/ontologyDefinitions.js +2 -17
  64. package/dist/ontologyDefinitions.js.map +1 -1
  65. package/dist/ontologyRegistry.js +2 -17
  66. package/dist/ontologyRegistry.js.map +1 -1
  67. package/dist/projectionReconciliation.js +2 -17
  68. package/dist/projectionReconciliation.js.map +1 -1
  69. package/dist/questionEvidenceLinks.js +242 -837
  70. package/dist/questionEvidenceLinks.js.map +1 -1
  71. package/dist/text-matching.js +1 -244
  72. package/dist/text-matching.js.map +1 -1
  73. package/dist/workflowBridge.d.ts +27 -0
  74. package/dist/workflowBridge.js +303 -0
  75. package/dist/workflowBridge.js.map +1 -0
  76. package/dist/workspaceIsolation.js +8 -609
  77. package/dist/workspaceIsolation.js.map +1 -1
  78. package/package.json +6 -6
@@ -1,798 +1,12 @@
1
1
  import { v } from 'convex/values';
2
+ import { checkProjectAccess } from '@lucern/access-control/access';
3
+ import { getCurrentUserId } from '@lucern/access-control/auth';
4
+ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
2
5
  import { componentsGeneric, queryGeneric, mutationGeneric, anyApi } from 'convex/server';
3
6
 
4
7
  // src/entityLifecycle.ts
5
8
  var api = anyApi;
6
9
  componentsGeneric();
7
-
8
- // ../access-control/src/topicProjectOverlay.ts
9
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
10
- function readNonEmptyString(value) {
11
- if (typeof value !== "string") {
12
- return;
13
- }
14
- const normalized = value.trim();
15
- return normalized.length > 0 ? normalized : void 0;
16
- }
17
- function readStringArray(value) {
18
- if (!Array.isArray(value)) {
19
- return [];
20
- }
21
- return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
22
- }
23
- function readMetadata(topic) {
24
- return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
25
- }
26
- function readLegacyProjectId(value) {
27
- if (!value) {
28
- return;
29
- }
30
- return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
31
- }
32
- function coerceVisibility(value) {
33
- return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
34
- }
35
- function coerceStatus(value) {
36
- return value === "active" || value === "archived" || value === "watching" ? value : void 0;
37
- }
38
- function mapProjectType(topic, metadata) {
39
- const explicit = readNonEmptyString(metadata.projectType);
40
- if (explicit) {
41
- return explicit;
42
- }
43
- if (topic.type === "theme") {
44
- return "thematic";
45
- }
46
- return readNonEmptyString(topic.type) || "general";
47
- }
48
- function isProjectLikeTopic(topic) {
49
- const metadata = readMetadata(topic);
50
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
51
- }
52
- async function resolveTopicDoc(ctx, scopeId) {
53
- if (ctx?.db && typeof ctx.db.get === "function") {
54
- try {
55
- const directTopic = await ctx.db.get(scopeId);
56
- if (directTopic) {
57
- return directTopic;
58
- }
59
- } catch {
60
- }
61
- }
62
- if (typeof ctx.runQuery !== "function") {
63
- return null;
64
- }
65
- try {
66
- const topic = await ctx.runQuery(api.topics.get, {
67
- id: String(scopeId)
68
- });
69
- if (topic?.name !== void 0 && topic?.type !== void 0) {
70
- return topic;
71
- }
72
- } catch {
73
- }
74
- try {
75
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
76
- projectId: String(scopeId)
77
- });
78
- if (topic?.name !== void 0 && topic?.type !== void 0) {
79
- return topic;
80
- }
81
- } catch {
82
- }
83
- return null;
84
- }
85
- function materializeTopicProjectOverlay(topic, idMode = "legacy") {
86
- const metadata = readMetadata(topic);
87
- const topicId = String(topic._id);
88
- const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
89
- const storageProjectId = legacyProjectId || topicId;
90
- const outwardId = idMode === "topic" ? topicId : storageProjectId;
91
- const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
92
- const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
93
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
94
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
95
- return {
96
- ...metadata,
97
- _id: outwardId,
98
- projectId: outwardId,
99
- topicId,
100
- storageProjectId,
101
- legacyProjectId,
102
- name: readNonEmptyString(topic.name) || "Untitled Theme",
103
- type: mapProjectType(topic, metadata),
104
- description: readNonEmptyString(topic.description),
105
- ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
106
- sharedWith: readStringArray(metadata.sharedWith),
107
- visibility,
108
- tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
109
- workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
110
- status,
111
- tags: readStringArray(metadata.tags),
112
- chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
113
- artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
114
- lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
115
- _creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
116
- createdAt,
117
- updatedAt
118
- };
119
- }
120
- async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
121
- const topic = await resolveTopicDoc(ctx, scopeId);
122
- if (!topic) {
123
- return null;
124
- }
125
- if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
126
- return null;
127
- }
128
- return materializeTopicProjectOverlay(topic, options.idMode);
129
- }
130
- async function listTopicProjectOverlays(ctx, options = {}) {
131
- let allTopics = [];
132
- if (ctx?.db?.query && typeof ctx.db.query === "function") {
133
- try {
134
- allTopics = await ctx.db.query("topics").collect();
135
- } catch {
136
- allTopics = [];
137
- }
138
- }
139
- if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
140
- allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
141
- }
142
- return allTopics.filter(
143
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
144
- ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
145
- }
146
-
147
- // ../access-control/src/projectGrantsBridge.ts
148
- var PROJECT_GRANT_STATUSES = ["active", "revoked", "expired"];
149
- function normalizeString(value) {
150
- if (typeof value !== "string") {
151
- return;
152
- }
153
- const trimmed = value.trim();
154
- return trimmed.length > 0 ? trimmed : void 0;
155
- }
156
- async function resolveGrantScopeIds(ctx, args) {
157
- const topicId = normalizeString(args.topicId);
158
- const projectId = normalizeString(args.projectId);
159
- for (const scopeId of [topicId, projectId]) {
160
- if (!scopeId) {
161
- continue;
162
- }
163
- try {
164
- const overlay = await resolveTopicProjectOverlay(ctx, scopeId, {
165
- idMode: "legacy",
166
- projectLikeOnly: false
167
- });
168
- if (overlay) {
169
- return {
170
- topicId: normalizeString(overlay.topicId) ?? topicId,
171
- projectId: normalizeString(overlay.projectId) ?? projectId ?? scopeId
172
- };
173
- }
174
- } catch {
175
- }
176
- }
177
- return { topicId, projectId };
178
- }
179
- async function normalizeProjectGrantRow(ctx, row) {
180
- const scope = await resolveGrantScopeIds(ctx, {
181
- topicId: row.topicId,
182
- projectId: row.projectId
183
- });
184
- return {
185
- ...row,
186
- ...scope.topicId ? { topicId: scope.topicId } : {},
187
- ...scope.projectId ?? scope.topicId ? { projectId: scope.projectId ?? scope.topicId } : {}
188
- };
189
- }
190
- async function normalizeProjectGrantRows(ctx, rows) {
191
- return await Promise.all(rows.map((row) => normalizeProjectGrantRow(ctx, row)));
192
- }
193
- async function listProjectGrantsByPrincipal(ctx, principalId) {
194
- const rows = await Promise.all(
195
- PROJECT_GRANT_STATUSES.map(
196
- (status) => ctx.db.query("projectGrants").withIndex(
197
- "by_principal_status",
198
- (q) => q.eq("principalId", principalId).eq("status", status)
199
- ).collect()
200
- )
201
- );
202
- return await normalizeProjectGrantRows(ctx, rows.flat());
203
- }
204
- async function listProjectGrantsByGroup(ctx, groupId) {
205
- const rows = await Promise.all(
206
- PROJECT_GRANT_STATUSES.map(
207
- (status) => ctx.db.query("projectGrants").withIndex(
208
- "by_group_status",
209
- (q) => q.eq("groupId", groupId).eq("status", status)
210
- ).collect()
211
- )
212
- );
213
- return await normalizeProjectGrantRows(ctx, rows.flat());
214
- }
215
- function buildScopeMatchers(inputScopeId, resolved) {
216
- return new Set(
217
- [inputScopeId, resolved.topicId, resolved.projectId].map((value) => normalizeString(value)).filter((value) => Boolean(value))
218
- );
219
- }
220
- function matchesResolvedScope(row, scopeIds) {
221
- const rowTopicId = normalizeString(row.topicId);
222
- const rowProjectId = normalizeString(row.projectId);
223
- return rowTopicId !== void 0 && scopeIds.has(rowTopicId) || rowProjectId !== void 0 && scopeIds.has(rowProjectId);
224
- }
225
- async function bridgeListProjectGrantsByTopicAndPrincipal(ctx, topicId, principalId) {
226
- const resolved = await resolveGrantScopeIds(ctx, { topicId });
227
- const scopeIds = buildScopeMatchers(topicId, resolved);
228
- const rows = await listProjectGrantsByPrincipal(ctx, principalId);
229
- return rows.filter((row) => matchesResolvedScope(row, scopeIds));
230
- }
231
- async function bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId) {
232
- const resolved = await resolveGrantScopeIds(ctx, { topicId });
233
- const scopeIds = buildScopeMatchers(topicId, resolved);
234
- const rows = await listProjectGrantsByGroup(ctx, groupId);
235
- return rows.filter((row) => matchesResolvedScope(row, scopeIds));
236
- }
237
- async function bridgeListProjectGrantsByPrincipalStatus(ctx, principalId, status) {
238
- const rows = await listProjectGrantsByPrincipal(ctx, principalId);
239
- return rows.filter((row) => row.status === status);
240
- }
241
- async function bridgeListProjectGrantsByGroupStatus(ctx, groupId, status) {
242
- const rows = await listProjectGrantsByGroup(ctx, groupId);
243
- return rows.filter((row) => row.status === status);
244
- }
245
- async function bridgeInsertProjectGrant(ctx, value) {
246
- const resolved = await resolveGrantScopeIds(ctx, value);
247
- return await ctx.db.insert("projectGrants", {
248
- ...value,
249
- ...resolved.topicId ? { topicId: resolved.topicId } : {},
250
- ...resolved.projectId ?? resolved.topicId ? { projectId: resolved.projectId ?? resolved.topicId } : {}
251
- });
252
- }
253
-
254
- // ../access-control/src/resolvers.ts
255
- async function findUserByClerkId(ctx, clerkId) {
256
- const normalizedClerkId = clerkId.trim();
257
- if (!normalizedClerkId) {
258
- return null;
259
- }
260
- if (typeof ctx.runQuery === "function") {
261
- try {
262
- const bridgedUser = await ctx.runQuery(api.users.getUserByClerkId, {
263
- clerkId: normalizedClerkId
264
- });
265
- if (bridgedUser) {
266
- return bridgedUser;
267
- }
268
- } catch {
269
- }
270
- }
271
- try {
272
- const users = await ctx.db.query("users").collect();
273
- return users.find((user) => String(user.clerkId ?? "") === normalizedClerkId) ?? null;
274
- } catch {
275
- return null;
276
- }
277
- }
278
- async function findUserByPrincipalId(ctx, principalId) {
279
- const normalizedPrincipalId = principalId.trim();
280
- if (!normalizedPrincipalId) {
281
- return null;
282
- }
283
- try {
284
- const users = await ctx.db.query("users").collect();
285
- return users.find(
286
- (user) => String(user.defaultPrincipalId ?? "") === normalizedPrincipalId
287
- ) ?? null;
288
- } catch {
289
- return null;
290
- }
291
- }
292
- async function findAgentByPrincipalId(ctx, principalId) {
293
- const normalizedPrincipalId = principalId.trim();
294
- if (!normalizedPrincipalId) {
295
- return null;
296
- }
297
- if (typeof ctx.runQuery === "function") {
298
- try {
299
- const bridgedAgent = await ctx.runQuery(
300
- api.agents.getAgentByPrincipalId,
301
- {
302
- principalId: normalizedPrincipalId
303
- }
304
- );
305
- if (bridgedAgent) {
306
- return bridgedAgent;
307
- }
308
- } catch {
309
- }
310
- }
311
- try {
312
- const agents = await ctx.db.query("agents").collect();
313
- return agents.find(
314
- (agent) => String(agent.principalId ?? "") === normalizedPrincipalId
315
- ) ?? null;
316
- } catch {
317
- return null;
318
- }
319
- }
320
- function defaultResolvers() {
321
- return {
322
- async getProject(ctx, topicId) {
323
- return await resolveTopicProjectOverlay(ctx, topicId, {
324
- idMode: "legacy",
325
- projectLikeOnly: false
326
- });
327
- },
328
- async listTopics(ctx) {
329
- return await listTopicProjectOverlays(ctx, { idMode: "legacy" });
330
- },
331
- async listTopicsByOwner(ctx, ownerId) {
332
- const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
333
- return topics.filter((topic) => topic.ownerId === ownerId);
334
- },
335
- async listTopicsByVisibility(ctx, visibility) {
336
- const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
337
- return topics.filter((topic) => topic.visibility === visibility);
338
- },
339
- async listProjectGrantsByProjectAndPrincipal(ctx, topicId, principalId) {
340
- return await bridgeListProjectGrantsByTopicAndPrincipal(
341
- ctx,
342
- topicId,
343
- principalId
344
- );
345
- },
346
- async listProjectGrantsByProjectAndGroup(ctx, topicId, groupId) {
347
- return await bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId);
348
- },
349
- async listProjectGrantsByPrincipalStatus(ctx, principalId, status) {
350
- return await bridgeListProjectGrantsByPrincipalStatus(
351
- ctx,
352
- principalId,
353
- status
354
- );
355
- },
356
- async listProjectGrantsByGroupStatus(ctx, groupId, status) {
357
- return await bridgeListProjectGrantsByGroupStatus(ctx, groupId, status);
358
- },
359
- async insertProjectGrant(ctx, value) {
360
- return await bridgeInsertProjectGrant(ctx, value);
361
- },
362
- async getAgentByPrincipalId(ctx, principalId) {
363
- return await findAgentByPrincipalId(ctx, principalId);
364
- },
365
- async getUserByClerkId(ctx, clerkId) {
366
- return await findUserByClerkId(ctx, clerkId);
367
- },
368
- async getUserByPrincipalId(ctx, principalId) {
369
- return await findUserByPrincipalId(ctx, principalId);
370
- }
371
- };
372
- }
373
- var resolverOverrides = {};
374
- function resolveAccessControlAppResolvers(_ctx) {
375
- return {
376
- ...defaultResolvers(),
377
- ...resolverOverrides
378
- };
379
- }
380
-
381
- // ../access-control/src/principalContext.ts
382
- function requireCanonicalResolvedUser(user, clerkId) {
383
- const resolved = user;
384
- if (!resolved) {
385
- throw new Error(
386
- `[AccessControl] Canonical user identity required for ${clerkId}. Sync users.upsertUser before user-bound access checks.`
387
- );
388
- }
389
- const { mcRole, defaultTenantId, defaultWorkspaceId, defaultPrincipalId } = resolved;
390
- if (mcRole !== "platform_admin" && mcRole !== "tenant_admin" && mcRole !== "workspace_admin" && mcRole !== "editor" && mcRole !== "viewer" && mcRole !== "auditor" && mcRole !== "service_agent") {
391
- throw new Error(
392
- `[AccessControl] Canonical MC role required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
393
- );
394
- }
395
- if (typeof defaultTenantId !== "string" || defaultTenantId.trim().length === 0) {
396
- throw new Error(
397
- `[AccessControl] Canonical home tenant required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
398
- );
399
- }
400
- if (typeof defaultWorkspaceId !== "string" || defaultWorkspaceId.trim().length === 0) {
401
- throw new Error(
402
- `[AccessControl] Canonical home workspace required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
403
- );
404
- }
405
- if (typeof defaultPrincipalId !== "string" || defaultPrincipalId.trim().length === 0) {
406
- throw new Error(
407
- `[AccessControl] Canonical federated principal required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
408
- );
409
- }
410
- return {
411
- mcRole,
412
- defaultTenantId: defaultTenantId.trim(),
413
- defaultWorkspaceId: defaultWorkspaceId.trim(),
414
- defaultPrincipalId: defaultPrincipalId.trim()
415
- };
416
- }
417
- function isPrincipalIdInput(value) {
418
- return value.startsWith("user:") || value.startsWith("group:") || value.startsWith("service:") || value.startsWith("agent:") || value.startsWith("external_viewer:");
419
- }
420
- async function resolveCanonicalUserRecord(ctx, actorId) {
421
- const normalizedActorId = actorId.trim();
422
- const clerkId = isPrincipalIdInput(normalizedActorId) && normalizedActorId.startsWith("user:") ? normalizedActorId.slice("user:".length) : normalizedActorId;
423
- const resolvers = resolveAccessControlAppResolvers();
424
- const resolvedByClerkId = await resolvers.getUserByClerkId(ctx, clerkId);
425
- if (resolvedByClerkId) {
426
- return {
427
- resolvedUser: resolvedByClerkId,
428
- clerkId,
429
- contextClerkId: clerkId
430
- };
431
- }
432
- const resolvedByPrincipalId = await resolvers.getUserByPrincipalId(
433
- ctx,
434
- normalizedActorId
435
- );
436
- return {
437
- resolvedUser: resolvedByPrincipalId ?? null,
438
- clerkId,
439
- contextClerkId: normalizedActorId.startsWith("user:") && clerkId.length > 0 ? clerkId : normalizedActorId
440
- };
441
- }
442
- function uniqRoles(roles) {
443
- const roleSet = /* @__PURE__ */ new Set();
444
- for (const role of roles) {
445
- if (role === "platform_admin" || role === "tenant_admin" || role === "workspace_admin" || role === "editor" || role === "viewer" || role === "auditor" || role === "service_agent") {
446
- roleSet.add(role);
447
- }
448
- }
449
- return [...roleSet];
450
- }
451
- function normalizeGroupIds(value) {
452
- if (!Array.isArray(value)) {
453
- return [];
454
- }
455
- return [...new Set(
456
- value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean)
457
- )];
458
- }
459
- function requireServiceAgentUser(user, actorId) {
460
- const canonicalUser = requireCanonicalResolvedUser(user, actorId);
461
- if (canonicalUser.mcRole !== "service_agent") {
462
- throw new Error(
463
- `[AccessControl] Canonical service_agent identity required for ${actorId}. Sync users.upsertUser before agent-bound access checks.`
464
- );
465
- }
466
- return canonicalUser;
467
- }
468
- function requireCanonicalResolvedAgent(agent, actorId) {
469
- const resolved = agent;
470
- if (!resolved) {
471
- throw new Error(
472
- `[AccessControl] Agent "${actorId}" not found in agents or users table.`
473
- );
474
- }
475
- if (typeof resolved.principalId !== "string" || resolved.principalId.trim().length === 0) {
476
- throw new Error(
477
- `[AccessControl] Canonical agent principalId required for ${actorId}.`
478
- );
479
- }
480
- if (typeof resolved.tenantId !== "string" || resolved.tenantId.trim().length === 0) {
481
- throw new Error(
482
- `[AccessControl] Canonical home tenant required for ${actorId}.`
483
- );
484
- }
485
- if (typeof resolved.workspaceId !== "string" || resolved.workspaceId.trim().length === 0) {
486
- throw new Error(
487
- `[AccessControl] Canonical home workspace required for ${actorId}.`
488
- );
489
- }
490
- return {
491
- principalId: resolved.principalId.trim(),
492
- tenantId: resolved.tenantId.trim(),
493
- workspaceId: resolved.workspaceId.trim(),
494
- roles: uniqRoles(Array.isArray(resolved.roles) ? resolved.roles : []) ?? ["service_agent"],
495
- groupIds: normalizeGroupIds(resolved.groupIds)
496
- };
497
- }
498
- async function resolvePrincipalContext(ctx, actorId) {
499
- if (actorId.startsWith("agent:")) {
500
- const resolvers = resolveAccessControlAppResolvers();
501
- const resolvedAgent = await resolvers.getAgentByPrincipalId(ctx, actorId);
502
- if (resolvedAgent) {
503
- const agent = requireCanonicalResolvedAgent(
504
- resolvedAgent,
505
- actorId
506
- );
507
- return {
508
- principalId: agent.principalId,
509
- principalType: "service",
510
- clerkId: actorId,
511
- tenantId: agent.tenantId,
512
- workspaceId: agent.workspaceId,
513
- roles: agent.roles.length > 0 ? agent.roles : ["service_agent"],
514
- groupIds: agent.groupIds,
515
- isPlatformAdmin: false,
516
- isTenantAdmin: false,
517
- isWorkspaceAdmin: false,
518
- isSystemFallback: false
519
- };
520
- }
521
- const resolvedUser2 = await resolvers.getUserByClerkId(
522
- ctx,
523
- actorId
524
- );
525
- if (!resolvedUser2) {
526
- throw new Error(
527
- `[AccessControl] Agent "${actorId}" not found in agents or users table.`
528
- );
529
- }
530
- const user2 = requireServiceAgentUser(
531
- resolvedUser2,
532
- actorId
533
- );
534
- console.warn(
535
- `[AccessControl] Deprecated legacy service-agent fallback for ${actorId}; migrate this principal into identity.agents.`
536
- );
537
- return {
538
- principalId: user2.defaultPrincipalId,
539
- principalType: "service",
540
- clerkId: actorId,
541
- tenantId: user2.defaultTenantId,
542
- workspaceId: user2.defaultWorkspaceId,
543
- roles: ["service_agent"],
544
- groupIds: normalizeGroupIds(resolvedUser2?.principalGroupIds),
545
- isPlatformAdmin: false,
546
- isTenantAdmin: false,
547
- isWorkspaceAdmin: false,
548
- isSystemFallback: false
549
- };
550
- }
551
- const {
552
- resolvedUser,
553
- contextClerkId
554
- } = await resolveCanonicalUserRecord(ctx, actorId);
555
- const user = requireCanonicalResolvedUser(
556
- resolvedUser,
557
- contextClerkId
558
- );
559
- if (!user.defaultPrincipalId) {
560
- throw new Error(
561
- `[AccessControl] Canonical federated principal required for ${contextClerkId}. Re-sync Master Control identity before user-bound access checks.`
562
- );
563
- }
564
- if (user.mcRole === "service_agent") {
565
- return {
566
- principalId: user.defaultPrincipalId,
567
- principalType: "service",
568
- clerkId: contextClerkId,
569
- tenantId: user.defaultTenantId,
570
- workspaceId: user.defaultWorkspaceId,
571
- roles: ["service_agent"],
572
- groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
573
- isPlatformAdmin: false,
574
- isTenantAdmin: false,
575
- isWorkspaceAdmin: false,
576
- isSystemFallback: false
577
- };
578
- }
579
- const principalId = user.defaultPrincipalId;
580
- const effectiveRole = user.mcRole;
581
- const roles = effectiveRole === "platform_admin" ? ["platform_admin", "tenant_admin"] : effectiveRole === "tenant_admin" ? ["tenant_admin"] : [effectiveRole];
582
- const tenantId = user.defaultTenantId;
583
- const workspaceId = user.defaultWorkspaceId;
584
- const isPlatformAdmin = effectiveRole === "platform_admin";
585
- return {
586
- principalId,
587
- principalType: "user",
588
- clerkId: contextClerkId,
589
- tenantId,
590
- workspaceId,
591
- roles: uniqRoles(roles),
592
- groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
593
- isPlatformAdmin,
594
- isTenantAdmin: isPlatformAdmin || effectiveRole === "tenant_admin",
595
- isWorkspaceAdmin: isPlatformAdmin || effectiveRole === "tenant_admin" || effectiveRole === "workspace_admin",
596
- isSystemFallback: false
597
- };
598
- }
599
-
600
- // ../access-control/src/access.ts
601
- function isTopicInPrincipalTenant(topic, principalTenantId) {
602
- if (!topic.tenantId) {
603
- return false;
604
- }
605
- if (!principalTenantId) {
606
- return false;
607
- }
608
- return String(topic.tenantId) === String(principalTenantId);
609
- }
610
- function isTopicInPrincipalWorkspace(topic, principalWorkspaceId) {
611
- if (!topic.workspaceId) {
612
- return false;
613
- }
614
- if (!principalWorkspaceId) {
615
- return false;
616
- }
617
- return String(topic.workspaceId) === String(principalWorkspaceId);
618
- }
619
- function isLegacyUnscopedTopic(topic) {
620
- return !topic.tenantId || !topic.workspaceId;
621
- }
622
- function isGrantScopeAlignedToTopic(topic, grant) {
623
- if (topic.tenantId && grant.tenantId && String(topic.tenantId) !== String(grant.tenantId)) {
624
- return false;
625
- }
626
- if (topic.workspaceId && grant.workspaceId && String(topic.workspaceId) !== String(grant.workspaceId)) {
627
- return false;
628
- }
629
- return true;
630
- }
631
- function isGrantSourceAllowedForVisibility(visibility, source) {
632
- if (source !== "external_share") {
633
- return true;
634
- }
635
- return visibility === "external" || visibility === "public";
636
- }
637
- function isGrantActive(grant) {
638
- if (grant.status !== "active") {
639
- return false;
640
- }
641
- if (grant.expiresAt !== void 0 && grant.expiresAt <= Date.now()) {
642
- return false;
643
- }
644
- return true;
645
- }
646
- async function hasPrincipalGrant(ctx, args) {
647
- const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndPrincipal(
648
- ctx,
649
- args.topic._id,
650
- args.principalId
651
- );
652
- if (grants.some(
653
- (grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
654
- args.topic.visibility,
655
- grant.source
656
- ) && (!args.principalIsExternal || args.topic.visibility === "public" || grant.source === "external_share")
657
- )) {
658
- return true;
659
- }
660
- return false;
661
- }
662
- async function hasGroupGrant(ctx, args) {
663
- if (args.groupIds.length === 0) {
664
- return false;
665
- }
666
- for (const groupId of args.groupIds) {
667
- const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndGroup(ctx, args.topic._id, groupId);
668
- if (grants.some(
669
- (grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
670
- args.topic.visibility,
671
- grant.source
672
- )
673
- )) {
674
- return true;
675
- }
676
- }
677
- return false;
678
- }
679
- function isExternalPrincipal(_ctx, _args) {
680
- return false;
681
- }
682
- async function evaluateTopicAccessDetailed(ctx, args) {
683
- if (args.legacyUserId) {
684
- return {
685
- hasAccess: true,
686
- isAdmin: false,
687
- isOwner: false,
688
- isShared: false,
689
- hasGrant: true,
690
- isFirmVisible: true,
691
- isExternalVisible: false,
692
- isPublicVisible: false,
693
- isTenantScopeMatch: true,
694
- isWorkspaceScopeMatch: true,
695
- isPrincipalExternal: false
696
- };
697
- }
698
- const topic = await resolveAccessControlAppResolvers().getProject(
699
- ctx,
700
- args.topicId
701
- );
702
- if (!topic) {
703
- return {
704
- hasAccess: false,
705
- isAdmin: false,
706
- isOwner: false,
707
- isShared: false,
708
- hasGrant: false,
709
- isFirmVisible: false,
710
- isExternalVisible: false,
711
- isPublicVisible: false,
712
- isTenantScopeMatch: false,
713
- isWorkspaceScopeMatch: false,
714
- isPrincipalExternal: false
715
- };
716
- }
717
- const { principalContext, legacyUserId } = args;
718
- const userIsAdmin = principalContext.isPlatformAdmin;
719
- const isOwner = topic.ownerId === legacyUserId;
720
- const isShared = (topic.sharedWith ?? []).includes(legacyUserId);
721
- const principalIsExternal = await isExternalPrincipal(ctx, {
722
- groupIds: principalContext.groupIds,
723
- topicTenantId: topic.tenantId,
724
- topicWorkspaceId: topic.workspaceId
725
- });
726
- const hasPrincipalGrantResult = await hasPrincipalGrant(ctx, {
727
- topic,
728
- principalId: principalContext.principalId,
729
- principalIsExternal
730
- });
731
- const hasGroupGrantResult = await hasGroupGrant(ctx, {
732
- topic,
733
- groupIds: principalContext.groupIds
734
- });
735
- const hasGrant = isShared || hasPrincipalGrantResult || hasGroupGrantResult;
736
- const legacyUnscoped = isLegacyUnscopedTopic(topic);
737
- const tenantScopeMatch = isTopicInPrincipalTenant(
738
- topic,
739
- principalContext.tenantId
740
- );
741
- const workspaceScopeMatch = isTopicInPrincipalWorkspace(
742
- topic,
743
- principalContext.workspaceId
744
- );
745
- const isPublicVisible = topic.visibility === "public";
746
- const isFirmVisible = topic.visibility === "firm" && !legacyUnscoped && tenantScopeMatch && workspaceScopeMatch && !principalIsExternal;
747
- const hasScopedGrant = hasGrant && (legacyUnscoped || tenantScopeMatch && workspaceScopeMatch);
748
- const isExternalVisible = topic.visibility === "external" && hasScopedGrant;
749
- const hasAccess = userIsAdmin || isOwner || hasScopedGrant || isPublicVisible || isFirmVisible;
750
- return {
751
- hasAccess,
752
- isAdmin: userIsAdmin,
753
- isOwner,
754
- isShared,
755
- hasGrant,
756
- isFirmVisible,
757
- isExternalVisible,
758
- isPublicVisible,
759
- isTenantScopeMatch: tenantScopeMatch,
760
- isWorkspaceScopeMatch: workspaceScopeMatch,
761
- isPrincipalExternal: principalIsExternal
762
- };
763
- }
764
- async function checkTopicAccessDetailed(ctx, topicId, userId) {
765
- const principalContext = await resolvePrincipalContext(ctx, userId);
766
- return evaluateTopicAccessDetailed(ctx, {
767
- topicId,
768
- legacyUserId: userId,
769
- principalContext
770
- });
771
- }
772
- async function checkTopicAccess(ctx, topicId, userId) {
773
- const result = await checkTopicAccessDetailed(ctx, topicId, userId);
774
- return result.hasAccess;
775
- }
776
- var checkProjectAccess = checkTopicAccess;
777
-
778
- // ../access-control/src/auth.ts
779
- async function getCurrentUserId(ctx) {
780
- const identity = await ctx.auth.getUserIdentity();
781
- return identity?.subject ?? null;
782
- }
783
- var permissiveReturn = v.optional(v.any());
784
- var looseJsonObject = v.record(v.string(), v.any());
785
- var looseJsonArray = v.array(v.any());
786
- v.union(
787
- v.string(),
788
- v.number(),
789
- v.boolean(),
790
- v.null(),
791
- looseJsonObject,
792
- looseJsonArray
793
- );
794
- var api2 = anyApi;
795
- componentsGeneric();
796
10
  var internal = anyApi;
797
11
  var mutation = mutationGeneric;
798
12
  var query = queryGeneric;
@@ -899,7 +113,7 @@ async function resolveTopicOntologyInternal(ctx, topicId) {
899
113
  "by_ontologyId",
900
114
  (q) => q.eq("ontologyId", current?.ontologyId)
901
115
  ).collect();
902
- const published = versions.filter((v4) => v4.status === "published").sort((a, b) => (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
116
+ const published = versions.filter((v3) => v3.status === "published").sort((a, b) => (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
903
117
  const latestPublished = published[0] ?? null;
904
118
  return {
905
119
  ontologyId: ontologyDef._id,
@@ -938,48 +152,48 @@ async function validateEntityTypeForTopic(ctx, topicId, nodeType) {
938
152
  }
939
153
 
940
154
  // src/topicProjectOverlay.ts
941
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
942
- function readNonEmptyString2(value) {
155
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
156
+ function readNonEmptyString(value) {
943
157
  if (typeof value !== "string") {
944
158
  return;
945
159
  }
946
160
  const normalized = value.trim();
947
161
  return normalized.length > 0 ? normalized : void 0;
948
162
  }
949
- function readStringArray2(value) {
163
+ function readStringArray(value) {
950
164
  if (!Array.isArray(value)) {
951
165
  return [];
952
166
  }
953
- return value.map((entry) => readNonEmptyString2(entry)).filter((entry) => Boolean(entry));
167
+ return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
954
168
  }
955
- function readMetadata2(topic) {
169
+ function readMetadata(topic) {
956
170
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
957
171
  }
958
- function readLegacyProjectId2(value) {
172
+ function readLegacyProjectId(value) {
959
173
  if (!value) {
960
174
  return;
961
175
  }
962
- return readNonEmptyString2(value[LEGACY_SCOPE_FIELD2]);
176
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
963
177
  }
964
- function coerceVisibility2(value) {
178
+ function coerceVisibility(value) {
965
179
  return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
966
180
  }
967
- function coerceStatus2(value) {
181
+ function coerceStatus(value) {
968
182
  return value === "active" || value === "archived" || value === "watching" ? value : void 0;
969
183
  }
970
- function mapProjectType2(topic, metadata) {
971
- const explicit = readNonEmptyString2(metadata.projectType);
184
+ function mapProjectType(topic, metadata) {
185
+ const explicit = readNonEmptyString(metadata.projectType);
972
186
  if (explicit) {
973
187
  return explicit;
974
188
  }
975
189
  if (topic.type === "theme") {
976
190
  return "thematic";
977
191
  }
978
- return readNonEmptyString2(topic.type) || "general";
192
+ return readNonEmptyString(topic.type) || "general";
979
193
  }
980
- function isProjectLikeTopic2(topic) {
981
- const metadata = readMetadata2(topic);
982
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId2(topic) !== void 0 || readNonEmptyString2(metadata.projectType) !== void 0;
194
+ function isProjectLikeTopic(topic) {
195
+ const metadata = readMetadata(topic);
196
+ return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
983
197
  }
984
198
  function isMissingLucernChildComponentError(error) {
985
199
  const message = error instanceof Error ? error.message : String(error);
@@ -987,7 +201,7 @@ function isMissingLucernChildComponentError(error) {
987
201
  'Child component ComponentName(Identifier("lucern")) not found'
988
202
  ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
989
203
  }
990
- async function resolveTopicDoc2(ctx, scopeId) {
204
+ async function resolveTopicDoc(ctx, scopeId) {
991
205
  if (ctx?.db && typeof ctx.db.get === "function") {
992
206
  try {
993
207
  const directTopic = await ctx.db.get(scopeId);
@@ -1001,7 +215,7 @@ async function resolveTopicDoc2(ctx, scopeId) {
1001
215
  return null;
1002
216
  }
1003
217
  try {
1004
- const topic = await ctx.runQuery(api2.topics.get, {
218
+ const topic = await ctx.runQuery(api.topics.get, {
1005
219
  id: String(scopeId)
1006
220
  });
1007
221
  if (topic?.name !== void 0 && topic?.type !== void 0) {
@@ -1010,7 +224,7 @@ async function resolveTopicDoc2(ctx, scopeId) {
1010
224
  } catch {
1011
225
  }
1012
226
  try {
1013
- const topic = await ctx.runQuery(api2.topics.getByLegacyScopeId, {
227
+ const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
1014
228
  projectId: String(scopeId)
1015
229
  });
1016
230
  if (topic?.name !== void 0 && topic?.type !== void 0) {
@@ -1020,14 +234,14 @@ async function resolveTopicDoc2(ctx, scopeId) {
1020
234
  }
1021
235
  return null;
1022
236
  }
1023
- function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1024
- const metadata = readMetadata2(topic);
237
+ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
238
+ const metadata = readMetadata(topic);
1025
239
  const topicId = String(topic._id);
1026
- const legacyProjectId = readLegacyProjectId2(topic) || readLegacyProjectId2(metadata) || readNonEmptyString2(metadata.legacyProjectId);
240
+ const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
1027
241
  const storageProjectId = legacyProjectId || topicId;
1028
242
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
1029
- const visibility = coerceVisibility2(topic.visibility) || coerceVisibility2(metadata.visibility) || "private";
1030
- const status = coerceStatus2(topic.status) || coerceStatus2(metadata.status) || "active";
243
+ const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
244
+ const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
1031
245
  const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
1032
246
  const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
1033
247
  return {
@@ -1037,16 +251,16 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1037
251
  topicId,
1038
252
  storageProjectId,
1039
253
  legacyProjectId,
1040
- name: readNonEmptyString2(topic.name) || "Untitled Theme",
1041
- type: mapProjectType2(topic, metadata),
1042
- description: readNonEmptyString2(topic.description),
1043
- ownerId: readNonEmptyString2(metadata.ownerId) || readNonEmptyString2(topic.createdBy) || "system",
1044
- sharedWith: readStringArray2(metadata.sharedWith),
254
+ name: readNonEmptyString(topic.name) || "Untitled Theme",
255
+ type: mapProjectType(topic, metadata),
256
+ description: readNonEmptyString(topic.description),
257
+ ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
258
+ sharedWith: readStringArray(metadata.sharedWith),
1045
259
  visibility,
1046
- tenantId: readNonEmptyString2(topic.tenantId) || readNonEmptyString2(metadata.tenantId),
1047
- workspaceId: readNonEmptyString2(topic.workspaceId) || readNonEmptyString2(metadata.workspaceId),
260
+ tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
261
+ workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
1048
262
  status,
1049
- tags: readStringArray2(metadata.tags),
263
+ tags: readStringArray(metadata.tags),
1050
264
  chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
1051
265
  artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
1052
266
  lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
@@ -1055,17 +269,17 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1055
269
  updatedAt
1056
270
  };
1057
271
  }
1058
- async function resolveTopicProjectOverlay2(ctx, scopeId, options = {}) {
1059
- const topic = await resolveTopicDoc2(ctx, scopeId);
272
+ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
273
+ const topic = await resolveTopicDoc(ctx, scopeId);
1060
274
  if (!topic) {
1061
275
  return null;
1062
276
  }
1063
- if (options.projectLikeOnly !== false && !isProjectLikeTopic2(topic)) {
277
+ if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
1064
278
  return null;
1065
279
  }
1066
- return materializeTopicProjectOverlay2(topic, options.idMode);
280
+ return materializeTopicProjectOverlay(topic, options.idMode);
1067
281
  }
1068
- async function listTopicProjectOverlays2(ctx, options = {}) {
282
+ async function listTopicProjectOverlays(ctx, options = {}) {
1069
283
  let allTopics = [];
1070
284
  if (ctx?.db?.query && typeof ctx.db.query === "function") {
1071
285
  try {
@@ -1075,18 +289,18 @@ async function listTopicProjectOverlays2(ctx, options = {}) {
1075
289
  }
1076
290
  }
1077
291
  if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
1078
- allTopics = (await ctx.runQuery(api2.topics.list, {}) ?? []) || [];
292
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
1079
293
  }
1080
294
  return allTopics.filter(
1081
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic2(topic)
1082
- ).map((topic) => materializeTopicProjectOverlay2(topic, options.idMode));
295
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
296
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
1083
297
  }
1084
298
  async function patchTopicProjectOverlay(ctx, scopeId, value) {
1085
- const topic = await resolveTopicDoc2(ctx, scopeId);
299
+ const topic = await resolveTopicDoc(ctx, scopeId);
1086
300
  if (!topic) {
1087
301
  return null;
1088
302
  }
1089
- const nextMetadata = { ...readMetadata2(topic) };
303
+ const nextMetadata = { ...readMetadata(topic) };
1090
304
  const patch = {};
1091
305
  const topicUpdateArgs = {
1092
306
  id: String(topic._id)
@@ -1111,7 +325,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1111
325
  `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
1112
326
  );
1113
327
  case "status": {
1114
- const status = coerceStatus2(rawValue);
328
+ const status = coerceStatus(rawValue);
1115
329
  if (status) {
1116
330
  patch.status = status;
1117
331
  topicUpdateArgs.status = status;
@@ -1119,7 +333,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1119
333
  break;
1120
334
  }
1121
335
  case "visibility": {
1122
- const visibility = coerceVisibility2(rawValue);
336
+ const visibility = coerceVisibility(rawValue);
1123
337
  if (visibility) {
1124
338
  patch.visibility = visibility;
1125
339
  topicUpdateArgs.visibility = visibility;
@@ -1127,7 +341,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1127
341
  break;
1128
342
  }
1129
343
  case "type": {
1130
- const projectType = readNonEmptyString2(rawValue);
344
+ const projectType = readNonEmptyString(rawValue);
1131
345
  if (projectType) {
1132
346
  nextMetadata.projectType = projectType;
1133
347
  } else {
@@ -1151,7 +365,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1151
365
  topicUpdateArgs.metadata = nextMetadata;
1152
366
  if (typeof ctx.runMutation === "function") {
1153
367
  try {
1154
- await ctx.runMutation(api2.topics.update, topicUpdateArgs);
368
+ await ctx.runMutation(api.topics.update, topicUpdateArgs);
1155
369
  } catch (error) {
1156
370
  if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
1157
371
  throw error;
@@ -1165,7 +379,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
1165
379
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
1166
380
  );
1167
381
  }
1168
- return materializeTopicProjectOverlay2(
382
+ return materializeTopicProjectOverlay(
1169
383
  {
1170
384
  ...topic,
1171
385
  ...patch,
@@ -1198,10 +412,10 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
1198
412
  });
1199
413
  }
1200
414
  }
1201
- function defaultResolvers2() {
415
+ function defaultResolvers() {
1202
416
  return {
1203
417
  async getProject(ctx, projectId) {
1204
- return await resolveTopicProjectOverlay2(ctx, projectId, {
418
+ return await resolveTopicProjectOverlay(ctx, projectId, {
1205
419
  idMode: "legacy",
1206
420
  projectLikeOnly: false
1207
421
  });
@@ -1210,7 +424,7 @@ function defaultResolvers2() {
1210
424
  await patchProjectWithTolerance(ctx, projectId, value);
1211
425
  },
1212
426
  async listTopics(ctx) {
1213
- return await listTopicProjectOverlays2(ctx, {
427
+ return await listTopicProjectOverlays(ctx, {
1214
428
  idMode: "legacy"
1215
429
  });
1216
430
  },
@@ -1219,24 +433,24 @@ function defaultResolvers2() {
1219
433
  }
1220
434
  };
1221
435
  }
1222
- var resolverOverrides2 = {};
436
+ var resolverOverrides = {};
1223
437
  function resolveGraphPrimitivesAppResolvers(_ctx) {
1224
438
  return {
1225
- ...defaultResolvers2(),
1226
- ...resolverOverrides2
439
+ ...defaultResolvers(),
440
+ ...resolverOverrides
1227
441
  };
1228
442
  }
1229
- var LEGACY_SCOPE_FIELD3 = "graphScopeProjectId";
443
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
1230
444
  function asMappedProjectId(topic) {
1231
445
  if (!topic) {
1232
446
  return;
1233
447
  }
1234
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD3]);
448
+ const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
1235
449
  if (directLegacyProjectId) {
1236
450
  return directLegacyProjectId;
1237
451
  }
1238
452
  const metadata = topic.metadata || {};
1239
- const candidate = metadata[LEGACY_SCOPE_FIELD3] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
453
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
1240
454
  return candidate ? candidate : void 0;
1241
455
  }
1242
456
  function normalizeScopeValue(value) {
@@ -1265,7 +479,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
1265
479
  try {
1266
480
  return await ctx.db.query("topics").withIndex(
1267
481
  "by_graph_scope_project",
1268
- (q) => q.eq(LEGACY_SCOPE_FIELD3, scopeId)
482
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
1269
483
  ).collect();
1270
484
  } catch {
1271
485
  const topics = await ctx.db.query("topics").collect();
@@ -1281,7 +495,7 @@ async function tryResolveHostTopicById(ctx, topicId) {
1281
495
  return null;
1282
496
  }
1283
497
  try {
1284
- return await ctx.runQuery(api2.topics.get, {
498
+ return await ctx.runQuery(api.topics.get, {
1285
499
  id: topicId
1286
500
  }) ?? null;
1287
501
  } catch {
@@ -1293,7 +507,7 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
1293
507
  return null;
1294
508
  }
1295
509
  try {
1296
- return await ctx.runQuery(api2.topics.getByLegacyScopeId, {
510
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
1297
511
  projectId: legacyScopeId
1298
512
  }) ?? null;
1299
513
  } catch {