@tearleads/client-sdk 0.1.43 → 0.1.45

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 (189) hide show
  1. package/client/containerDocumentDiscovery.js +71 -29
  2. package/client/containerDocumentDiscovery.js.map +1 -1
  3. package/client/deviceFirst.js +4 -5
  4. package/client/deviceFirst.js.map +1 -1
  5. package/data/persistence/container-contents/containerContentsPersistence.js +2 -3
  6. package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
  7. package/data/persistence/container-contents/containerCreateIntentSettlement.js +16 -16
  8. package/data/persistence/container-contents/containerCreateIntentSettlement.js.map +1 -1
  9. package/data/persistence/container-contents/containerDeletionPersistence.js +5 -11
  10. package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
  11. package/data/persistence/container-contents/containerDocumentReassignment.js +13 -13
  12. package/data/persistence/container-contents/containerDocumentReassignment.js.map +1 -1
  13. package/data/persistence/container-contents/containerHydrationPersistence.js +7 -4
  14. package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
  15. package/data/persistence/container-contents/containerIntentPersistence.js +43 -42
  16. package/data/persistence/container-contents/containerIntentPersistence.js.map +1 -1
  17. package/data/persistence/container-contents/containerMetadataMutationPersistence.js +15 -20
  18. package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
  19. package/data/persistence/container-contents/containerMoveAbandonPersistence.js +1 -6
  20. package/data/persistence/container-contents/containerMoveAbandonPersistence.js.map +1 -1
  21. package/data/persistence/container-contents/containerMoveIntentRows.js +9 -8
  22. package/data/persistence/container-contents/containerMoveIntentRows.js.map +1 -1
  23. package/data/persistence/container-contents/containerReconcilePersistence.js +4 -8
  24. package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
  25. package/data/persistence/container-contents/containerRecoveryPersistence.js +20 -19
  26. package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
  27. package/data/persistence/container-contents/containerRemovalWork.js +10 -10
  28. package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
  29. package/data/persistence/container-contents/containerStructuralRepair.js +21 -44
  30. package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
  31. package/data/persistence/container-contents/documentLinkRemovalRepair.js +12 -11
  32. package/data/persistence/container-contents/documentLinkRemovalRepair.js.map +1 -1
  33. package/data/persistence/container-contents/documentMoveIntentPersistence.js +53 -28
  34. package/data/persistence/container-contents/documentMoveIntentPersistence.js.map +1 -1
  35. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js +9 -8
  36. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js.map +1 -1
  37. package/data/persistence/container-contents/documentPurgePlacement.js +6 -6
  38. package/data/persistence/container-contents/documentPurgePlacement.js.map +1 -1
  39. package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
  40. package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
  41. package/data/persistence/container-contents/pendingContainerCreate.js +5 -5
  42. package/data/persistence/container-contents/pendingContainerCreate.js.map +1 -1
  43. package/data/persistence/containers/containerPersistence.js +10 -27
  44. package/data/persistence/containers/containerPersistence.js.map +1 -1
  45. package/data/persistence/containers/containerSyncWatermarkPersistence.d.ts +11 -3
  46. package/data/persistence/containers/containerSyncWatermarkPersistence.js +46 -58
  47. package/data/persistence/containers/containerSyncWatermarkPersistence.js.map +1 -1
  48. package/data/persistence/containers/documentContainerProjectionPersistence.js +2 -2
  49. package/data/persistence/containers/documentContainerProjectionPersistence.js.map +1 -1
  50. package/data/persistence/containers/documentPlacement.js +10 -10
  51. package/data/persistence/containers/documentPlacement.js.map +1 -1
  52. package/data/persistence/documents/internal/discardDocument.js +5 -5
  53. package/data/persistence/documents/internal/discardDocument.js.map +1 -1
  54. package/data/persistence/documents/internal/documentDeletionPersistence.js +7 -9
  55. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  56. package/data/persistence/documents/internal/documentMutationPersistence.js +6 -8
  57. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  58. package/data/persistence/documents/internal/ensureDocumentsSchema.js +2 -2
  59. package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
  60. package/data/persistence/documents/internal/orphanSideRows.js +3 -22
  61. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  62. package/data/persistence/organizations/organizationDataUsagePersistence.js +31 -64
  63. package/data/persistence/organizations/organizationDataUsagePersistence.js.map +1 -1
  64. package/data/persistence/organizations/organizationReadModelPurge.js +1 -5
  65. package/data/persistence/organizations/organizationReadModelPurge.js.map +1 -1
  66. package/data/persistence/principalCurrentAcknowledgementPersistence.js +24 -17
  67. package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -1
  68. package/data/persistence/principalHistoryIncompleteRetention.js +3 -9
  69. package/data/persistence/principalHistoryIncompleteRetention.js.map +1 -1
  70. package/data/persistence/principalHistoryStagePersistence.d.ts +3 -9
  71. package/data/persistence/principalHistoryStagePersistence.js +15 -25
  72. package/data/persistence/principalHistoryStagePersistence.js.map +1 -1
  73. package/data/persistence/principalHistoryStageRetention.js +16 -15
  74. package/data/persistence/principalHistoryStageRetention.js.map +1 -1
  75. package/data/persistence/principalHistoryUnpublishedRetention.js +6 -13
  76. package/data/persistence/principalHistoryUnpublishedRetention.js.map +1 -1
  77. package/data/sqlite/containerSchema.d.ts +84 -180
  78. package/data/sqlite/containerSchema.js +14 -23
  79. package/data/sqlite/containerSchema.js.map +1 -1
  80. package/data/sqlite/documentPlacementIntentSchema.js +3 -50
  81. package/data/sqlite/documentPlacementIntentSchema.js.map +1 -1
  82. package/data/sqlite/documentSyncFailurePersistence.d.ts +16 -6
  83. package/data/sqlite/documentSyncFailurePersistence.js +44 -54
  84. package/data/sqlite/documentSyncFailurePersistence.js.map +1 -1
  85. package/data/sqlite/{documentPlacementIntentSchema.d.ts → localIntentSchema.d.ts} +162 -88
  86. package/data/sqlite/localIntentSchema.js +90 -0
  87. package/data/sqlite/localIntentSchema.js.map +1 -0
  88. package/data/sqlite/organizationDataUsageSchema.js +11 -17
  89. package/data/sqlite/organizationDataUsageSchema.js.map +1 -1
  90. package/data/sqlite/principalHistoryRetentionSchema.js +0 -15
  91. package/data/sqlite/principalHistoryRetentionSchema.js.map +1 -1
  92. package/data/sqlite/principalHistoryStageSchema.d.ts +44 -2
  93. package/data/sqlite/principalHistoryStageSchema.js +14 -2
  94. package/data/sqlite/principalHistoryStageSchema.js.map +1 -1
  95. package/data/sqlite/schema.d.ts +1019 -2284
  96. package/data/sqlite/schema.js +48 -169
  97. package/data/sqlite/schema.js.map +1 -1
  98. package/internal/api-client/ApiClient.d.ts +6 -34
  99. package/internal/api-client/ApiClient.js +8 -10
  100. package/internal/api-client/ApiClient.js.map +1 -1
  101. package/internal/api-client/apiRequestRuntime.d.ts +2 -0
  102. package/internal/api-client/apiRequestRuntime.js +4 -0
  103. package/internal/api-client/apiRequestRuntime.js.map +1 -1
  104. package/internal/api-client/requestInternals.js +7 -7
  105. package/internal/api-client/requestInternals.js.map +1 -1
  106. package/internal/api-client/routes/containers/reads.d.ts +13 -7
  107. package/internal/api-client/routes/containers/reads.js +36 -15
  108. package/internal/api-client/routes/containers/reads.js.map +1 -1
  109. package/internal/api-client/types.d.ts +1 -5
  110. package/internal/api-client/types.js.map +1 -1
  111. package/internal/validators/containerReadRefinements.js +15 -5
  112. package/internal/validators/containerReadRefinements.js.map +1 -1
  113. package/internal/validators/containerReadSchemas.d.ts +36 -0
  114. package/internal/validators/containerReadSchemas.js +64 -1
  115. package/internal/validators/containerReadSchemas.js.map +1 -1
  116. package/internal/validators/operation/containerReads.d.ts +118 -182
  117. package/internal/validators/operation/containerReads.js +20 -54
  118. package/internal/validators/operation/containerReads.js.map +1 -1
  119. package/internal/validators/operation/index.d.ts +1 -1
  120. package/internal/validators/operation/index.js +1 -1
  121. package/internal/validators/operation/index.js.map +1 -1
  122. package/internal/validators/operation/registry.d.ts +2 -2
  123. package/internal/validators/operation/registry.js +2 -2
  124. package/internal/validators/operation/registry.js.map +1 -1
  125. package/internal/validators/request/containerDocumentLanes.d.ts +23 -0
  126. package/internal/validators/request/containerDocumentLanes.js +23 -0
  127. package/internal/validators/request/containerDocumentLanes.js.map +1 -0
  128. package/internal/validators/request/containerParentLanes.js +5 -35
  129. package/internal/validators/request/containerParentLanes.js.map +1 -1
  130. package/internal/validators/request/index.d.ts +1 -0
  131. package/internal/validators/request/index.js +1 -0
  132. package/internal/validators/request/index.js.map +1 -1
  133. package/internal/validators/response/containerDocumentLanes.d.ts +82 -0
  134. package/internal/validators/response/containerDocumentLanes.js +35 -0
  135. package/internal/validators/response/containerDocumentLanes.js.map +1 -0
  136. package/internal/validators/response/containerParentLanes.js +3 -15
  137. package/internal/validators/response/containerParentLanes.js.map +1 -1
  138. package/internal/validators/response/index.d.ts +2 -1
  139. package/internal/validators/response/index.js +1 -1
  140. package/internal/validators/response/index.js.map +1 -1
  141. package/package.json +1 -1
  142. package/sync/reconciliation/knownContainerSweep.js +57 -54
  143. package/sync/reconciliation/knownContainerSweep.js.map +1 -1
  144. package/sync/reconciliation/reconcileContainer.js +49 -17
  145. package/sync/reconciliation/reconcileContainer.js.map +1 -1
  146. package/sync/reconciliation/service.js +44 -16
  147. package/sync/reconciliation/service.js.map +1 -1
  148. package/sync/reconciliation/serviceTypes.d.ts +23 -2
  149. package/sync/reconciliation/serviceTypes.js.map +1 -1
  150. package/workflows/container-contents/containerDocumentListing.js +92 -38
  151. package/workflows/container-contents/containerDocumentListing.js.map +1 -1
  152. package/workflows/container-contents/containerPersistence.d.ts +8 -2
  153. package/workflows/container-contents/containerPersistence.js +6 -7
  154. package/workflows/container-contents/containerPersistence.js.map +1 -1
  155. package/workflows/container-contents/documentDiscovery.d.ts +3 -3
  156. package/workflows/container-contents/documentDiscovery.js +24 -96
  157. package/workflows/container-contents/documentDiscovery.js.map +1 -1
  158. package/workflows/container-contents/documentDiscoveryApply.js +65 -0
  159. package/workflows/container-contents/documentDiscoveryApply.js.map +1 -0
  160. package/workflows/container-contents/documentDiscoveryLanes.js +53 -0
  161. package/workflows/container-contents/documentDiscoveryLanes.js.map +1 -0
  162. package/workflows/container-contents/documentDiscoveryTypes.d.ts +25 -19
  163. package/workflows/container-contents/documentDiscoveryTypes.js.map +1 -1
  164. package/workflows/container-contents/documentPriming.js +6 -10
  165. package/workflows/container-contents/documentPriming.js.map +1 -1
  166. package/workflows/container-contents/documentQueries/sql.js +11 -10
  167. package/workflows/container-contents/documentQueries/sql.js.map +1 -1
  168. package/workflows/container-contents/documentQueries.js +2 -2
  169. package/workflows/container-contents/documentQueries.js.map +1 -1
  170. package/workflows/container-contents/pendingDownloads.js +2 -5
  171. package/workflows/container-contents/pendingDownloads.js.map +1 -1
  172. package/workflows/container-contents/pendingWrites/deferredTails.js +3 -11
  173. package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
  174. package/workflows/container-contents/pendingWrites/sources.js +56 -80
  175. package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
  176. package/workflows/container-contents/pendingWrites.js +6 -4
  177. package/workflows/container-contents/pendingWrites.js.map +1 -1
  178. package/workflows/container-contents/remoteContainerState.js +2 -1
  179. package/workflows/container-contents/remoteContainerState.js.map +1 -1
  180. package/workflows/container-contents/remoteHydration/laneFetchMarkers.js +11 -17
  181. package/workflows/container-contents/remoteHydration/laneFetchMarkers.js.map +1 -1
  182. package/workflows/sync/remoteReset.js +16 -23
  183. package/workflows/sync/remoteReset.js.map +1 -1
  184. package/workflows/sync/remoteResetCursorScope.js +10 -18
  185. package/workflows/sync/remoteResetCursorScope.js.map +1 -1
  186. package/workflows/sync/remoteResetPrincipalScope.js +1 -2
  187. package/workflows/sync/remoteResetPrincipalScope.js.map +1 -1
  188. package/workflows/sync/remoteResetScope.js +18 -18
  189. package/workflows/sync/remoteResetScope.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"principalHistoryStageRetention.js","sourceRoot":"","sources":["principalHistoryStageRetention.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, desc, eq, lt } from \"drizzle-orm\";\nimport { principalHistoryStageScopes } from \"../sqlite/principalHistoryRetentionSchema\";\nimport { principalHistoryStages } from \"../sqlite/principalHistoryStageSchema\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { releasePrincipalHistoryRoot } from \"./principalHistoryRootOwnership\";\nimport { archivePrincipalHistoryKeyEnvelopes } from \"./principalKeyEnvelopeArchivePersistence\";\n\n/** Each publication reclaims at most this many obsolete completed heads. */\nexport const PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT = 16;\n\nexport async function recordPrincipalHistoryStageScope(\n tx: ClientSQLiteTransactionScope,\n input: {\n readonly id: string;\n readonly organizationId: string;\n readonly scopeId: string;\n readonly afterVersion: number;\n readonly complete: boolean;\n },\n) {\n const row = { ...input, touchedAt: Date.now() };\n await tx\n .insert(principalHistoryStageScopes)\n .values(row)\n .onConflictDoUpdate({ target: principalHistoryStageScopes.id, set: row })\n .run();\n}\n\n/** The prefix and its key candidates must be published in this transaction. */\nexport async function reclaimCompletedPrincipalHistoryStages(\n tx: ClientSQLiteTransactionScope,\n prefix: {\n readonly scopeId: string;\n readonly organizationId: string;\n readonly version: number;\n },\n) {\n const obsolete = await tx\n .select({ stage: principalHistoryStages })\n .from(principalHistoryStageScopes)\n .innerJoin(\n principalHistoryStages,\n eq(principalHistoryStageScopes.id, principalHistoryStages.id),\n )\n .where(\n and(\n eq(principalHistoryStageScopes.scopeId, prefix.scopeId),\n eq(principalHistoryStageScopes.organizationId, prefix.organizationId),\n eq(principalHistoryStageScopes.complete, true),\n lt(principalHistoryStageScopes.afterVersion, prefix.version),\n eq(principalHistoryStages.organizationId, prefix.organizationId),\n eq(principalHistoryStages.complete, true),\n lt(principalHistoryStages.afterVersion, prefix.version),\n ),\n )\n .orderBy(\n desc(principalHistoryStageScopes.afterVersion),\n desc(principalHistoryStageScopes.touchedAt),\n asc(principalHistoryStageScopes.id),\n )\n // Keep the current completed head and its newest completed predecessor.\n // This also preserves the prefix-only predecessor restored after an ack.\n .offset(2)\n .limit(PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT);\n for (const { stage } of obsolete) {\n await releasePrincipalHistoryRoot(tx, `stage:${stage.id}`);\n await archivePrincipalHistoryKeyEnvelopes(tx, {\n ...stage,\n version: stage.afterVersion + 1,\n });\n await tx\n .delete(principalHistoryStages)\n .where(eq(principalHistoryStages.id, stage.id))\n .run();\n await tx\n .delete(principalHistoryStageScopes)\n .where(eq(principalHistoryStageScopes.id, stage.id))\n .run();\n }\n}\n"]}
1
+ {"version":3,"file":"principalHistoryStageRetention.js","sourceRoot":"","sources":["principalHistoryStageRetention.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAE/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EAAE,mCAAmC,EAAE,MAAM,0CAA0C,CAAC;AAE/F,4EAA4E;AAC5E,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,CAAC;AAExD,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,EAAgC,EAChC,KAAwD;IAExD,MAAM,EAAE;SACL,MAAM,CAAC,sBAAsB,CAAC;SAC9B,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;SACtD,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;SAC9C,GAAG,EAAE,CAAC;AACX,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,sCAAsC,CAC1D,EAAgC,EAChC,MAIC;IAED,MAAM,QAAQ,GAAG,MAAM,EAAE;SACtB,MAAM,CAAC;QACN,KAAK,EAAE;YACL,EAAE,EAAE,sBAAsB,CAAC,EAAE;YAC7B,cAAc,EAAE,sBAAsB,CAAC,cAAc;YACrD,WAAW,EAAE,sBAAsB,CAAC,WAAW;YAC/C,YAAY,EAAE,sBAAsB,CAAC,YAAY;SAClD;KACF,CAAC;SACD,IAAI,CAAC,sBAAsB,CAAC;SAC5B,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,EAClD,EAAE,CAAC,sBAAsB,CAAC,cAAc,EAAE,MAAM,CAAC,cAAc,CAAC,EAChE,EAAE,CAAC,sBAAsB,CAAC,QAAQ,EAAE,IAAI,CAAC,EACzC,EAAE,CAAC,sBAAsB,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,CACxD,CACF;SACA,OAAO,CACN,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC,EACzC,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,EACtC,GAAG,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAC/B;QACD,wEAAwE;QACxE,yEAAyE;SACxE,MAAM,CAAC,CAAC,CAAC;SACT,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAChD,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;QACjC,MAAM,2BAA2B,CAAC,EAAE,EAAE,SAAS,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,mCAAmC,CAAC,EAAE,EAAE;YAC5C,GAAG,KAAK;YACR,OAAO,EAAE,KAAK,CAAC,YAAY,GAAG,CAAC;SAChC,CAAC,CAAC;QACH,MAAM,EAAE;aACL,MAAM,CAAC,sBAAsB,CAAC;aAC9B,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;aAC9C,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC","sourcesContent":["import { and, asc, desc, eq, lt } from \"drizzle-orm\";\nimport { principalHistoryStages } from \"../sqlite/principalHistoryStageSchema\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { releasePrincipalHistoryRoot } from \"./principalHistoryRootOwnership\";\nimport { archivePrincipalHistoryKeyEnvelopes } from \"./principalKeyEnvelopeArchivePersistence\";\n\n/** Each publication reclaims at most this many obsolete completed heads. */\nexport const PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT = 16;\n\n/** Mark a stored stage as just used by a writer for its principal history. */\nexport async function touchPrincipalHistoryStage(\n tx: ClientSQLiteTransactionScope,\n input: { readonly id: string; readonly scopeId: string },\n) {\n await tx\n .update(principalHistoryStages)\n .set({ scopeId: input.scopeId, touchedAt: Date.now() })\n .where(eq(principalHistoryStages.id, input.id))\n .run();\n}\n\n/** The prefix and its key candidates must be published in this transaction. */\nexport async function reclaimCompletedPrincipalHistoryStages(\n tx: ClientSQLiteTransactionScope,\n prefix: {\n readonly scopeId: string;\n readonly organizationId: string;\n readonly version: number;\n },\n) {\n const obsolete = await tx\n .select({\n stage: {\n id: principalHistoryStages.id,\n organizationId: principalHistoryStages.organizationId,\n currentJson: principalHistoryStages.currentJson,\n afterVersion: principalHistoryStages.afterVersion,\n },\n })\n .from(principalHistoryStages)\n .where(\n and(\n eq(principalHistoryStages.scopeId, prefix.scopeId),\n eq(principalHistoryStages.organizationId, prefix.organizationId),\n eq(principalHistoryStages.complete, true),\n lt(principalHistoryStages.afterVersion, prefix.version),\n ),\n )\n .orderBy(\n desc(principalHistoryStages.afterVersion),\n desc(principalHistoryStages.touchedAt),\n asc(principalHistoryStages.id),\n )\n // Keep the current completed head and its newest completed predecessor.\n // This also preserves the prefix-only predecessor restored after an ack.\n .offset(2)\n .limit(PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT);\n for (const { stage } of obsolete) {\n await releasePrincipalHistoryRoot(tx, `stage:${stage.id}`);\n await archivePrincipalHistoryKeyEnvelopes(tx, {\n ...stage,\n version: stage.afterVersion + 1,\n });\n await tx\n .delete(principalHistoryStages)\n .where(eq(principalHistoryStages.id, stage.id))\n .run();\n }\n}\n"]}
@@ -1,13 +1,12 @@
1
1
  import { and, asc, desc, eq, inArray, lt, notInArray } from "drizzle-orm";
2
2
  import { principalHistoryPrefixes } from "../sqlite/principalHistoryEvidenceSchema.js";
3
- import { principalHistoryStageScopes } from "../sqlite/principalHistoryRetentionSchema.js";
4
3
  import { principalHistoryStages } from "../sqlite/principalHistoryStageSchema.js";
5
4
  import { releasePrincipalHistoryRoot } from "./principalHistoryRootOwnership.js";
6
5
  import { PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT } from "./principalHistoryStageRetention.js";
7
6
  import { archivePrincipalHistoryKeyEnvelopes } from "./principalKeyEnvelopeArchivePersistence.js";
8
7
  const COMPLETED_STAGE_LIMIT = 8;
9
8
  function matchingCompletedStages(current) {
10
- return and(eq(principalHistoryStageScopes.scopeId, current.scopeId), eq(principalHistoryStageScopes.organizationId, current.organizationId), eq(principalHistoryStageScopes.complete, true), eq(principalHistoryStages.organizationId, current.organizationId), eq(principalHistoryStages.complete, true), eq(principalHistoryStages.afterVersion, principalHistoryStageScopes.afterVersion));
9
+ return and(eq(principalHistoryStages.scopeId, current.scopeId), eq(principalHistoryStages.organizationId, current.organizationId), eq(principalHistoryStages.complete, true));
11
10
  }
12
11
  async function protectedPublishedStages(tx, current) {
13
12
  const [prefix] = await tx
@@ -19,10 +18,9 @@ async function protectedPublishedStages(tx, current) {
19
18
  return [];
20
19
  return tx
21
20
  .select({ id: principalHistoryStages.id })
22
- .from(principalHistoryStageScopes)
23
- .innerJoin(principalHistoryStages, eq(principalHistoryStageScopes.id, principalHistoryStages.id))
24
- .where(and(matchingCompletedStages(current), lt(principalHistoryStageScopes.afterVersion, prefix.version)))
25
- .orderBy(desc(principalHistoryStageScopes.afterVersion), desc(principalHistoryStageScopes.touchedAt), asc(principalHistoryStageScopes.id))
21
+ .from(principalHistoryStages)
22
+ .where(and(matchingCompletedStages(current), lt(principalHistoryStages.afterVersion, prefix.version)))
23
+ .orderBy(desc(principalHistoryStages.afterVersion), desc(principalHistoryStages.touchedAt), asc(principalHistoryStages.id))
26
24
  .limit(2);
27
25
  }
28
26
  /** Bound completed attempts even when current-artifact verification never publishes. */
@@ -42,11 +40,10 @@ export async function reclaimUnpublishedPrincipalHistoryStages(tx, current) {
42
40
  afterVersion: principalHistoryStages.afterVersion,
43
41
  },
44
42
  })
45
- .from(principalHistoryStageScopes)
46
- .innerJoin(principalHistoryStages, eq(principalHistoryStageScopes.id, principalHistoryStages.id))
43
+ .from(principalHistoryStages)
47
44
  .where(and(matchingCompletedStages(current), notInArray(principalHistoryStages.id, protectedIds)))
48
45
  // The existing "incomplete" index also covers completed scoped recency.
49
- .orderBy(desc(principalHistoryStageScopes.touchedAt), asc(principalHistoryStageScopes.id))
46
+ .orderBy(desc(principalHistoryStages.touchedAt), asc(principalHistoryStages.id))
50
47
  .offset(COMPLETED_STAGE_LIMIT - protectedIds.length)
51
48
  .limit(PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT);
52
49
  if (obsolete.length === 0)
@@ -63,9 +60,5 @@ export async function reclaimUnpublishedPrincipalHistoryStages(tx, current) {
63
60
  .delete(principalHistoryStages)
64
61
  .where(inArray(principalHistoryStages.id, ids))
65
62
  .run();
66
- await tx
67
- .delete(principalHistoryStageScopes)
68
- .where(inArray(principalHistoryStageScopes.id, ids))
69
- .run();
70
63
  }
71
64
  //# sourceMappingURL=principalHistoryUnpublishedRetention.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"principalHistoryUnpublishedRetention.js","sourceRoot":"","sources":["principalHistoryUnpublishedRetention.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, desc, eq, inArray, lt, notInArray } from \"drizzle-orm\";\nimport { principalHistoryPrefixes } from \"../sqlite/principalHistoryEvidenceSchema\";\nimport { principalHistoryStageScopes } from \"../sqlite/principalHistoryRetentionSchema\";\nimport { principalHistoryStages } from \"../sqlite/principalHistoryStageSchema\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { releasePrincipalHistoryRoot } from \"./principalHistoryRootOwnership\";\nimport { PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT } from \"./principalHistoryStageRetention\";\nimport { archivePrincipalHistoryKeyEnvelopes } from \"./principalKeyEnvelopeArchivePersistence\";\n\nconst COMPLETED_STAGE_LIMIT = 8;\n\ninterface CompletedWriter {\n readonly id: string;\n readonly scopeId: string;\n readonly organizationId: string;\n readonly complete: boolean;\n}\n\nfunction matchingCompletedStages(current: CompletedWriter) {\n return and(\n eq(principalHistoryStageScopes.scopeId, current.scopeId),\n eq(principalHistoryStageScopes.organizationId, current.organizationId),\n eq(principalHistoryStageScopes.complete, true),\n eq(principalHistoryStages.organizationId, current.organizationId),\n eq(principalHistoryStages.complete, true),\n eq(\n principalHistoryStages.afterVersion,\n principalHistoryStageScopes.afterVersion,\n ),\n );\n}\n\nasync function protectedPublishedStages(\n tx: ClientSQLiteTransactionScope,\n current: CompletedWriter,\n) {\n const [prefix] = await tx\n .select({ version: principalHistoryPrefixes.version })\n .from(principalHistoryPrefixes)\n .where(\n and(\n eq(principalHistoryPrefixes.scopeId, current.scopeId),\n eq(principalHistoryPrefixes.organizationId, current.organizationId),\n ),\n )\n .limit(1);\n if (!prefix) return [];\n return tx\n .select({ id: principalHistoryStages.id })\n .from(principalHistoryStageScopes)\n .innerJoin(\n principalHistoryStages,\n eq(principalHistoryStageScopes.id, principalHistoryStages.id),\n )\n .where(\n and(\n matchingCompletedStages(current),\n lt(principalHistoryStageScopes.afterVersion, prefix.version),\n ),\n )\n .orderBy(\n desc(principalHistoryStageScopes.afterVersion),\n desc(principalHistoryStageScopes.touchedAt),\n asc(principalHistoryStageScopes.id),\n )\n .limit(2);\n}\n\n/** Bound completed attempts even when current-artifact verification never publishes. */\nexport async function reclaimUnpublishedPrincipalHistoryStages(\n tx: ClientSQLiteTransactionScope,\n current: CompletedWriter,\n) {\n if (!current.complete) return;\n const published = await protectedPublishedStages(tx, current);\n const protectedIds = [\n ...new Set([current.id, ...published.map(({ id }) => id)]),\n ];\n const obsolete = await tx\n .select({\n stage: {\n id: principalHistoryStages.id,\n organizationId: principalHistoryStages.organizationId,\n currentJson: principalHistoryStages.currentJson,\n afterVersion: principalHistoryStages.afterVersion,\n },\n })\n .from(principalHistoryStageScopes)\n .innerJoin(\n principalHistoryStages,\n eq(principalHistoryStageScopes.id, principalHistoryStages.id),\n )\n .where(\n and(\n matchingCompletedStages(current),\n notInArray(principalHistoryStages.id, protectedIds),\n ),\n )\n // The existing \"incomplete\" index also covers completed scoped recency.\n .orderBy(\n desc(principalHistoryStageScopes.touchedAt),\n asc(principalHistoryStageScopes.id),\n )\n .offset(COMPLETED_STAGE_LIMIT - protectedIds.length)\n .limit(PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT);\n if (obsolete.length === 0) return;\n for (const { stage } of obsolete)\n await archivePrincipalHistoryKeyEnvelopes(tx, {\n ...stage,\n version: stage.afterVersion + 1,\n });\n const ids = obsolete.map(({ stage }) => stage.id);\n for (const id of ids) await releasePrincipalHistoryRoot(tx, `stage:${id}`);\n await tx\n .delete(principalHistoryStages)\n .where(inArray(principalHistoryStages.id, ids))\n .run();\n await tx\n .delete(principalHistoryStageScopes)\n .where(inArray(principalHistoryStageScopes.id, ids))\n .run();\n}\n"]}
1
+ {"version":3,"file":"principalHistoryUnpublishedRetention.js","sourceRoot":"","sources":["principalHistoryUnpublishedRetention.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, desc, eq, inArray, lt, notInArray } from \"drizzle-orm\";\nimport { principalHistoryPrefixes } from \"../sqlite/principalHistoryEvidenceSchema\";\nimport { principalHistoryStages } from \"../sqlite/principalHistoryStageSchema\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { releasePrincipalHistoryRoot } from \"./principalHistoryRootOwnership\";\nimport { PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT } from \"./principalHistoryStageRetention\";\nimport { archivePrincipalHistoryKeyEnvelopes } from \"./principalKeyEnvelopeArchivePersistence\";\n\nconst COMPLETED_STAGE_LIMIT = 8;\n\ninterface CompletedWriter {\n readonly id: string;\n readonly scopeId: string;\n readonly organizationId: string;\n readonly complete: boolean;\n}\n\nfunction matchingCompletedStages(current: CompletedWriter) {\n return and(\n eq(principalHistoryStages.scopeId, current.scopeId),\n eq(principalHistoryStages.organizationId, current.organizationId),\n eq(principalHistoryStages.complete, true),\n );\n}\n\nasync function protectedPublishedStages(\n tx: ClientSQLiteTransactionScope,\n current: CompletedWriter,\n) {\n const [prefix] = await tx\n .select({ version: principalHistoryPrefixes.version })\n .from(principalHistoryPrefixes)\n .where(\n and(\n eq(principalHistoryPrefixes.scopeId, current.scopeId),\n eq(principalHistoryPrefixes.organizationId, current.organizationId),\n ),\n )\n .limit(1);\n if (!prefix) return [];\n return tx\n .select({ id: principalHistoryStages.id })\n .from(principalHistoryStages)\n .where(\n and(\n matchingCompletedStages(current),\n lt(principalHistoryStages.afterVersion, prefix.version),\n ),\n )\n .orderBy(\n desc(principalHistoryStages.afterVersion),\n desc(principalHistoryStages.touchedAt),\n asc(principalHistoryStages.id),\n )\n .limit(2);\n}\n\n/** Bound completed attempts even when current-artifact verification never publishes. */\nexport async function reclaimUnpublishedPrincipalHistoryStages(\n tx: ClientSQLiteTransactionScope,\n current: CompletedWriter,\n) {\n if (!current.complete) return;\n const published = await protectedPublishedStages(tx, current);\n const protectedIds = [\n ...new Set([current.id, ...published.map(({ id }) => id)]),\n ];\n const obsolete = await tx\n .select({\n stage: {\n id: principalHistoryStages.id,\n organizationId: principalHistoryStages.organizationId,\n currentJson: principalHistoryStages.currentJson,\n afterVersion: principalHistoryStages.afterVersion,\n },\n })\n .from(principalHistoryStages)\n .where(\n and(\n matchingCompletedStages(current),\n notInArray(principalHistoryStages.id, protectedIds),\n ),\n )\n // The existing \"incomplete\" index also covers completed scoped recency.\n .orderBy(\n desc(principalHistoryStages.touchedAt),\n asc(principalHistoryStages.id),\n )\n .offset(COMPLETED_STAGE_LIMIT - protectedIds.length)\n .limit(PRINCIPAL_HISTORY_STAGE_RECLAIM_LIMIT);\n if (obsolete.length === 0) return;\n for (const { stage } of obsolete)\n await archivePrincipalHistoryKeyEnvelopes(tx, {\n ...stage,\n version: stage.afterVersion + 1,\n });\n const ids = obsolete.map(({ stage }) => stage.id);\n for (const id of ids) await releasePrincipalHistoryRoot(tx, `stage:${id}`);\n await tx\n .delete(principalHistoryStages)\n .where(inArray(principalHistoryStages.id, ids))\n .run();\n}\n"]}
@@ -2,12 +2,14 @@ import { type SqlTableSchema } from "./sqlTableSchema.js";
2
2
  /**
3
3
  * Materialized local container tree.
4
4
  *
5
- * Container rows describe the tree and its encrypted metadata document. Display
6
- * fields are kept in `containerProjection`; metadata rows live in `documents`.
7
- * `id` is the primary key for structural lookups. `metadataDocumentId` is the
8
- * server metadata-document id when known; `systemSlot` is an optional opaque
9
- * app-owned slot. Local timestamps track client storage/structural changes,
10
- * while server timestamps are populated once the container has synced.
5
+ * Container rows describe the tree and its encrypted metadata document;
6
+ * metadata rows live in `documents`. `id` is the primary key for structural
7
+ * lookups. `metadataDocumentId` is the server metadata-document id when known;
8
+ * `systemSlot` is an optional opaque app-owned slot. `displayName` and `icon`
9
+ * are the decrypted metadata projection lists read: `displayName` stays
10
+ * nullable so presentation falls back to `/` for a root and `Untitled`
11
+ * otherwise. Local timestamps track client storage/structural changes, while
12
+ * server timestamps are populated once the container has synced.
11
13
  */
12
14
  export declare const containers: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
13
15
  name: "containers";
@@ -108,6 +110,44 @@ export declare const containers: import("drizzle-orm/sqlite-core").SQLiteTableWi
108
110
  }, {}, {
109
111
  length: number | undefined;
110
112
  }>;
113
+ displayName: import("drizzle-orm/sqlite-core").SQLiteColumn<{
114
+ name: "display_name";
115
+ tableName: "containers";
116
+ dataType: "string";
117
+ columnType: "SQLiteText";
118
+ data: string;
119
+ driverParam: string;
120
+ notNull: false;
121
+ hasDefault: false;
122
+ isPrimaryKey: false;
123
+ isAutoincrement: false;
124
+ hasRuntimeDefault: false;
125
+ enumValues: [string, ...string[]];
126
+ baseColumn: never;
127
+ identity: undefined;
128
+ generated: undefined;
129
+ }, {}, {
130
+ length: number | undefined;
131
+ }>;
132
+ icon: import("drizzle-orm/sqlite-core").SQLiteColumn<{
133
+ name: "icon";
134
+ tableName: "containers";
135
+ dataType: "string";
136
+ columnType: "SQLiteText";
137
+ data: string;
138
+ driverParam: string;
139
+ notNull: false;
140
+ hasDefault: false;
141
+ isPrimaryKey: false;
142
+ isAutoincrement: false;
143
+ hasRuntimeDefault: false;
144
+ enumValues: [string, ...string[]];
145
+ baseColumn: never;
146
+ identity: undefined;
147
+ generated: undefined;
148
+ }, {}, {
149
+ length: number | undefined;
150
+ }>;
111
151
  effectiveAccessLevel: import("drizzle-orm/sqlite-core").SQLiteColumn<{
112
152
  name: "effective_access_level";
113
153
  tableName: "containers";
@@ -570,97 +610,6 @@ export declare const dormantMetadataSweepRequests: import("drizzle-orm/sqlite-co
570
610
  };
571
611
  dialect: "sqlite";
572
612
  }>;
573
- /**
574
- * Decrypted container metadata read model.
575
- *
576
- * Container metadata is authored as a Loro document, but lists need a small
577
- * queryable projection for names and icons. `displayName` remains nullable so
578
- * presentation can fall back to `/` or `Untitled`; `containerId` is the primary
579
- * key joining the projection back to `containers.id`.
580
- */
581
- export declare const containerProjection: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
582
- name: "container_projection";
583
- schema: undefined;
584
- columns: {
585
- containerId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
586
- name: "container_id";
587
- tableName: "container_projection";
588
- dataType: "string";
589
- columnType: "SQLiteText";
590
- data: string;
591
- driverParam: string;
592
- notNull: false;
593
- hasDefault: false;
594
- isPrimaryKey: false;
595
- isAutoincrement: false;
596
- hasRuntimeDefault: false;
597
- enumValues: [string, ...string[]];
598
- baseColumn: never;
599
- identity: undefined;
600
- generated: undefined;
601
- }, {}, {
602
- length: number | undefined;
603
- }>;
604
- displayName: import("drizzle-orm/sqlite-core").SQLiteColumn<{
605
- name: "display_name";
606
- tableName: "container_projection";
607
- dataType: "string";
608
- columnType: "SQLiteText";
609
- data: string;
610
- driverParam: string;
611
- notNull: false;
612
- hasDefault: false;
613
- isPrimaryKey: false;
614
- isAutoincrement: false;
615
- hasRuntimeDefault: false;
616
- enumValues: [string, ...string[]];
617
- baseColumn: never;
618
- identity: undefined;
619
- generated: undefined;
620
- }, {}, {
621
- length: number | undefined;
622
- }>;
623
- icon: import("drizzle-orm/sqlite-core").SQLiteColumn<{
624
- name: "icon";
625
- tableName: "container_projection";
626
- dataType: "string";
627
- columnType: "SQLiteText";
628
- data: string;
629
- driverParam: string;
630
- notNull: false;
631
- hasDefault: false;
632
- isPrimaryKey: false;
633
- isAutoincrement: false;
634
- hasRuntimeDefault: false;
635
- enumValues: [string, ...string[]];
636
- baseColumn: never;
637
- identity: undefined;
638
- generated: undefined;
639
- }, {}, {
640
- length: number | undefined;
641
- }>;
642
- updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
643
- name: "updated_at";
644
- tableName: "container_projection";
645
- dataType: "string";
646
- columnType: "SQLiteText";
647
- data: string;
648
- driverParam: string;
649
- notNull: true;
650
- hasDefault: false;
651
- isPrimaryKey: false;
652
- isAutoincrement: false;
653
- hasRuntimeDefault: false;
654
- enumValues: [string, ...string[]];
655
- baseColumn: never;
656
- identity: undefined;
657
- generated: undefined;
658
- }, {}, {
659
- length: number | undefined;
660
- }>;
661
- };
662
- dialect: "sqlite";
663
- }>;
664
613
  export declare const containerTableSchemas: ReadonlyArray<SqlTableSchema>;
665
614
  export declare const containerSQLiteSchema: {
666
615
  containers: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
@@ -762,6 +711,44 @@ export declare const containerSQLiteSchema: {
762
711
  }, {}, {
763
712
  length: number | undefined;
764
713
  }>;
714
+ displayName: import("drizzle-orm/sqlite-core").SQLiteColumn<{
715
+ name: "display_name";
716
+ tableName: "containers";
717
+ dataType: "string";
718
+ columnType: "SQLiteText";
719
+ data: string;
720
+ driverParam: string;
721
+ notNull: false;
722
+ hasDefault: false;
723
+ isPrimaryKey: false;
724
+ isAutoincrement: false;
725
+ hasRuntimeDefault: false;
726
+ enumValues: [string, ...string[]];
727
+ baseColumn: never;
728
+ identity: undefined;
729
+ generated: undefined;
730
+ }, {}, {
731
+ length: number | undefined;
732
+ }>;
733
+ icon: import("drizzle-orm/sqlite-core").SQLiteColumn<{
734
+ name: "icon";
735
+ tableName: "containers";
736
+ dataType: "string";
737
+ columnType: "SQLiteText";
738
+ data: string;
739
+ driverParam: string;
740
+ notNull: false;
741
+ hasDefault: false;
742
+ isPrimaryKey: false;
743
+ isAutoincrement: false;
744
+ hasRuntimeDefault: false;
745
+ enumValues: [string, ...string[]];
746
+ baseColumn: never;
747
+ identity: undefined;
748
+ generated: undefined;
749
+ }, {}, {
750
+ length: number | undefined;
751
+ }>;
765
752
  effectiveAccessLevel: import("drizzle-orm/sqlite-core").SQLiteColumn<{
766
753
  name: "effective_access_level";
767
754
  tableName: "containers";
@@ -958,89 +945,6 @@ export declare const containerSQLiteSchema: {
958
945
  };
959
946
  dialect: "sqlite";
960
947
  }>;
961
- containerProjection: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
962
- name: "container_projection";
963
- schema: undefined;
964
- columns: {
965
- containerId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
966
- name: "container_id";
967
- tableName: "container_projection";
968
- dataType: "string";
969
- columnType: "SQLiteText";
970
- data: string;
971
- driverParam: string;
972
- notNull: false;
973
- hasDefault: false;
974
- isPrimaryKey: false;
975
- isAutoincrement: false;
976
- hasRuntimeDefault: false;
977
- enumValues: [string, ...string[]];
978
- baseColumn: never;
979
- identity: undefined;
980
- generated: undefined;
981
- }, {}, {
982
- length: number | undefined;
983
- }>;
984
- displayName: import("drizzle-orm/sqlite-core").SQLiteColumn<{
985
- name: "display_name";
986
- tableName: "container_projection";
987
- dataType: "string";
988
- columnType: "SQLiteText";
989
- data: string;
990
- driverParam: string;
991
- notNull: false;
992
- hasDefault: false;
993
- isPrimaryKey: false;
994
- isAutoincrement: false;
995
- hasRuntimeDefault: false;
996
- enumValues: [string, ...string[]];
997
- baseColumn: never;
998
- identity: undefined;
999
- generated: undefined;
1000
- }, {}, {
1001
- length: number | undefined;
1002
- }>;
1003
- icon: import("drizzle-orm/sqlite-core").SQLiteColumn<{
1004
- name: "icon";
1005
- tableName: "container_projection";
1006
- dataType: "string";
1007
- columnType: "SQLiteText";
1008
- data: string;
1009
- driverParam: string;
1010
- notNull: false;
1011
- hasDefault: false;
1012
- isPrimaryKey: false;
1013
- isAutoincrement: false;
1014
- hasRuntimeDefault: false;
1015
- enumValues: [string, ...string[]];
1016
- baseColumn: never;
1017
- identity: undefined;
1018
- generated: undefined;
1019
- }, {}, {
1020
- length: number | undefined;
1021
- }>;
1022
- updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
1023
- name: "updated_at";
1024
- tableName: "container_projection";
1025
- dataType: "string";
1026
- columnType: "SQLiteText";
1027
- data: string;
1028
- driverParam: string;
1029
- notNull: true;
1030
- hasDefault: false;
1031
- isPrimaryKey: false;
1032
- isAutoincrement: false;
1033
- hasRuntimeDefault: false;
1034
- enumValues: [string, ...string[]];
1035
- baseColumn: never;
1036
- identity: undefined;
1037
- generated: undefined;
1038
- }, {}, {
1039
- length: number | undefined;
1040
- }>;
1041
- };
1042
- dialect: "sqlite";
1043
- }>;
1044
948
  dormantContainerMetadata: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
1045
949
  name: "dormant_container_metadata";
1046
950
  schema: undefined;
@@ -4,12 +4,14 @@ const accessLevelColumn = "effective_access_level";
4
4
  /**
5
5
  * Materialized local container tree.
6
6
  *
7
- * Container rows describe the tree and its encrypted metadata document. Display
8
- * fields are kept in `containerProjection`; metadata rows live in `documents`.
9
- * `id` is the primary key for structural lookups. `metadataDocumentId` is the
10
- * server metadata-document id when known; `systemSlot` is an optional opaque
11
- * app-owned slot. Local timestamps track client storage/structural changes,
12
- * while server timestamps are populated once the container has synced.
7
+ * Container rows describe the tree and its encrypted metadata document;
8
+ * metadata rows live in `documents`. `id` is the primary key for structural
9
+ * lookups. `metadataDocumentId` is the server metadata-document id when known;
10
+ * `systemSlot` is an optional opaque app-owned slot. `displayName` and `icon`
11
+ * are the decrypted metadata projection lists read: `displayName` stays
12
+ * nullable so presentation falls back to `/` for a root and `Untitled`
13
+ * otherwise. Local timestamps track client storage/structural changes, while
14
+ * server timestamps are populated once the container has synced.
13
15
  */
14
16
  export const containers = sqliteTable("containers", {
15
17
  id: text("id"),
@@ -17,6 +19,8 @@ export const containers = sqliteTable("containers", {
17
19
  parentId: text("parent_id"),
18
20
  metadataDocumentId: text("metadata_document_id"),
19
21
  systemSlot: text("system_slot"),
22
+ displayName: text("display_name"),
23
+ icon: text("icon"),
20
24
  effectiveAccessLevel: text(accessLevelColumn).notNull().default("read"),
21
25
  localCreatedAt: text("local_created_at").notNull(),
22
26
  localUpdatedAt: text("local_updated_at").notNull(),
@@ -76,27 +80,15 @@ export const dormantMetadataSweepRequests = sqliteTable("dormant_metadata_sweep_
76
80
  }, (table) => [
77
81
  primaryKey({ columns: [table.organizationId, table.requesterUserId] }),
78
82
  ]);
79
- /**
80
- * Decrypted container metadata read model.
81
- *
82
- * Container metadata is authored as a Loro document, but lists need a small
83
- * queryable projection for names and icons. `displayName` remains nullable so
84
- * presentation can fall back to `/` or `Untitled`; `containerId` is the primary
85
- * key joining the projection back to `containers.id`.
86
- */
87
- export const containerProjection = sqliteTable("container_projection", {
88
- containerId: text("container_id"),
89
- displayName: text("display_name"),
90
- icon: text("icon"),
91
- updatedAt: text("updated_at").notNull(),
92
- }, (table) => [primaryKey({ columns: [table.containerId] })]);
93
83
  export const containerTableSchemas = [
94
- defineSqlTableSchema(containers),
84
+ {
85
+ ...defineSqlTableSchema(containers),
86
+ requiredColumns: ["display_name", "icon"],
87
+ },
95
88
  {
96
89
  ...defineSqlTableSchema(containerHydrationTombstones),
97
90
  requiredColumns: ["cleared"],
98
91
  },
99
- defineSqlTableSchema(containerProjection),
100
92
  defineSqlTableSchema(dormantContainerMetadata),
101
93
  defineSqlTableSchema(dormantMetadataSweepRequests),
102
94
  defineSqlTableSchema(supersededContainerBindings),
@@ -104,7 +96,6 @@ export const containerTableSchemas = [
104
96
  export const containerSQLiteSchema = {
105
97
  containers,
106
98
  containerHydrationTombstones,
107
- containerProjection,
108
99
  dormantContainerMetadata,
109
100
  dormantMetadataSweepRequests,
110
101
  supersededContainerBindings,
@@ -1 +1 @@
1
- {"version":3,"file":"containerSchema.js","sourceRoot":"","sources":["containerSchema.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n} from \"drizzle-orm/sqlite-core\";\nimport { defineSqlTableSchema, type SqlTableSchema } from \"./sqlTableSchema\";\n\nconst accessLevelColumn = \"effective_access_level\";\n\n/**\n * Materialized local container tree.\n *\n * Container rows describe the tree and its encrypted metadata document. Display\n * fields are kept in `containerProjection`; metadata rows live in `documents`.\n * `id` is the primary key for structural lookups. `metadataDocumentId` is the\n * server metadata-document id when known; `systemSlot` is an optional opaque\n * app-owned slot. Local timestamps track client storage/structural changes,\n * while server timestamps are populated once the container has synced.\n */\nexport const containers = sqliteTable(\n \"containers\",\n {\n id: text(\"id\"),\n organizationId: text(\"organization_id\").notNull(),\n parentId: text(\"parent_id\"),\n metadataDocumentId: text(\"metadata_document_id\"),\n systemSlot: text(\"system_slot\"),\n effectiveAccessLevel: text(accessLevelColumn).notNull().default(\"read\"),\n localCreatedAt: text(\"local_created_at\").notNull(),\n localUpdatedAt: text(\"local_updated_at\").notNull(),\n serverCreatedAt: text(\"server_created_at\"),\n serverUpdatedAt: text(\"server_updated_at\"),\n },\n (table) => [primaryKey({ columns: [table.id] })],\n);\n\n/**\n * Latest removal observed for each container. Hydration must observe the same\n * generation before fetching verified restoration evidence; unsigned clocks\n * never establish a terminal deletion or bypass a concurrent removal. Cleared\n * observations retain their generation so remove/restore/remove cannot reuse it.\n */\nexport const containerHydrationTombstones = sqliteTable(\n \"container_hydration_tombstones\",\n {\n containerId: text(\"container_id\").notNull(),\n generation: integer(\"generation\").notNull().default(1),\n cleared: integer(\"cleared\", { mode: \"boolean\" }).notNull().default(false),\n reason: text(\"reason\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.containerId] })],\n);\n\n/**\n * Organization attribution for container metadata retained after access loss.\n * The container row is removed on revocation, so this marker retains the\n * organization scope needed by a later access-restoration sweep.\n */\nexport const dormantContainerMetadata = sqliteTable(\n \"dormant_container_metadata\",\n {\n containerId: text(\"container_id\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n retainedAt: text(\"retained_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.containerId] }),\n index(\"dormant_container_metadata_organization_idx\").on(\n table.organizationId,\n table.containerId,\n ),\n ],\n);\n\n/**\n * Organizations a held folder was re-homed away from. Purged-organization\n * recovery re-creates folders under their existing ids and a purged\n * organization never returns, so a later proof binding the folder back to one\n * of these organizations is a replay. Retained across remote resets.\n */\nexport const supersededContainerBindings = sqliteTable(\n \"superseded_container_bindings\",\n {\n containerId: text(\"container_id\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n supersededAt: text(\"superseded_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.containerId, table.organizationId] }),\n ],\n);\n\n/**\n * Durable request for a post-access-restoration crawl and sweep. Attempt state\n * enforces exponential backoff and a bounded retry budget across restarts.\n */\nexport const dormantMetadataSweepRequests = sqliteTable(\n \"dormant_metadata_sweep_requests\",\n {\n organizationId: text(\"organization_id\").notNull(),\n requesterUserId: text(\"requester_user_id\").notNull(),\n generation: integer(\"generation\").notNull().default(1),\n attemptCount: integer(\"attempt_count\").notNull().default(0),\n lastAttemptedAt: text(\"last_attempted_at\"),\n requestedAt: text(\"requested_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.organizationId, table.requesterUserId] }),\n ],\n);\n\n/**\n * Decrypted container metadata read model.\n *\n * Container metadata is authored as a Loro document, but lists need a small\n * queryable projection for names and icons. `displayName` remains nullable so\n * presentation can fall back to `/` or `Untitled`; `containerId` is the primary\n * key joining the projection back to `containers.id`.\n */\nexport const containerProjection = sqliteTable(\n \"container_projection\",\n {\n containerId: text(\"container_id\"),\n displayName: text(\"display_name\"),\n icon: text(\"icon\"),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.containerId] })],\n);\n\nexport const containerTableSchemas: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(containers),\n {\n ...defineSqlTableSchema(containerHydrationTombstones),\n requiredColumns: [\"cleared\"],\n },\n defineSqlTableSchema(containerProjection),\n defineSqlTableSchema(dormantContainerMetadata),\n defineSqlTableSchema(dormantMetadataSweepRequests),\n defineSqlTableSchema(supersededContainerBindings),\n];\n\nexport const containerSQLiteSchema = {\n containers,\n containerHydrationTombstones,\n containerProjection,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n supersededContainerBindings,\n};\n"]}
1
+ {"version":3,"file":"containerSchema.js","sourceRoot":"","sources":["containerSchema.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n} from \"drizzle-orm/sqlite-core\";\nimport { defineSqlTableSchema, type SqlTableSchema } from \"./sqlTableSchema\";\n\nconst accessLevelColumn = \"effective_access_level\";\n\n/**\n * Materialized local container tree.\n *\n * Container rows describe the tree and its encrypted metadata document;\n * metadata rows live in `documents`. `id` is the primary key for structural\n * lookups. `metadataDocumentId` is the server metadata-document id when known;\n * `systemSlot` is an optional opaque app-owned slot. `displayName` and `icon`\n * are the decrypted metadata projection lists read: `displayName` stays\n * nullable so presentation falls back to `/` for a root and `Untitled`\n * otherwise. Local timestamps track client storage/structural changes, while\n * server timestamps are populated once the container has synced.\n */\nexport const containers = sqliteTable(\n \"containers\",\n {\n id: text(\"id\"),\n organizationId: text(\"organization_id\").notNull(),\n parentId: text(\"parent_id\"),\n metadataDocumentId: text(\"metadata_document_id\"),\n systemSlot: text(\"system_slot\"),\n displayName: text(\"display_name\"),\n icon: text(\"icon\"),\n effectiveAccessLevel: text(accessLevelColumn).notNull().default(\"read\"),\n localCreatedAt: text(\"local_created_at\").notNull(),\n localUpdatedAt: text(\"local_updated_at\").notNull(),\n serverCreatedAt: text(\"server_created_at\"),\n serverUpdatedAt: text(\"server_updated_at\"),\n },\n (table) => [primaryKey({ columns: [table.id] })],\n);\n\n/**\n * Latest removal observed for each container. Hydration must observe the same\n * generation before fetching verified restoration evidence; unsigned clocks\n * never establish a terminal deletion or bypass a concurrent removal. Cleared\n * observations retain their generation so remove/restore/remove cannot reuse it.\n */\nexport const containerHydrationTombstones = sqliteTable(\n \"container_hydration_tombstones\",\n {\n containerId: text(\"container_id\").notNull(),\n generation: integer(\"generation\").notNull().default(1),\n cleared: integer(\"cleared\", { mode: \"boolean\" }).notNull().default(false),\n reason: text(\"reason\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.containerId] })],\n);\n\n/**\n * Organization attribution for container metadata retained after access loss.\n * The container row is removed on revocation, so this marker retains the\n * organization scope needed by a later access-restoration sweep.\n */\nexport const dormantContainerMetadata = sqliteTable(\n \"dormant_container_metadata\",\n {\n containerId: text(\"container_id\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n retainedAt: text(\"retained_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.containerId] }),\n index(\"dormant_container_metadata_organization_idx\").on(\n table.organizationId,\n table.containerId,\n ),\n ],\n);\n\n/**\n * Organizations a held folder was re-homed away from. Purged-organization\n * recovery re-creates folders under their existing ids and a purged\n * organization never returns, so a later proof binding the folder back to one\n * of these organizations is a replay. Retained across remote resets.\n */\nexport const supersededContainerBindings = sqliteTable(\n \"superseded_container_bindings\",\n {\n containerId: text(\"container_id\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n supersededAt: text(\"superseded_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.containerId, table.organizationId] }),\n ],\n);\n\n/**\n * Durable request for a post-access-restoration crawl and sweep. Attempt state\n * enforces exponential backoff and a bounded retry budget across restarts.\n */\nexport const dormantMetadataSweepRequests = sqliteTable(\n \"dormant_metadata_sweep_requests\",\n {\n organizationId: text(\"organization_id\").notNull(),\n requesterUserId: text(\"requester_user_id\").notNull(),\n generation: integer(\"generation\").notNull().default(1),\n attemptCount: integer(\"attempt_count\").notNull().default(0),\n lastAttemptedAt: text(\"last_attempted_at\"),\n requestedAt: text(\"requested_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.organizationId, table.requesterUserId] }),\n ],\n);\n\nexport const containerTableSchemas: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(containers),\n requiredColumns: [\"display_name\", \"icon\"],\n },\n {\n ...defineSqlTableSchema(containerHydrationTombstones),\n requiredColumns: [\"cleared\"],\n },\n defineSqlTableSchema(dormantContainerMetadata),\n defineSqlTableSchema(dormantMetadataSweepRequests),\n defineSqlTableSchema(supersededContainerBindings),\n];\n\nexport const containerSQLiteSchema = {\n containers,\n containerHydrationTombstones,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n supersededContainerBindings,\n};\n"]}
@@ -1,55 +1,8 @@
1
- import { index, integer, primaryKey, sqliteTable, text, } from "drizzle-orm/sqlite-core";
1
+ import { primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core";
2
2
  /**
3
- * Device-first document moves waiting for remote link-set replay.
4
- *
5
- * A document move is applied to local projections immediately, then replayed as
6
- * remote link/unlink mutations when writer context is available. Replays are
7
- * rebuilt from current writer projections so the queue stores only intent.
8
- *
9
- * Columns:
10
- * - `id`: Client-generated intent id.
11
- * - `localId`: Local document row to update after replay.
12
- * - `documentId`: Server document id whose link set should move.
13
- * - `targetContainerId`: Desired active/final container id.
14
- * - `sourceContainerId`: Original active container to unlink for move-style
15
- * intents. Replace-style intents unlink every remote container except target.
16
- * - `replaceLinkedContainers`: Whether the final remote link set should be
17
- * only the target container.
18
- * - `intentType`: `document.move` requests placement; `document.link` requests
19
- * only explicit additions/removals, even if preferred containers match.
20
- * - `syncStatus`: Current sync state, currently `pending` or `blocked`.
21
- * - `lastError`: Last sync error message for retry/debug display.
22
- * - `lastAttemptedAt`: Timestamp of the last replay attempt.
23
- * - `createdAt`: Intent creation timestamp used for FIFO sync.
24
- * - `updatedAt`: Local timestamp for the latest target/status/error change.
25
- *
26
- * Indexes:
27
- * - `id` is the primary key.
28
- * - `documentId` is unique so same-document moves coalesce to one intent.
29
- * - `(syncStatus, createdAt)` supports listing pending intents in queue order.
3
+ * Additional link targets of a document placement intent in `localIntents`,
4
+ * keyed by that intent's current revision id and settled with it.
30
5
  */
31
- export const documentMoveIntents = sqliteTable("document_move_intents", {
32
- id: text("id"),
33
- localId: text("local_id").notNull(),
34
- documentId: text("document_id").notNull().unique(),
35
- targetContainerId: text("target_container_id").notNull(),
36
- sourceContainerId: text("source_container_id"),
37
- replaceLinkedContainers: integer("replace_linked_containers", {
38
- mode: "boolean",
39
- })
40
- .notNull()
41
- .default(false),
42
- intentType: text("intent_type").notNull(),
43
- syncStatus: text("sync_status").notNull(),
44
- lastError: text("last_error"),
45
- lastAttemptedAt: text("last_attempted_at"),
46
- createdAt: text("created_at").notNull(),
47
- updatedAt: text("updated_at").notNull(),
48
- }, (table) => [
49
- primaryKey({ columns: [table.id] }),
50
- index("document_move_intents_status_created_idx").on(table.syncStatus, table.createdAt),
51
- ]);
52
- /** Additional links share the parent placement intent revision and settlement. */
53
6
  export const documentIntentLinkTargets = sqliteTable("document_intent_link_targets", {
54
7
  intentId: text("intent_id").notNull(),
55
8
  operation: text("operation", { enum: ["link", "unlink"] })
@@ -1 +1 @@
1
- {"version":3,"file":"documentPlacementIntentSchema.js","sourceRoot":"","sources":["documentPlacementIntentSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,IAAI,GACL,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAC5C,uBAAuB,EACvB;IACE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC;IACd,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE;IACnC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE;IAClD,iBAAiB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC,OAAO,EAAE;IACxD,iBAAiB,EAAE,IAAI,CAAC,qBAAqB,CAAC;IAC9C,uBAAuB,EAAE,OAAO,CAAC,2BAA2B,EAAE;QAC5D,IAAI,EAAE,SAAS;KAChB,CAAC;SACC,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC;IAC7B,eAAe,EAAE,IAAI,CAAC,mBAAmB,CAAC;IAC1C,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;CACxC,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;IACnC,KAAK,CAAC,0CAA0C,CAAC,CAAC,EAAE,CAClD,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,SAAS,CAChB;CACF,CACF,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,yBAAyB,GAAG,WAAW,CAClD,8BAA8B,EAC9B;IACE,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE;IACrC,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;SACvD,OAAO,EAAE;SACT,OAAO,CAAC,MAAM,CAAC;IAClB,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE;CAC5C,EACD,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAC1E,CAAC","sourcesContent":["import {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n} from \"drizzle-orm/sqlite-core\";\n\n/**\n * Device-first document moves waiting for remote link-set replay.\n *\n * A document move is applied to local projections immediately, then replayed as\n * remote link/unlink mutations when writer context is available. Replays are\n * rebuilt from current writer projections so the queue stores only intent.\n *\n * Columns:\n * - `id`: Client-generated intent id.\n * - `localId`: Local document row to update after replay.\n * - `documentId`: Server document id whose link set should move.\n * - `targetContainerId`: Desired active/final container id.\n * - `sourceContainerId`: Original active container to unlink for move-style\n * intents. Replace-style intents unlink every remote container except target.\n * - `replaceLinkedContainers`: Whether the final remote link set should be\n * only the target container.\n * - `intentType`: `document.move` requests placement; `document.link` requests\n * only explicit additions/removals, even if preferred containers match.\n * - `syncStatus`: Current sync state, currently `pending` or `blocked`.\n * - `lastError`: Last sync error message for retry/debug display.\n * - `lastAttemptedAt`: Timestamp of the last replay attempt.\n * - `createdAt`: Intent creation timestamp used for FIFO sync.\n * - `updatedAt`: Local timestamp for the latest target/status/error change.\n *\n * Indexes:\n * - `id` is the primary key.\n * - `documentId` is unique so same-document moves coalesce to one intent.\n * - `(syncStatus, createdAt)` supports listing pending intents in queue order.\n */\nexport const documentMoveIntents = sqliteTable(\n \"document_move_intents\",\n {\n id: text(\"id\"),\n localId: text(\"local_id\").notNull(),\n documentId: text(\"document_id\").notNull().unique(),\n targetContainerId: text(\"target_container_id\").notNull(),\n sourceContainerId: text(\"source_container_id\"),\n replaceLinkedContainers: integer(\"replace_linked_containers\", {\n mode: \"boolean\",\n })\n .notNull()\n .default(false),\n intentType: text(\"intent_type\").notNull(),\n syncStatus: text(\"sync_status\").notNull(),\n lastError: text(\"last_error\"),\n lastAttemptedAt: text(\"last_attempted_at\"),\n createdAt: text(\"created_at\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.id] }),\n index(\"document_move_intents_status_created_idx\").on(\n table.syncStatus,\n table.createdAt,\n ),\n ],\n);\n\n/** Additional links share the parent placement intent revision and settlement. */\nexport const documentIntentLinkTargets = sqliteTable(\n \"document_intent_link_targets\",\n {\n intentId: text(\"intent_id\").notNull(),\n operation: text(\"operation\", { enum: [\"link\", \"unlink\"] })\n .notNull()\n .default(\"link\"),\n containerId: text(\"container_id\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.intentId, table.containerId] })],\n);\n"]}
1
+ {"version":3,"file":"documentPlacementIntentSchema.js","sourceRoot":"","sources":["documentPlacementIntentSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAExE;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,WAAW,CAClD,8BAA8B,EAC9B;IACE,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE;IACrC,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;SACvD,OAAO,EAAE;SACT,OAAO,CAAC,MAAM,CAAC;IAClB,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE;CAC5C,EACD,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAC1E,CAAC","sourcesContent":["import { primaryKey, sqliteTable, text } from \"drizzle-orm/sqlite-core\";\n\n/**\n * Additional link targets of a document placement intent in `localIntents`,\n * keyed by that intent's current revision id and settled with it.\n */\nexport const documentIntentLinkTargets = sqliteTable(\n \"document_intent_link_targets\",\n {\n intentId: text(\"intent_id\").notNull(),\n operation: text(\"operation\", { enum: [\"link\", \"unlink\"] })\n .notNull()\n .default(\"link\"),\n containerId: text(\"container_id\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.intentId, table.containerId] })],\n);\n"]}