@hiai-gg/docsmint 0.6.7 → 0.7.0

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 (129) hide show
  1. package/README.md +27 -4
  2. package/backend/src/lib/api-keys.ts +14 -6
  3. package/backend/src/lib/lifecycle-service.ts +397 -73
  4. package/dist/backend/index.js +13066 -10878
  5. package/dist/backend-account-runtime-cleanup.js +152 -42
  6. package/dist/backend-api-key-facade.js +207 -61
  7. package/dist/backend-pipeline-cancellation.js +144 -42
  8. package/dist/client.d.ts +12 -2
  9. package/dist/client.js +83 -30
  10. package/dist/frontend/{CategoryDialog-CbXBMBZB.js → CategoryDialog-C67_TXf0.js} +4 -4
  11. package/dist/frontend/{ConfirmDialog-DgMTQBq4.js → ConfirmDialog-_LlrA--f.js} +3 -3
  12. package/dist/frontend/{CreateSnapshotDialog-FUq-ZfBH.js → CreateSnapshotDialog-BmCRpOMv.js} +3 -3
  13. package/dist/frontend/{DatePicker-D6E-EEtZ.js → DatePicker-DsoepNdb.js} +8 -8
  14. package/dist/frontend/{DeleteDialog-8k6JYWCx.js → DeleteDialog-L1A3FhMM.js} +1 -1
  15. package/dist/frontend/{FolderNode-DAAn_T8_.js → FolderNode-CNwi0ySr.js} +1 -1
  16. package/dist/frontend/{HiAiEditor-DSVG3GNd.js → HiAiEditor-B1EDGsnA.js} +6 -6
  17. package/dist/frontend/{SettingsDialog-BDNgf5rv.js → SettingsDialog-AP42xOGg.js} +12 -12
  18. package/dist/frontend/ShareDialog-wGTXuXFE.js +281 -0
  19. package/dist/frontend/{Sidebar-DX08utdV.js → Sidebar-lKQT3dEf.js} +17 -16
  20. package/dist/frontend/{TagCreateDialog-Bb0-Vtzh.js → TagCreateDialog-su8BhLzS.js} +3 -3
  21. package/dist/frontend/api/attachments.js +1 -1
  22. package/dist/frontend/api/settings.js +1 -1
  23. package/dist/frontend/app-shell.js +2 -2
  24. package/dist/frontend/{attachments-B8AuDjno.js → attachments-B2aH3hXF.js} +10 -9
  25. package/dist/frontend/{auth-client-Cygmp1I2.js → auth-client-CnDZwPfp.js} +11 -11
  26. package/dist/frontend/components/category-dialog.js +1 -1
  27. package/dist/frontend/components/create-snapshot-dialog.js +1 -1
  28. package/dist/frontend/components/delete-dialog.js +1 -1
  29. package/dist/frontend/components/editor/compact-editor.js +1 -1
  30. package/dist/frontend/components/editor/document-editor.js +1 -1
  31. package/dist/frontend/components/folder-node.js +1 -1
  32. package/dist/frontend/components/save-as-dialog.js +3 -3
  33. package/dist/frontend/components/settings.js +1 -1
  34. package/dist/frontend/components/share-dialog.d.ts +2 -1
  35. package/dist/frontend/components/share-dialog.js +1 -1
  36. package/dist/frontend/components/sidebar.js +1 -1
  37. package/dist/frontend/components/tag-create-dialog.js +1 -1
  38. package/dist/frontend/components/version-history.js +2 -2
  39. package/dist/frontend/{confirm-dialog-CzmoZw3a.js → confirm-dialog-BG8y2Pum.js} +4 -4
  40. package/dist/frontend/dashboard.js +1008 -998
  41. package/dist/frontend/{db-ByrlYfaI.js → db-Bo1t_76T.js} +1 -1
  42. package/dist/frontend/{dialog-Ce79C9fd.js → dialog-C2iKObEu.js} +7 -7
  43. package/dist/frontend/{dropdown-menu-CJ_7V3N0.js → dropdown-menu-BXIl2E26.js} +12 -12
  44. package/dist/frontend/{floating-layer-anchor-S5RSefGN.js → floating-layer-anchor-BGIndLY-.js} +63 -63
  45. package/dist/frontend/{identity-DyWeNzu_.js → identity-Ynrglr5i.js} +1 -1
  46. package/dist/frontend/{input-BWlOML_m.js → input-eHFb2qiL.js} +2 -2
  47. package/dist/frontend/{label-C2HfJNQ2.js → label-_I1iiaNU.js} +2 -2
  48. package/dist/frontend/offline/identity.js +1 -1
  49. package/dist/frontend/search.js +2 -2
  50. package/dist/frontend/{select-value-JCAp2PmU.js → select-value-CtMyrvDJ.js} +18 -18
  51. package/dist/frontend/{settings-DSrUl4hW.js → settings-BR48ihB4.js} +6 -23
  52. package/dist/frontend/{textarea-DOAE-h42.js → textarea-2eslfANY.js} +2 -2
  53. package/dist/frontend/{utils-BPDRytUU.js → utils-CDBqTgoV.js} +1 -1
  54. package/dist/frontend-ssr/api/attachments.js +1 -1
  55. package/dist/frontend-ssr/api/settings.js +1 -1
  56. package/dist/frontend-ssr/app-shell.js +2 -2
  57. package/dist/frontend-ssr/assets/{CategoryDialog-QHEv_9N4.js → CategoryDialog-BGuHTb3K.js} +4 -4
  58. package/dist/frontend-ssr/assets/{ConfirmDialog-BhAelejz.js → ConfirmDialog-D1BDXXll.js} +3 -3
  59. package/dist/frontend-ssr/assets/{CreateSnapshotDialog-CI8vXXcN.js → CreateSnapshotDialog-BZ45odvJ.js} +3 -3
  60. package/dist/frontend-ssr/assets/{DatePicker-D84cJ-Eq.js → DatePicker-CPtl6W5E.js} +3 -3
  61. package/dist/frontend-ssr/assets/{DeleteDialog-DG9Lm38J.js → DeleteDialog-oHT_p_vG.js} +1 -1
  62. package/dist/frontend-ssr/assets/{FolderNode-kmilhDjO.js → FolderNode-D9kgJG9d.js} +1 -1
  63. package/dist/frontend-ssr/assets/{HiAiEditor-CUOJmKzT.js → HiAiEditor-DOd2MXjD.js} +5 -5
  64. package/dist/frontend-ssr/assets/{SettingsDialog-BjJIiVLc.js → SettingsDialog-CIVbMKmf.js} +12 -12
  65. package/dist/frontend-ssr/assets/{ShareDialog-C9C-XTm4.js → ShareDialog-D2UNUbF7.js} +19 -6
  66. package/dist/frontend-ssr/assets/{Sidebar-C2sUfGNk.js → Sidebar-Bb-k2R-Z.js} +13 -12
  67. package/dist/frontend-ssr/assets/{TagCreateDialog-DUPMitlL.js → TagCreateDialog-6Gk7L3D-.js} +3 -3
  68. package/dist/frontend-ssr/assets/{attachments-Cj3fQyUp.js → attachments-BdkOp8ha.js} +5 -4
  69. package/dist/frontend-ssr/assets/{auth-client-x26kqY8Z.js → auth-client-CojKIzqy.js} +13 -13
  70. package/dist/frontend-ssr/assets/{confirm-dialog-XuyaL8sr.js → confirm-dialog-B9MVS_bF.js} +4 -4
  71. package/dist/frontend-ssr/assets/{db-CnxeO66n.js → db-BhwJPEkn.js} +1 -1
  72. package/dist/frontend-ssr/assets/{dialog-BOV1u6zP.js → dialog-1SB5neow.js} +8 -8
  73. package/dist/frontend-ssr/assets/{dropdown-menu-Dn_vQq9b.js → dropdown-menu-DqoOkdqB.js} +12 -12
  74. package/dist/frontend-ssr/assets/{floating-layer-anchor-BIAu-252.js → floating-layer-anchor-BoiiIEiK.js} +71 -71
  75. package/dist/frontend-ssr/assets/{identity-B3uHoDtf.js → identity-DcMMBKWg.js} +1 -1
  76. package/dist/frontend-ssr/assets/{input-DezGsU3y.js → input-Df-QP3Km.js} +2 -2
  77. package/dist/frontend-ssr/assets/{label-Bj8-TfFN.js → label-CbUOUz6L.js} +2 -2
  78. package/dist/frontend-ssr/assets/{select-value-DBhbkNcc.js → select-value-CXEDWrZg.js} +18 -18
  79. package/dist/frontend-ssr/assets/{settings-Bk5Hk9Vq.js → settings-Mp8EuFSn.js} +3 -21
  80. package/dist/frontend-ssr/assets/{textarea-Dev-qSEc.js → textarea-CHh8NuSS.js} +2 -2
  81. package/dist/frontend-ssr/assets/{utils-DtlPPXpJ.js → utils-DtX0ta7y.js} +1 -1
  82. package/dist/frontend-ssr/components/category-dialog.js +1 -1
  83. package/dist/frontend-ssr/components/create-snapshot-dialog.js +1 -1
  84. package/dist/frontend-ssr/components/delete-dialog.js +1 -1
  85. package/dist/frontend-ssr/components/editor/compact-editor.js +1 -1
  86. package/dist/frontend-ssr/components/editor/document-editor.js +1 -1
  87. package/dist/frontend-ssr/components/folder-node.js +1 -1
  88. package/dist/frontend-ssr/components/save-as-dialog.js +3 -3
  89. package/dist/frontend-ssr/components/settings.js +1 -1
  90. package/dist/frontend-ssr/components/share-dialog.js +1 -1
  91. package/dist/frontend-ssr/components/sidebar.js +1 -1
  92. package/dist/frontend-ssr/components/tag-create-dialog.js +1 -1
  93. package/dist/frontend-ssr/components/version-history.js +2 -2
  94. package/dist/frontend-ssr/dashboard.js +31 -29
  95. package/dist/frontend-ssr/offline/identity.js +1 -1
  96. package/dist/frontend-ssr/search.js +2 -2
  97. package/dist/index.d.ts +5 -5
  98. package/dist/index.js +2 -2
  99. package/dist/lifecycle-persistent.d.ts +1 -1
  100. package/dist/lifecycle-runtime.js +52659 -338
  101. package/dist/mcp-cli.js +1056 -0
  102. package/dist/mcp-server.d.ts +39 -0
  103. package/dist/mcp-server.js +1053 -0
  104. package/dist/storage-quota.d.ts +5 -1
  105. package/dist/types.d.ts +7 -0
  106. package/dist/workspace.d.ts +11 -2
  107. package/dist/workspace.js +82 -10
  108. package/package.json +7 -13
  109. package/packages/cli/src/index.ts +1 -1
  110. package/packages/db/src/client.ts +56 -5
  111. package/packages/db/src/schema.ts +192 -1
  112. package/packages/db/src/with-tenant.ts +20 -2
  113. package/server.json +2 -2
  114. package/dist/frontend/ShareDialog-2Mty7hm4.js +0 -258
  115. package/packages/mcp-server/src/capabilities.ts +0 -189
  116. package/packages/mcp-server/src/client.ts +0 -225
  117. package/packages/mcp-server/src/index.ts +0 -8
  118. package/packages/mcp-server/src/server.ts +0 -87
  119. package/packages/mcp-server/src/tools/create-document.ts +0 -34
  120. package/packages/mcp-server/src/tools/create-folder.ts +0 -31
  121. package/packages/mcp-server/src/tools/create-snapshot.ts +0 -27
  122. package/packages/mcp-server/src/tools/export-document.ts +0 -22
  123. package/packages/mcp-server/src/tools/get-document.ts +0 -22
  124. package/packages/mcp-server/src/tools/list-documents.ts +0 -34
  125. package/packages/mcp-server/src/tools/list-folders.ts +0 -26
  126. package/packages/mcp-server/src/tools/search.ts +0 -39
  127. package/packages/mcp-server/src/tools/update-document.ts +0 -38
  128. package/packages/mcp-server/src/tools/version-history.ts +0 -27
  129. package/packages/mcp-server/src/types.ts +0 -126
@@ -17,49 +17,53 @@ var __export = (target, all) => {
17
17
  // ../db/src/schema.ts
18
18
  var exports_schema = {};
19
19
  __export(exports_schema, {
20
- versions: () => versions,
21
- versionRelations: () => versionRelations,
22
- verifications: () => verifications,
23
- users: () => users,
24
- tags: () => tags,
25
- tagRelations: () => tagRelations,
26
- shareRoleEnum: () => shareRoleEnum,
27
- shareLinks: () => shareLinks,
28
- shareLinkRelations: () => shareLinkRelations,
29
- shareGrantStatusEnum: () => shareGrantStatusEnum,
30
- shareAccessModeEnum: () => shareAccessModeEnum,
31
- sessions: () => sessions,
32
- pipelineStatusEnum: () => pipelineStatusEnum,
33
- pipelineStageEnum: () => pipelineStageEnum,
34
- lifecycleOperations: () => lifecycleOperations,
35
- lifecycleOperationStatusEnum: () => lifecycleOperationStatusEnum,
36
- lifecycleOperationKindEnum: () => lifecycleOperationKindEnum,
37
- guestAccessRelations: () => guestAccessRelations,
38
- guestAccess: () => guestAccess,
39
- folders: () => folders,
40
- folderRelations: () => folderRelations,
41
- embeddingStatusEnum: () => embeddingStatusEnum,
42
- documents: () => documents,
43
- documentVisibilityEnum: () => documentVisibilityEnum,
44
- documentTags: () => documentTags,
45
- documentTagRelations: () => documentTagRelations,
46
- documentRelations: () => documentRelations,
47
- documentPipelineRuns: () => documentPipelineRuns,
48
- documentPipelineBatches: () => documentPipelineBatches,
49
- documentKnowledgeSummaries: () => documentKnowledgeSummaries,
50
- documentEmbeddings: () => documentEmbeddings,
51
- documentEmbeddingRelations: () => documentEmbeddingRelations,
52
- documentCreateOperations: () => documentCreateOperations,
53
- categoryRelations: () => categoryRelations,
54
- categories: () => categories,
55
- auditLog: () => auditLog,
56
- attachments: () => attachments,
57
- attachmentRelations: () => attachmentRelations,
58
- apiKeys: () => apiKeys,
20
+ accounts: () => accounts,
59
21
  apiKeyRelations: () => apiKeyRelations,
60
- accounts: () => accounts
22
+ apiKeys: () => apiKeys,
23
+ attachmentRelations: () => attachmentRelations,
24
+ attachmentStorageCleanupOutbox: () => attachmentStorageCleanupOutbox,
25
+ attachments: () => attachments,
26
+ auditLog: () => auditLog,
27
+ categories: () => categories,
28
+ categoryRelations: () => categoryRelations,
29
+ documentCreateOperations: () => documentCreateOperations,
30
+ documentEmbeddingRelations: () => documentEmbeddingRelations,
31
+ documentEmbeddings: () => documentEmbeddings,
32
+ documentKnowledgeSummaries: () => documentKnowledgeSummaries,
33
+ documentPipelineBatches: () => documentPipelineBatches,
34
+ documentPipelineRuns: () => documentPipelineRuns,
35
+ documentRelations: () => documentRelations,
36
+ documentTagRelations: () => documentTagRelations,
37
+ documentTags: () => documentTags,
38
+ documentVisibilityEnum: () => documentVisibilityEnum,
39
+ documents: () => documents,
40
+ embeddingStatusEnum: () => embeddingStatusEnum,
41
+ folderRelations: () => folderRelations,
42
+ folders: () => folders,
43
+ guestAccess: () => guestAccess,
44
+ guestAccessRelations: () => guestAccessRelations,
45
+ lifecycleOperationKindEnum: () => lifecycleOperationKindEnum,
46
+ lifecycleOperationStatusEnum: () => lifecycleOperationStatusEnum,
47
+ lifecycleOperations: () => lifecycleOperations,
48
+ metadataReembedOutbox: () => metadataReembedOutbox,
49
+ pendingAttachmentCleanupAuthorizations: () => pendingAttachmentCleanupAuthorizations,
50
+ pendingAttachmentUploads: () => pendingAttachmentUploads,
51
+ pipelineStageEnum: () => pipelineStageEnum,
52
+ pipelineStatusEnum: () => pipelineStatusEnum,
53
+ sessions: () => sessions,
54
+ shareAccessModeEnum: () => shareAccessModeEnum,
55
+ shareGrantStatusEnum: () => shareGrantStatusEnum,
56
+ shareLinkRelations: () => shareLinkRelations,
57
+ shareLinks: () => shareLinks,
58
+ shareRoleEnum: () => shareRoleEnum,
59
+ tagRelations: () => tagRelations,
60
+ tags: () => tags,
61
+ users: () => users,
62
+ verifications: () => verifications,
63
+ versionRelations: () => versionRelations,
64
+ versions: () => versions
61
65
  });
62
- import { pgTable, uuid, text, timestamp, bigint, jsonb, index, uniqueIndex, customType, boolean, check, integer, pgEnum } from "drizzle-orm/pg-core";
66
+ import { pgTable, uuid, text, timestamp, bigint, jsonb, index, uniqueIndex, customType, boolean, check, integer, pgEnum, primaryKey } from "drizzle-orm/pg-core";
63
67
  import { relations, sql } from "drizzle-orm";
64
68
  var vector = customType({
65
69
  dataType(config) {
@@ -227,6 +231,7 @@ var documents = pgTable("documents", {
227
231
  activeEmbeddingGeneration: uuid("active_embedding_generation"),
228
232
  pendingEmbeddingGeneration: uuid("pending_embedding_generation"),
229
233
  embeddingProfile: text("embedding_profile"),
234
+ embeddingContextHash: text("embedding_context_hash"),
230
235
  embeddingErrorCode: text("embedding_error_code"),
231
236
  embeddingUpdatedAt: timestamp("embedding_updated_at"),
232
237
  deletedAt: timestamp("deleted_at"),
@@ -265,6 +270,8 @@ var documentPipelineRuns = pgTable("document_pipeline_runs", {
265
270
  generationId: uuid("generation_id").notNull(),
266
271
  revision: text("revision").notNull(),
267
272
  source: text("source").notNull(),
273
+ embeddingContextHash: text("embedding_context_hash"),
274
+ refreshMode: text("refresh_mode").notNull().default("full"),
268
275
  status: pipelineStatusEnum("status").notNull().default("pending"),
269
276
  prepareStatus: pipelineStatusEnum("prepare_status").notNull().default("pending"),
270
277
  embedStatus: pipelineStatusEnum("embed_status").notNull().default("pending"),
@@ -285,7 +292,8 @@ var documentPipelineRuns = pgTable("document_pipeline_runs", {
285
292
  updatedAt: timestamp("updated_at").defaultNow().notNull()
286
293
  }, (table) => [
287
294
  uniqueIndex("document_pipeline_runs_document_generation_idx").on(table.documentId, table.generationId),
288
- index("document_pipeline_runs_owner_status_updated_idx").on(table.ownerId, table.status, table.updatedAt)
295
+ index("document_pipeline_runs_owner_status_updated_idx").on(table.ownerId, table.status, table.updatedAt),
296
+ check("document_pipeline_runs_refresh_mode_check", sql`${table.refreshMode} in ('incremental', 'full')`)
289
297
  ]);
290
298
  var documentPipelineBatches = pgTable("document_pipeline_batches", {
291
299
  id: uuid("id").primaryKey().defaultRandom(),
@@ -311,6 +319,19 @@ var documentPipelineBatches = pgTable("document_pipeline_batches", {
311
319
  index("document_pipeline_batches_stage_status_available_idx").on(table.stage, table.status, table.availableAt),
312
320
  index("document_pipeline_batches_document_id_idx").on(table.documentId)
313
321
  ]);
322
+ var metadataReembedOutbox = pgTable("metadata_reembed_outbox", {
323
+ id: uuid("id").primaryKey(),
324
+ operationId: uuid("operation_id").notNull(),
325
+ documentId: uuid("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
326
+ ownerId: uuid("owner_id").notNull().references(() => users.id, { onDelete: "cascade" }),
327
+ workspaceId: text("workspace_id"),
328
+ revision: text("revision").notNull(),
329
+ createdAt: timestamp("created_at").defaultNow().notNull()
330
+ }, (table) => [
331
+ uniqueIndex("metadata_reembed_outbox_operation_document_idx").on(table.operationId, table.documentId),
332
+ index("metadata_reembed_outbox_operation_id_idx").on(table.operationId, table.id),
333
+ index("metadata_reembed_outbox_created_id_idx").on(table.createdAt, table.id)
334
+ ]);
314
335
  var documentKnowledgeSummaries = pgTable("document_knowledge_summaries", {
315
336
  id: uuid().primaryKey().defaultRandom(),
316
337
  document_id: uuid().notNull().references(() => documents.id, { onDelete: "cascade" }),
@@ -447,6 +468,7 @@ var attachments = pgTable("attachments", {
447
468
  id: uuid("id").primaryKey().defaultRandom(),
448
469
  documentId: uuid("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
449
470
  workspaceId: text("workspace_id"),
471
+ uploadedBy: uuid("uploaded_by").notNull().references(() => users.id, { onDelete: "restrict" }),
450
472
  filename: text("filename").notNull(),
451
473
  mimeType: text("mime_type").notNull(),
452
474
  size: bigint("size", { mode: "number" }).notNull(),
@@ -454,8 +476,88 @@ var attachments = pgTable("attachments", {
454
476
  createdAt: timestamp("created_at").defaultNow().notNull()
455
477
  }, (table) => [
456
478
  index("attachments_document_id_idx").on(table.documentId),
479
+ index("attachments_uploaded_by_idx").on(table.uploadedBy),
457
480
  uniqueIndex("attachments_storage_key_unique").on(table.storageKey)
458
481
  ]);
482
+ var pendingAttachmentUploads = pgTable("pending_attachment_uploads", {
483
+ id: uuid("id").primaryKey().defaultRandom(),
484
+ documentId: uuid("document_id").notNull().references(() => documents.id, { onDelete: "restrict" }),
485
+ actorUserId: uuid("actor_user_id").notNull().references(() => users.id, { onDelete: "restrict" }),
486
+ workspaceId: text("workspace_id"),
487
+ storageKey: text("storage_key").notNull(),
488
+ tokenHash: text("token_hash").notNull(),
489
+ filename: text("filename").notNull(),
490
+ mimeType: text("mime_type").notNull(),
491
+ declaredSize: bigint("declared_size", { mode: "number" }).notNull(),
492
+ quotaReservationId: text("quota_reservation_id"),
493
+ quotaOperationKey: text("quota_operation_key").notNull(),
494
+ quotaState: text("quota_state").notNull(),
495
+ actualSize: bigint("actual_size", { mode: "number" }),
496
+ urlIssuedAt: timestamp("url_issued_at"),
497
+ confirmingAt: timestamp("confirming_at"),
498
+ leaseOwner: text("lease_owner"),
499
+ leaseExpiresAt: timestamp("lease_expires_at"),
500
+ attemptCount: integer("attempt_count").default(0).notNull(),
501
+ lastError: text("last_error"),
502
+ expiresAt: timestamp("expires_at").notNull(),
503
+ createdAt: timestamp("created_at").defaultNow().notNull()
504
+ }, (table) => [
505
+ uniqueIndex("pending_attachment_uploads_storage_key_unique").on(table.storageKey),
506
+ uniqueIndex("pending_attachment_uploads_token_hash_unique").on(table.tokenHash),
507
+ index("pending_attachment_uploads_actor_expiry_idx").on(table.actorUserId, table.expiresAt),
508
+ index("pending_attachment_uploads_document_idx").on(table.documentId),
509
+ index("pending_attachment_uploads_cleanup_lease_idx").on(table.expiresAt, table.leaseExpiresAt, table.id),
510
+ check("pending_attachment_uploads_quota_state_check", sql`${table.quotaState} IN ('not_required', 'reserve_pending', 'reserved', 'finalize_pending', 'committed')`)
511
+ ]);
512
+ var attachmentStorageCleanupOutbox = pgTable("attachment_storage_cleanup_outbox", {
513
+ id: uuid("id").primaryKey().defaultRandom(),
514
+ sourceKind: text("source_kind").notNull(),
515
+ sourceId: uuid("source_id").notNull(),
516
+ storageKey: text("storage_key").notNull(),
517
+ documentId: uuid("document_id").notNull(),
518
+ actorUserId: uuid("actor_user_id").notNull(),
519
+ ownerUserId: uuid("owner_user_id").notNull(),
520
+ requestedByUserId: uuid("requested_by_user_id").notNull(),
521
+ workspaceId: text("workspace_id"),
522
+ size: bigint("size", { mode: "number" }).notNull(),
523
+ quotaOperationKey: text("quota_operation_key").notNull(),
524
+ quotaReleaseKind: text("quota_release_kind").default("none").notNull(),
525
+ quotaReservationId: text("quota_reservation_id"),
526
+ notBefore: timestamp("not_before").defaultNow().notNull(),
527
+ retainUntil: timestamp("retain_until"),
528
+ objectDeletedAt: timestamp("object_deleted_at"),
529
+ leaseOwner: text("lease_owner"),
530
+ leaseExpiresAt: timestamp("lease_expires_at"),
531
+ attemptCount: integer("attempt_count").default(0).notNull(),
532
+ lastError: text("last_error"),
533
+ createdAt: timestamp("created_at").defaultNow().notNull()
534
+ }, (table) => [
535
+ uniqueIndex("attachment_storage_cleanup_outbox_source_unique").on(table.sourceKind, table.sourceId),
536
+ uniqueIndex("attachment_storage_cleanup_outbox_storage_key_unique").on(table.storageKey),
537
+ index("attachment_storage_cleanup_outbox_ready_idx").on(table.notBefore, table.leaseExpiresAt, table.createdAt, table.id),
538
+ index("attachment_storage_cleanup_outbox_actor_idx").on(table.actorUserId, table.id),
539
+ index("attachment_storage_cleanup_outbox_owner_idx").on(table.ownerUserId, table.id),
540
+ index("attachment_storage_cleanup_outbox_requester_idx").on(table.requestedByUserId, table.id),
541
+ check("attachment_storage_cleanup_outbox_source_kind_check", sql`${table.sourceKind} IN ('attachment', 'pending_upload', 'uncommitted_upload')`),
542
+ check("attachment_storage_cleanup_outbox_quota_kind_check", sql`${table.quotaReleaseKind} IN ('none', 'reserve_pending', 'reservation', 'finalize_pending', 'committed')`),
543
+ check("attachment_storage_cleanup_outbox_size_check", sql`${table.size} >= 0`),
544
+ check("attachment_storage_cleanup_outbox_reservation_check", sql`${table.quotaReleaseKind} NOT IN ('reservation', 'finalize_pending') OR ${table.quotaReservationId} IS NOT NULL`)
545
+ ]);
546
+ var pendingAttachmentCleanupAuthorizations = pgTable("pending_attachment_cleanup_authorizations", {
547
+ backendPid: integer("backend_pid").notNull(),
548
+ transactionId: bigint("transaction_id", { mode: "bigint" }).notNull(),
549
+ admissionId: uuid("admission_id").notNull(),
550
+ documentId: uuid("document_id").notNull(),
551
+ actorUserId: uuid("actor_user_id").notNull(),
552
+ ownerUserId: uuid("owner_user_id").notNull(),
553
+ workspaceId: text("workspace_id"),
554
+ storageKey: text("storage_key").notNull(),
555
+ tokenHash: text("token_hash").notNull()
556
+ }, (table) => [
557
+ primaryKey({
558
+ columns: [table.backendPid, table.transactionId, table.admissionId]
559
+ })
560
+ ]);
459
561
  var attachmentRelations = relations(attachments, ({ one }) => ({
460
562
  document: one(documents, {
461
563
  fields: [attachments.documentId],
@@ -2719,6 +2821,14 @@ function createAccountRuntimeCleanupWithDependencies(dependencies) {
2719
2821
  `${REEMBED_DEDUP_PREFIX}${document.workspaceId}:${document.documentId}`
2720
2822
  ] : []
2721
2823
  ], signal);
2824
+ for (const dedupScope of [
2825
+ `${REEMBED_DEDUP_PREFIX}${escapedDocumentId}`,
2826
+ ...document.workspaceId ? [
2827
+ `${REEMBED_DEDUP_PREFIX}${escapeRedisGlob(encodeURIComponent(document.workspaceId))}:${escapedDocumentId}`
2828
+ ] : []
2829
+ ]) {
2830
+ deleted += await deleteNamespacePattern(dependencies.redis, `${dedupScope}:*`, signal);
2831
+ }
2722
2832
  deleted += await deleteNamespacePattern(dependencies.redis, `${EXTRACT_DONE_PREFIX}${escapedDocumentId}:*`, signal);
2723
2833
  throwIfAborted(signal);
2724
2834
  }
@@ -17,49 +17,53 @@ var __export = (target, all) => {
17
17
  // ../db/src/schema.ts
18
18
  var exports_schema = {};
19
19
  __export(exports_schema, {
20
- versions: () => versions,
21
- versionRelations: () => versionRelations,
22
- verifications: () => verifications,
23
- users: () => users,
24
- tags: () => tags,
25
- tagRelations: () => tagRelations,
26
- shareRoleEnum: () => shareRoleEnum,
27
- shareLinks: () => shareLinks,
28
- shareLinkRelations: () => shareLinkRelations,
29
- shareGrantStatusEnum: () => shareGrantStatusEnum,
30
- shareAccessModeEnum: () => shareAccessModeEnum,
31
- sessions: () => sessions,
32
- pipelineStatusEnum: () => pipelineStatusEnum,
33
- pipelineStageEnum: () => pipelineStageEnum,
34
- lifecycleOperations: () => lifecycleOperations,
35
- lifecycleOperationStatusEnum: () => lifecycleOperationStatusEnum,
36
- lifecycleOperationKindEnum: () => lifecycleOperationKindEnum,
37
- guestAccessRelations: () => guestAccessRelations,
38
- guestAccess: () => guestAccess,
39
- folders: () => folders,
40
- folderRelations: () => folderRelations,
41
- embeddingStatusEnum: () => embeddingStatusEnum,
42
- documents: () => documents,
43
- documentVisibilityEnum: () => documentVisibilityEnum,
44
- documentTags: () => documentTags,
45
- documentTagRelations: () => documentTagRelations,
46
- documentRelations: () => documentRelations,
47
- documentPipelineRuns: () => documentPipelineRuns,
48
- documentPipelineBatches: () => documentPipelineBatches,
49
- documentKnowledgeSummaries: () => documentKnowledgeSummaries,
50
- documentEmbeddings: () => documentEmbeddings,
51
- documentEmbeddingRelations: () => documentEmbeddingRelations,
52
- documentCreateOperations: () => documentCreateOperations,
53
- categoryRelations: () => categoryRelations,
54
- categories: () => categories,
55
- auditLog: () => auditLog,
56
- attachments: () => attachments,
57
- attachmentRelations: () => attachmentRelations,
58
- apiKeys: () => apiKeys,
20
+ accounts: () => accounts,
59
21
  apiKeyRelations: () => apiKeyRelations,
60
- accounts: () => accounts
22
+ apiKeys: () => apiKeys,
23
+ attachmentRelations: () => attachmentRelations,
24
+ attachmentStorageCleanupOutbox: () => attachmentStorageCleanupOutbox,
25
+ attachments: () => attachments,
26
+ auditLog: () => auditLog,
27
+ categories: () => categories,
28
+ categoryRelations: () => categoryRelations,
29
+ documentCreateOperations: () => documentCreateOperations,
30
+ documentEmbeddingRelations: () => documentEmbeddingRelations,
31
+ documentEmbeddings: () => documentEmbeddings,
32
+ documentKnowledgeSummaries: () => documentKnowledgeSummaries,
33
+ documentPipelineBatches: () => documentPipelineBatches,
34
+ documentPipelineRuns: () => documentPipelineRuns,
35
+ documentRelations: () => documentRelations,
36
+ documentTagRelations: () => documentTagRelations,
37
+ documentTags: () => documentTags,
38
+ documentVisibilityEnum: () => documentVisibilityEnum,
39
+ documents: () => documents,
40
+ embeddingStatusEnum: () => embeddingStatusEnum,
41
+ folderRelations: () => folderRelations,
42
+ folders: () => folders,
43
+ guestAccess: () => guestAccess,
44
+ guestAccessRelations: () => guestAccessRelations,
45
+ lifecycleOperationKindEnum: () => lifecycleOperationKindEnum,
46
+ lifecycleOperationStatusEnum: () => lifecycleOperationStatusEnum,
47
+ lifecycleOperations: () => lifecycleOperations,
48
+ metadataReembedOutbox: () => metadataReembedOutbox,
49
+ pendingAttachmentCleanupAuthorizations: () => pendingAttachmentCleanupAuthorizations,
50
+ pendingAttachmentUploads: () => pendingAttachmentUploads,
51
+ pipelineStageEnum: () => pipelineStageEnum,
52
+ pipelineStatusEnum: () => pipelineStatusEnum,
53
+ sessions: () => sessions,
54
+ shareAccessModeEnum: () => shareAccessModeEnum,
55
+ shareGrantStatusEnum: () => shareGrantStatusEnum,
56
+ shareLinkRelations: () => shareLinkRelations,
57
+ shareLinks: () => shareLinks,
58
+ shareRoleEnum: () => shareRoleEnum,
59
+ tagRelations: () => tagRelations,
60
+ tags: () => tags,
61
+ users: () => users,
62
+ verifications: () => verifications,
63
+ versionRelations: () => versionRelations,
64
+ versions: () => versions
61
65
  });
62
- import { pgTable, uuid, text, timestamp, bigint, jsonb, index, uniqueIndex, customType, boolean, check, integer, pgEnum } from "drizzle-orm/pg-core";
66
+ import { pgTable, uuid, text, timestamp, bigint, jsonb, index, uniqueIndex, customType, boolean, check, integer, pgEnum, primaryKey } from "drizzle-orm/pg-core";
63
67
  import { relations, sql } from "drizzle-orm";
64
68
  var vector = customType({
65
69
  dataType(config) {
@@ -227,6 +231,7 @@ var documents = pgTable("documents", {
227
231
  activeEmbeddingGeneration: uuid("active_embedding_generation"),
228
232
  pendingEmbeddingGeneration: uuid("pending_embedding_generation"),
229
233
  embeddingProfile: text("embedding_profile"),
234
+ embeddingContextHash: text("embedding_context_hash"),
230
235
  embeddingErrorCode: text("embedding_error_code"),
231
236
  embeddingUpdatedAt: timestamp("embedding_updated_at"),
232
237
  deletedAt: timestamp("deleted_at"),
@@ -265,6 +270,8 @@ var documentPipelineRuns = pgTable("document_pipeline_runs", {
265
270
  generationId: uuid("generation_id").notNull(),
266
271
  revision: text("revision").notNull(),
267
272
  source: text("source").notNull(),
273
+ embeddingContextHash: text("embedding_context_hash"),
274
+ refreshMode: text("refresh_mode").notNull().default("full"),
268
275
  status: pipelineStatusEnum("status").notNull().default("pending"),
269
276
  prepareStatus: pipelineStatusEnum("prepare_status").notNull().default("pending"),
270
277
  embedStatus: pipelineStatusEnum("embed_status").notNull().default("pending"),
@@ -285,7 +292,8 @@ var documentPipelineRuns = pgTable("document_pipeline_runs", {
285
292
  updatedAt: timestamp("updated_at").defaultNow().notNull()
286
293
  }, (table) => [
287
294
  uniqueIndex("document_pipeline_runs_document_generation_idx").on(table.documentId, table.generationId),
288
- index("document_pipeline_runs_owner_status_updated_idx").on(table.ownerId, table.status, table.updatedAt)
295
+ index("document_pipeline_runs_owner_status_updated_idx").on(table.ownerId, table.status, table.updatedAt),
296
+ check("document_pipeline_runs_refresh_mode_check", sql`${table.refreshMode} in ('incremental', 'full')`)
289
297
  ]);
290
298
  var documentPipelineBatches = pgTable("document_pipeline_batches", {
291
299
  id: uuid("id").primaryKey().defaultRandom(),
@@ -311,6 +319,19 @@ var documentPipelineBatches = pgTable("document_pipeline_batches", {
311
319
  index("document_pipeline_batches_stage_status_available_idx").on(table.stage, table.status, table.availableAt),
312
320
  index("document_pipeline_batches_document_id_idx").on(table.documentId)
313
321
  ]);
322
+ var metadataReembedOutbox = pgTable("metadata_reembed_outbox", {
323
+ id: uuid("id").primaryKey(),
324
+ operationId: uuid("operation_id").notNull(),
325
+ documentId: uuid("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
326
+ ownerId: uuid("owner_id").notNull().references(() => users.id, { onDelete: "cascade" }),
327
+ workspaceId: text("workspace_id"),
328
+ revision: text("revision").notNull(),
329
+ createdAt: timestamp("created_at").defaultNow().notNull()
330
+ }, (table) => [
331
+ uniqueIndex("metadata_reembed_outbox_operation_document_idx").on(table.operationId, table.documentId),
332
+ index("metadata_reembed_outbox_operation_id_idx").on(table.operationId, table.id),
333
+ index("metadata_reembed_outbox_created_id_idx").on(table.createdAt, table.id)
334
+ ]);
314
335
  var documentKnowledgeSummaries = pgTable("document_knowledge_summaries", {
315
336
  id: uuid().primaryKey().defaultRandom(),
316
337
  document_id: uuid().notNull().references(() => documents.id, { onDelete: "cascade" }),
@@ -447,6 +468,7 @@ var attachments = pgTable("attachments", {
447
468
  id: uuid("id").primaryKey().defaultRandom(),
448
469
  documentId: uuid("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
449
470
  workspaceId: text("workspace_id"),
471
+ uploadedBy: uuid("uploaded_by").notNull().references(() => users.id, { onDelete: "restrict" }),
450
472
  filename: text("filename").notNull(),
451
473
  mimeType: text("mime_type").notNull(),
452
474
  size: bigint("size", { mode: "number" }).notNull(),
@@ -454,8 +476,88 @@ var attachments = pgTable("attachments", {
454
476
  createdAt: timestamp("created_at").defaultNow().notNull()
455
477
  }, (table) => [
456
478
  index("attachments_document_id_idx").on(table.documentId),
479
+ index("attachments_uploaded_by_idx").on(table.uploadedBy),
457
480
  uniqueIndex("attachments_storage_key_unique").on(table.storageKey)
458
481
  ]);
482
+ var pendingAttachmentUploads = pgTable("pending_attachment_uploads", {
483
+ id: uuid("id").primaryKey().defaultRandom(),
484
+ documentId: uuid("document_id").notNull().references(() => documents.id, { onDelete: "restrict" }),
485
+ actorUserId: uuid("actor_user_id").notNull().references(() => users.id, { onDelete: "restrict" }),
486
+ workspaceId: text("workspace_id"),
487
+ storageKey: text("storage_key").notNull(),
488
+ tokenHash: text("token_hash").notNull(),
489
+ filename: text("filename").notNull(),
490
+ mimeType: text("mime_type").notNull(),
491
+ declaredSize: bigint("declared_size", { mode: "number" }).notNull(),
492
+ quotaReservationId: text("quota_reservation_id"),
493
+ quotaOperationKey: text("quota_operation_key").notNull(),
494
+ quotaState: text("quota_state").notNull(),
495
+ actualSize: bigint("actual_size", { mode: "number" }),
496
+ urlIssuedAt: timestamp("url_issued_at"),
497
+ confirmingAt: timestamp("confirming_at"),
498
+ leaseOwner: text("lease_owner"),
499
+ leaseExpiresAt: timestamp("lease_expires_at"),
500
+ attemptCount: integer("attempt_count").default(0).notNull(),
501
+ lastError: text("last_error"),
502
+ expiresAt: timestamp("expires_at").notNull(),
503
+ createdAt: timestamp("created_at").defaultNow().notNull()
504
+ }, (table) => [
505
+ uniqueIndex("pending_attachment_uploads_storage_key_unique").on(table.storageKey),
506
+ uniqueIndex("pending_attachment_uploads_token_hash_unique").on(table.tokenHash),
507
+ index("pending_attachment_uploads_actor_expiry_idx").on(table.actorUserId, table.expiresAt),
508
+ index("pending_attachment_uploads_document_idx").on(table.documentId),
509
+ index("pending_attachment_uploads_cleanup_lease_idx").on(table.expiresAt, table.leaseExpiresAt, table.id),
510
+ check("pending_attachment_uploads_quota_state_check", sql`${table.quotaState} IN ('not_required', 'reserve_pending', 'reserved', 'finalize_pending', 'committed')`)
511
+ ]);
512
+ var attachmentStorageCleanupOutbox = pgTable("attachment_storage_cleanup_outbox", {
513
+ id: uuid("id").primaryKey().defaultRandom(),
514
+ sourceKind: text("source_kind").notNull(),
515
+ sourceId: uuid("source_id").notNull(),
516
+ storageKey: text("storage_key").notNull(),
517
+ documentId: uuid("document_id").notNull(),
518
+ actorUserId: uuid("actor_user_id").notNull(),
519
+ ownerUserId: uuid("owner_user_id").notNull(),
520
+ requestedByUserId: uuid("requested_by_user_id").notNull(),
521
+ workspaceId: text("workspace_id"),
522
+ size: bigint("size", { mode: "number" }).notNull(),
523
+ quotaOperationKey: text("quota_operation_key").notNull(),
524
+ quotaReleaseKind: text("quota_release_kind").default("none").notNull(),
525
+ quotaReservationId: text("quota_reservation_id"),
526
+ notBefore: timestamp("not_before").defaultNow().notNull(),
527
+ retainUntil: timestamp("retain_until"),
528
+ objectDeletedAt: timestamp("object_deleted_at"),
529
+ leaseOwner: text("lease_owner"),
530
+ leaseExpiresAt: timestamp("lease_expires_at"),
531
+ attemptCount: integer("attempt_count").default(0).notNull(),
532
+ lastError: text("last_error"),
533
+ createdAt: timestamp("created_at").defaultNow().notNull()
534
+ }, (table) => [
535
+ uniqueIndex("attachment_storage_cleanup_outbox_source_unique").on(table.sourceKind, table.sourceId),
536
+ uniqueIndex("attachment_storage_cleanup_outbox_storage_key_unique").on(table.storageKey),
537
+ index("attachment_storage_cleanup_outbox_ready_idx").on(table.notBefore, table.leaseExpiresAt, table.createdAt, table.id),
538
+ index("attachment_storage_cleanup_outbox_actor_idx").on(table.actorUserId, table.id),
539
+ index("attachment_storage_cleanup_outbox_owner_idx").on(table.ownerUserId, table.id),
540
+ index("attachment_storage_cleanup_outbox_requester_idx").on(table.requestedByUserId, table.id),
541
+ check("attachment_storage_cleanup_outbox_source_kind_check", sql`${table.sourceKind} IN ('attachment', 'pending_upload', 'uncommitted_upload')`),
542
+ check("attachment_storage_cleanup_outbox_quota_kind_check", sql`${table.quotaReleaseKind} IN ('none', 'reserve_pending', 'reservation', 'finalize_pending', 'committed')`),
543
+ check("attachment_storage_cleanup_outbox_size_check", sql`${table.size} >= 0`),
544
+ check("attachment_storage_cleanup_outbox_reservation_check", sql`${table.quotaReleaseKind} NOT IN ('reservation', 'finalize_pending') OR ${table.quotaReservationId} IS NOT NULL`)
545
+ ]);
546
+ var pendingAttachmentCleanupAuthorizations = pgTable("pending_attachment_cleanup_authorizations", {
547
+ backendPid: integer("backend_pid").notNull(),
548
+ transactionId: bigint("transaction_id", { mode: "bigint" }).notNull(),
549
+ admissionId: uuid("admission_id").notNull(),
550
+ documentId: uuid("document_id").notNull(),
551
+ actorUserId: uuid("actor_user_id").notNull(),
552
+ ownerUserId: uuid("owner_user_id").notNull(),
553
+ workspaceId: text("workspace_id"),
554
+ storageKey: text("storage_key").notNull(),
555
+ tokenHash: text("token_hash").notNull()
556
+ }, (table) => [
557
+ primaryKey({
558
+ columns: [table.backendPid, table.transactionId, table.admissionId]
559
+ })
560
+ ]);
459
561
  var attachmentRelations = relations(attachments, ({ one }) => ({
460
562
  document: one(documents, {
461
563
  fields: [attachments.documentId],
@@ -596,13 +698,33 @@ import { sql as sql2 } from "drizzle-orm";
596
698
  // ../db/src/client.ts
597
699
  import { drizzle } from "drizzle-orm/postgres-js";
598
700
  import postgres from "postgres";
701
+ function observeDatabaseQuery(observer, query) {
702
+ if (!observer)
703
+ return;
704
+ try {
705
+ observer(Object.freeze({ query }));
706
+ } catch {}
707
+ }
708
+ function createDatabaseClient(databaseUrl, options = {}) {
709
+ const sqlClient = postgres(databaseUrl, {
710
+ max: options.max ?? 20,
711
+ idle_timeout: options.idleTimeout ?? 30,
712
+ connect_timeout: options.connectTimeout ?? 10,
713
+ ...options.queryObserver ? {
714
+ debug: (_connection, query) => {
715
+ observeDatabaseQuery(options.queryObserver, query);
716
+ }
717
+ } : {}
718
+ });
719
+ return {
720
+ client: sqlClient,
721
+ db: drizzle(sqlClient, { schema: exports_schema })
722
+ };
723
+ }
599
724
  var databaseUrl = process.env.DATABASE_URL || "postgresql://hiai_app:changeme@localhost:5437/hiai_docs";
600
- var client = postgres(databaseUrl, {
601
- max: 20,
602
- idle_timeout: 30,
603
- connect_timeout: 10
604
- });
605
- var db = drizzle(client, { schema: exports_schema });
725
+ var database = createDatabaseClient(databaseUrl, {});
726
+ var client = database.client;
727
+ var db = database.db;
606
728
 
607
729
  // ../db/src/with-tenant.ts
608
730
  var ZERO_UUID = "00000000-0000-0000-0000-000000000000";
@@ -617,7 +739,10 @@ function adminTenantContext(ownerId) {
617
739
  };
618
740
  }
619
741
  async function withTenant(ctx, fn) {
620
- return db.transaction(async (tx) => {
742
+ return withTenantDatabase(db, ctx, fn);
743
+ }
744
+ async function withTenantDatabase(database2, ctx, fn) {
745
+ return database2.transaction(async (tx) => {
621
746
  await tx.execute(sql2`SELECT set_config('app.current_user_id', ${ctx.userId}, true)`);
622
747
  await tx.execute(sql2`SELECT set_config('app.current_user_role', ${ctx.role}, true)`);
623
748
  await tx.execute(sql2`SELECT set_config('app.current_workspace_id', ${ctx.workspaceId ?? ""}, true)`);
@@ -626,7 +751,23 @@ async function withTenant(ctx, fn) {
626
751
  }
627
752
 
628
753
  // ../../backend/src/lib/api-keys.ts
629
- import { and, desc, eq } from "drizzle-orm";
754
+ import { and as and2, desc, eq as eq2 } from "drizzle-orm";
755
+
756
+ // ../../backend/src/lib/account-purge-fence.ts
757
+ import { and, eq, isNotNull, ne, sql as sql3 } from "drizzle-orm";
758
+ function isAccountPurgeFencedError(error) {
759
+ let current = error;
760
+ for (let depth = 0;depth < 4; depth += 1) {
761
+ if (typeof current !== "object" || current === null)
762
+ return false;
763
+ const candidate = current;
764
+ if (candidate.code === "55000" && (candidate.constraint_name === "account_purge_fenced" || candidate.constraint === "account_purge_fenced" || candidate.message === "account_purge_fenced")) {
765
+ return true;
766
+ }
767
+ current = candidate.cause;
768
+ }
769
+ return false;
770
+ }
630
771
 
631
772
  // ../../backend/src/lib/api-key-encryption.ts
632
773
  var VERSION = "v1";
@@ -737,7 +878,7 @@ async function revealCategoryApiKey(id, ownerId, encryptionSecret) {
737
878
  const [row] = await withTenant({ userId: ownerId, role: "user" }, (tx) => tx.select({
738
879
  encryptedKey: apiKeys.encryptedKey,
739
880
  scopes: apiKeys.scopes
740
- }).from(apiKeys).where(and(eq(apiKeys.id, id), eq(apiKeys.ownerId, ownerId))).limit(1));
881
+ }).from(apiKeys).where(and2(eq2(apiKeys.id, id), eq2(apiKeys.ownerId, ownerId))).limit(1));
741
882
  if (!row?.encryptedKey)
742
883
  return null;
743
884
  const scopes = row.scopes ?? [];
@@ -755,7 +896,7 @@ async function listApiKeys(ownerId) {
755
896
  expiresAt: apiKeys.expiresAt,
756
897
  createdAt: apiKeys.createdAt,
757
898
  encryptedKey: apiKeys.encryptedKey
758
- }).from(apiKeys).where(eq(apiKeys.ownerId, ownerId)).orderBy(desc(apiKeys.createdAt)));
899
+ }).from(apiKeys).where(eq2(apiKeys.ownerId, ownerId)).orderBy(desc(apiKeys.createdAt)));
759
900
  return rows.map((r) => ({
760
901
  id: r.id,
761
902
  name: r.name,
@@ -768,7 +909,7 @@ async function listApiKeys(ownerId) {
768
909
  }));
769
910
  }
770
911
  async function revokeApiKey(id, ownerId) {
771
- const deleted = await withTenant({ userId: ownerId, role: "user" }, (tx) => tx.delete(apiKeys).where(and(eq(apiKeys.id, id), eq(apiKeys.ownerId, ownerId))).returning({ id: apiKeys.id }));
912
+ const deleted = await withTenant({ userId: ownerId, role: "user" }, (tx) => tx.delete(apiKeys).where(and2(eq2(apiKeys.id, id), eq2(apiKeys.ownerId, ownerId))).returning({ id: apiKeys.id }));
772
913
  return deleted.length > 0;
773
914
  }
774
915
  async function validateApiKey(key) {
@@ -778,7 +919,7 @@ async function validateApiKey(key) {
778
919
  ownerId: apiKeys.ownerId,
779
920
  scopes: apiKeys.scopes,
780
921
  expiresAt: apiKeys.expiresAt
781
- }).from(apiKeys).where(eq(apiKeys.keyHash, keyHash)).limit(1));
922
+ }).from(apiKeys).where(eq2(apiKeys.keyHash, keyHash)).limit(1));
782
923
  if (!row) {
783
924
  return null;
784
925
  }
@@ -788,7 +929,12 @@ async function validateApiKey(key) {
788
929
  const scopes = parseApiKeyScopes(row.scopes ?? []);
789
930
  if (!scopes)
790
931
  return null;
791
- await withTenant(API_KEY_ADMIN_TENANT, (tx) => tx.update(apiKeys).set({ lastUsedAt: new Date }).where(eq(apiKeys.id, row.id)));
932
+ try {
933
+ await withTenant(API_KEY_ADMIN_TENANT, (tx) => tx.update(apiKeys).set({ lastUsedAt: new Date }).where(eq2(apiKeys.id, row.id)));
934
+ } catch (error) {
935
+ if (!isAccountPurgeFencedError(error))
936
+ throw error;
937
+ }
792
938
  return {
793
939
  id: row.id,
794
940
  ownerId: row.ownerId,
@@ -796,11 +942,11 @@ async function validateApiKey(key) {
796
942
  };
797
943
  }
798
944
  export {
799
- validateApiKey as verifyApiKey,
800
- revokeApiKey,
801
- revealCategoryApiKey,
802
- listApiKeys,
803
- createApiKey as issueApiKey,
945
+ GLOBAL_API_SCOPE,
804
946
  buildCategoryApiKeyScopes,
805
- GLOBAL_API_SCOPE
947
+ createApiKey as issueApiKey,
948
+ listApiKeys,
949
+ revealCategoryApiKey,
950
+ revokeApiKey,
951
+ validateApiKey as verifyApiKey
806
952
  };