@tearleads/client-sdk 0.1.87 → 0.1.89

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 (153) hide show
  1. package/Tearleads.js +1 -1
  2. package/Tearleads.js.map +1 -1
  3. package/client/containerContents/documentDiscovery.js +16 -2
  4. package/client/containerContents/documentDiscovery.js.map +1 -1
  5. package/client/containerContents/index.d.ts +1 -1
  6. package/client/containerContents/index.js +1 -0
  7. package/client/containerContents/index.js.map +1 -1
  8. package/client/index.d.ts +1 -1
  9. package/client/index.js.map +1 -1
  10. package/client/organizations/index.d.ts +4 -2
  11. package/client/organizations/index.js +15 -8
  12. package/client/organizations/index.js.map +1 -1
  13. package/client/organizations/organizationMemberships.d.ts +41 -0
  14. package/client/organizations/organizationMemberships.js +166 -0
  15. package/client/organizations/organizationMemberships.js.map +1 -0
  16. package/client/organizations/organizationReadModels.d.ts +7 -1
  17. package/client/organizations/organizationReadModels.js +15 -6
  18. package/client/organizations/organizationReadModels.js.map +1 -1
  19. package/client/organizations/organizationsTypes.d.ts +3 -0
  20. package/client/organizations/organizationsTypes.js.map +1 -1
  21. package/data/persistence/container-contents/containerStructuralRepair.js +19 -14
  22. package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
  23. package/data/persistence/container-contents/exclusiveDocumentPlacements.js +60 -0
  24. package/data/persistence/container-contents/exclusiveDocumentPlacements.js.map +1 -0
  25. package/data/persistence/organizations/organizationReadModelPersistence.js +14 -0
  26. package/data/persistence/organizations/organizationReadModelPersistence.js.map +1 -1
  27. package/data/persistence/organizations/organizationReadModelProjection.js +12 -0
  28. package/data/persistence/organizations/organizationReadModelProjection.js.map +1 -1
  29. package/data/sqlite/schema/index.d.ts +90 -0
  30. package/data/sqlite/schema/index.js +3 -0
  31. package/data/sqlite/schema/index.js.map +1 -1
  32. package/data/sqlite/schema/organizationReadModelSchema.js +2 -0
  33. package/data/sqlite/schema/organizationReadModelSchema.js.map +1 -1
  34. package/data/sqlite/schema/organizationReadModelTableRegistry.d.ts +19 -0
  35. package/data/sqlite/schema/organizationSyncPauseSchema.js +32 -0
  36. package/data/sqlite/schema/organizationSyncPauseSchema.js.map +1 -0
  37. package/data/sync/organizationSyncPauses.d.ts +59 -0
  38. package/data/sync/organizationSyncPauses.js +149 -0
  39. package/data/sync/organizationSyncPauses.js.map +1 -0
  40. package/index.d.ts +2 -2
  41. package/index.js.map +1 -1
  42. package/internal/api-client/ApiClient.d.ts +21 -2
  43. package/internal/api-client/ApiClient.js +15 -1
  44. package/internal/api-client/ApiClient.js.map +1 -1
  45. package/internal/api-client/routes/organizations/memberships.js +36 -0
  46. package/internal/api-client/routes/organizations/memberships.js.map +1 -0
  47. package/internal/crypto/index.d.ts +1 -0
  48. package/internal/crypto/index.js +1 -0
  49. package/internal/crypto/index.js.map +1 -1
  50. package/internal/crypto/organizationLeaveRequest.d.ts +13 -0
  51. package/internal/crypto/organizationLeaveRequest.js +39 -0
  52. package/internal/crypto/organizationLeaveRequest.js.map +1 -0
  53. package/internal/validators/operation/index.d.ts +1 -0
  54. package/internal/validators/operation/index.js +1 -0
  55. package/internal/validators/operation/index.js.map +1 -1
  56. package/internal/validators/operation/organizationMemberships.d.ts +503 -0
  57. package/internal/validators/operation/organizationMemberships.js +93 -0
  58. package/internal/validators/operation/organizationMemberships.js.map +1 -0
  59. package/internal/validators/operation/organizations.d.ts +48 -0
  60. package/internal/validators/operation/registry.d.ts +5 -0
  61. package/internal/validators/operation/registry.js +5 -0
  62. package/internal/validators/operation/registry.js.map +1 -1
  63. package/internal/validators/realtime/index.js +1 -1
  64. package/internal/validators/realtime/index.js.map +1 -1
  65. package/internal/validators/realtime/wsInvalidationHints.js +8 -0
  66. package/internal/validators/realtime/wsInvalidationHints.js.map +1 -1
  67. package/internal/validators/request/index.d.ts +1 -1
  68. package/internal/validators/request/index.js +1 -1
  69. package/internal/validators/request/index.js.map +1 -1
  70. package/internal/validators/request/organization.d.ts +6 -0
  71. package/internal/validators/request/organization.js +7 -0
  72. package/internal/validators/request/organization.js.map +1 -1
  73. package/internal/validators/response/index.d.ts +1 -0
  74. package/internal/validators/response/index.js +1 -0
  75. package/internal/validators/response/index.js.map +1 -1
  76. package/internal/validators/response/organization.d.ts +82 -0
  77. package/internal/validators/response/organization.js +6 -0
  78. package/internal/validators/response/organization.js.map +1 -1
  79. package/internal/validators/response/organizationMembership.d.ts +66 -0
  80. package/internal/validators/response/organizationMembership.js +29 -0
  81. package/internal/validators/response/organizationMembership.js.map +1 -0
  82. package/internal/validators/response/organizationReadModel.d.ts +60 -0
  83. package/internal/validators/util/index.d.ts +1 -0
  84. package/internal/validators/util/index.js +1 -0
  85. package/internal/validators/util/index.js.map +1 -1
  86. package/internal/validators/util/organizationLeaveRequest.d.ts +15 -0
  87. package/internal/validators/util/organizationLeaveRequest.js +22 -0
  88. package/internal/validators/util/organizationLeaveRequest.js.map +1 -0
  89. package/package.json +1 -1
  90. package/stores/container-contents/containerContentsStore.d.ts +1 -1
  91. package/stores/container-contents/containerContentsStore.js +2 -0
  92. package/stores/container-contents/containerContentsStore.js.map +1 -1
  93. package/stores/container-contents/operations/forgetOrganizationContentOperation.js +76 -0
  94. package/stores/container-contents/operations/forgetOrganizationContentOperation.js.map +1 -0
  95. package/stores/container-contents/types.d.ts +6 -0
  96. package/stores/container-contents/types.js.map +1 -1
  97. package/stores/documents/documentStore/attachments/attachmentRemoval.js +3 -4
  98. package/stores/documents/documentStore/attachments/attachmentRemoval.js.map +1 -1
  99. package/stores/documents/documentStore/attachments/index.js +5 -7
  100. package/stores/documents/documentStore/attachments/index.js.map +1 -1
  101. package/stores/documents/documentStore/index.js +16 -12
  102. package/stores/documents/documentStore/index.js.map +1 -1
  103. package/stores/documents/documentStore/initialization/index.js +9 -0
  104. package/stores/documents/documentStore/initialization/index.js.map +1 -1
  105. package/stores/documents/documentStore/mutations.js +5 -7
  106. package/stores/documents/documentStore/mutations.js.map +1 -1
  107. package/stores/documents/documentStore/rotation/index.js +2 -1
  108. package/stores/documents/documentStore/rotation/index.js.map +1 -1
  109. package/stores/documents/documentStore/rows/index.js +3 -4
  110. package/stores/documents/documentStore/rows/index.js.map +1 -1
  111. package/stores/documents/documentStore/state.js +18 -0
  112. package/stores/documents/documentStore/state.js.map +1 -1
  113. package/stores/documents/documentStore/sync/index.js +5 -2
  114. package/stores/documents/documentStore/sync/index.js.map +1 -1
  115. package/stores/documents/registry.d.ts +32 -0
  116. package/stores/documents/registry.js +79 -4
  117. package/stores/documents/registry.js.map +1 -1
  118. package/stores/documents/removedDocumentStore.js +38 -0
  119. package/stores/documents/removedDocumentStore.js.map +1 -0
  120. package/stores/documents/types.d.ts +2 -0
  121. package/stores/documents/types.js.map +1 -1
  122. package/sync/reconciliation/service.js +2 -2
  123. package/sync/reconciliation/service.js.map +1 -1
  124. package/sync/reconciliation/serviceTypes.d.ts +8 -1
  125. package/sync/reconciliation/serviceTypes.js.map +1 -1
  126. package/workflows/container-contents/pendingWrites/index.d.ts +5 -0
  127. package/workflows/container-contents/pendingWrites/index.js +7 -0
  128. package/workflows/container-contents/pendingWrites/index.js.map +1 -1
  129. package/workflows/container-contents/remoteHydration/index.js +7 -1
  130. package/workflows/container-contents/remoteHydration/index.js.map +1 -1
  131. package/workflows/container-contents/remoteHydration/remoteContainers/organizationSyncPauseFilter.js +13 -0
  132. package/workflows/container-contents/remoteHydration/remoteContainers/organizationSyncPauseFilter.js.map +1 -0
  133. package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js +13 -2
  134. package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js.map +1 -1
  135. package/workflows/container-contents/syncPause/discoveryGuard.js +31 -0
  136. package/workflows/container-contents/syncPause/discoveryGuard.js.map +1 -0
  137. package/workflows/container-contents/syncPause/documentRemoval.js +154 -0
  138. package/workflows/container-contents/syncPause/documentRemoval.js.map +1 -0
  139. package/workflows/organizations/index.d.ts +3 -0
  140. package/workflows/organizations/index.js +3 -0
  141. package/workflows/organizations/index.js.map +1 -1
  142. package/workflows/organizations/memberships/leaveRequest.d.ts +31 -0
  143. package/workflows/organizations/memberships/leaveRequest.js +20 -0
  144. package/workflows/organizations/memberships/leaveRequest.js.map +1 -0
  145. package/workflows/organizations/memberships/leaveRequestVerification.d.ts +15 -0
  146. package/workflows/organizations/memberships/leaveRequestVerification.js +46 -0
  147. package/workflows/organizations/memberships/leaveRequestVerification.js.map +1 -0
  148. package/workflows/organizations/memberships/organizationMemberships.d.ts +84 -0
  149. package/workflows/organizations/memberships/organizationMemberships.js +95 -0
  150. package/workflows/organizations/memberships/organizationMemberships.js.map +1 -0
  151. package/workflows/sync/index.d.ts +1 -0
  152. package/workflows/sync/index.js +1 -0
  153. package/workflows/sync/index.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"containerContentsStore.js","sourceRoot":"","sources":["containerContentsStore.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kCAAkC,EAAE,MAAM,oEAAoE,CAAC;AACxH,OAAO,EAEL,mCAAmC,GACpC,MAAM,yDAAyD,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EACL,2BAA2B,EAC3B,iCAAiC,GAClC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACjF,OAAO,EACL,iCAAiC,EACjC,iCAAiC,EACjC,+BAA+B,EAC/B,uCAAuC,EACvC,mCAAmC,GACpC,MAAM,SAAS,CAAC;AACjB,OAAO,EAGL,qCAAqC,GACtC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAOlF,MAAM,8BAA8B,GAAG,IAAI,OAAO,EAG/C,CAAC;AAQJ,SAAS,kCAAkC,CACzC,KAAkC,EAClC,SAA0C,EAC1C,OAAsC;IAEtC,IAAI,UAAU,IAAI,OAAO,EAAE,CAAC;QAC1B,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IACpC,CAAC;IAED,IAAI,aAAa,IAAI,OAAO,EAAE,CAAC;QAC7B,uCAAuC,CACrC,KAAK,EACL,OAAO,CAAC,WAAW,IAAI,mCAAmC,EAC1D,SAAS,CACV,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,0CAA0C,CACjD,KAAkC,EAClC,WAAmB;IAEnB,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7D,OAAO,cAAc;QACnB,CAAC,CAAC,kCAAkC,CAAC,cAAc,CAAC;QACpD,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,SAAS,oCAAoC,CAC3C,KAAkC;IAElC,OAAO;QACL,qBAAqB,EAAE,CACrB,cAAc,EACd,KAAK,EACL,UAAU,EACV,WAAW,EACX,eAAe,EACf,EAAE,CACF,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE;YAC3C,KAAK;YACL,UAAU;YACV,WAAW;YACX,GAAG,eAAe;SACnB,CAAC;QACJ,sBAAsB,EAAE,GAAG,EAAE;YAC3B,KAAK,CAAC,yBAAyB,GAAG,IAAI,CAAC;QACzC,CAAC;QACD,cAAc,EAAE,GAAG,EAAE,CAAC,+BAA+B,CAAC,KAAK,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,SAAS,mBAAmB,CAC1B,KAAkC,EAClC,IAA6E,EAC7E,aAAuC,IAAI,EAC3C,OAAgB;IAEhB,MAAM,SAAS,GAAG,+BAA+B,CAAC,KAAK,CAAC,CAAC;IACzD,+BAA+B,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAC5D,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU;SAChC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;SACjB,IAAI,CAAC,GAAG,EAAE;QACT,IAAI,CAAC,SAAS,EAAE;YAAE,OAAO,IAAI,CAAC;QAC9B,+BAA+B,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,UAAU,CAAC;AAC1B,CAAC;AAiBD,iFAAiF;AACjF,+EAA+E;AAC/E,4EAA4E;AAC5E,gEAAgE;AAChE,SAAS,8BAA8B,CACrC,KAAkC,EAClC,SAAmE;IAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE;QAC1D,MAAM,WAAW,GAAG,MAAM,wBAAwB,CAChD,KAAK,EACL,SAAS,EACT,IAAI,EACJ,CAAC,SAAS,EAAE,EAAE,CACZ,2BAA2B,CACzB,KAAK,EACL,WAAW,EACX,OAAO,EACP,WAAW,EACX,OAAO,EACP,SAAS,CACV,EACH,WAAW,CACZ,CAAC;QACF,OAAO,WAAW,EAAE,MAAM,KAAK,UAAU;YACvC,CAAC,CAAC;gBACE,SAAS,EAAE,CACT,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,EAAE,CACF,wBAAwB,CACtB,KAAK,EACL,SAAS,EACT,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,iCAAiC,CAC/B,KAAK,EACL,WAAW,EACX,OAAO,EACP,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,CACV,EACH,WAAW,CACZ;gBACH,MAAM,EAAE,GAAG,EAAE,CACX,wBAAwB,CACtB,KAAK,EACL,SAAS,EACT,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,uBAAuB,CACrB,KAAK,EACL,SAAS,EACT,WAAW,EACX,OAAO,EACP,WAAW,EACX;oBACE,GAAG,OAAO;oBACV,kBAAkB,EAAE,WAAW,CAAC,kBAAkB;oBAClD,2DAA2D;oBAC3D,0DAA0D;oBAC1D,oBAAoB,EAAE,IAAI;iBAC3B,EACD,SAAS,CACV,EACH,WAAW,EACX,EAAE,0BAA0B,EAAE,IAAI,EAAE,CACrC;gBACH,MAAM,EAAE,UAAmB;aAC5B;YACH,CAAC,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,6BAA6B,CACpC,KAAkC,EAClC,SAA0C;IAE1C,OAAO;QACL,aAAa,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CACrC,wBAAwB,CACtB,KAAK,EACL,SAAS,EACT,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,sBAAsB,CACpB,KAAK,EACL,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,CACV,EACH,WAAW,EACX,EAAE,0BAA0B,EAAE,IAAI,EAAE,CACrC;QACH,cAAc,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,CAC7D,wBAAwB,CACtB,KAAK,EACL,SAAS,EACT,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,uBAAuB,CACrB,KAAK,EACL,SAAS,EACT,WAAW,EACX,OAAO,EACP,WAAW,EACX,OAAO,EACP,SAAS,CACV,EACH,WAAW,EACX,EAAE,0BAA0B,EAAE,IAAI,EAAE,CACrC;KACJ,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAClC,KAAkC,EAClC,SAA0C;IAE1C,OAAO,CAAC,WAAW,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,+BAA+B,CAAC,KAAK,CAAC,CAAC;QACvD,MAAM,YAAY,GAAG,GAAG,EAAE,CACxB,wBAAwB,CACtB,KAAK,EACL,SAAS,EACT,IAAI,EACJ,CAAC,SAAS,EAAE,EAAE,CACZ,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,EAC3D,WAAW,CACZ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,UAAU;YAC1D,OAAO,YAAY,EAAE,CAAC;QACxB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,mBAAmB,CACxB,KAAK,EACL,CAAC,SAAS,EAAE,EAAE;YACZ,sEAAsE;YACtE,yEAAyE;YACzE,QAAQ,GAAG,OAAO,CAChB,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,UAAU,CACzD,CAAC;YACF,OAAO,QAAQ;gBACb,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBACvB,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;QAChE,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,iCAAiC,CACxC,KAAkC,EAClC,SAA0C;IAE1C,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,CAAC,SAAwB,EAAE,EAAE,CACxC,qBAAqB,CACnB,KAAK,EACL,SAAS,EACT,UAAU,EACV,IAAI,EACJ,OAAO,EACP,SAAS,CACV,CAAC;QACJ,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;QAC3D,OAAO,OAAO,EAAE,oBAAoB;YAClC,CAAC,CAAC,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;YACtC,CAAC,CAAC,wBAAwB,CACtB,KAAK,EACL,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,SAAS,CAC5C,CAAC;IACR,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,KAAkC,EAClC,SAAmE;IAEnE,OAAO;QACL,GAAG,6BAA6B,CAAC,KAAK,EAAE,SAAS,CAAC;QAClD,WAAW,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAC9B,mBAAmB,CACjB,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,EACnE,CAAC,QAAQ,CAAC,CACX;QACH,eAAe,EAAE,2BAA2B,CAAC,KAAK,EAAE,SAAS,CAAC;QAC9D,cAAc,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CACvC,yBAAyB,CACvB,KAAK,EACL,SAAS,EACT,WAAW,EACX,OAAO,EACP,CAAC,SAAS,EAAE,EAAE,CACZ,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC,CACpE;QACH,UAAU,EAAE,CAAC,gBAAgB,EAAE,OAAO,EAAE,EAAE,CACxC,yBAAyB,CACvB,KAAK,EACL,SAAS,EACT,gBAAgB,EAChB,OAAO,EACP,CAAC,SAAS,EAAE,EAAE,CACZ,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,SAAS,CAAC,CACrE;QACH,qBAAqB,EAAE,iCAAiC,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,aAAa,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,EAAE,CACvC,mBAAmB,CACjB,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,EACnE,CAAC,WAAW,EAAE,QAAQ,CAAC,EACvB,WAAW,CACZ;QACH,kBAAkB,EAAE,8BAA8B,CAAC,KAAK,EAAE,SAAS,CAAC;QACpE,eAAe,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CACrC,mBAAmB,CACjB,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,CAAC,EACjE,CAAC,WAAW,CAAC,CACd;QACH,gBAAgB,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CACtC,mBAAmB,CACjB,KAAK,EACL,CAAC,SAAS,EAAE,EAAE,CACZ,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,CAAC,EAClE,CAAC,WAAW,CAAC,CACd;KACJ,CAAC;AACJ,CAAC;AAED,SAAS,iCAAiC,CACxC,cAA6C,EAC7C,cAA4C,mCAAmC,EAC/E,UAAyC,EAAE;IAE3C,MAAM,KAAK,GAAG,iCAAiC,CAC7C,cAAc,EACd,OAAO,CAAC,WAAW,IAAI,WAAW,EAClC,OAAO,CAAC,QAAQ,CACjB,CAAC;IACF,MAAM,SAAS,GAAG,qCAAqC,CAAC;QACtD,IAAI,EAAE,oCAAoC,CAAC,KAAK,CAAC;QACjD,KAAK;KACN,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,2BAA2B,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAEnE,OAAO;QACL,sBAAsB,EAAE,GAAG,EAAE;YAC3B,KAAK,CAAC,yBAAyB,GAAG,IAAI,CAAC;YACvC,SAAS,CAAC,YAAY,EAAE,CAAC;QAC3B,CAAC;QACD,KAAK,EAAE;YACL,GAAG,YAAY;YACf,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,sBAAsB,EAAE,IAAI,EAAE,CAAC;YAClE,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC;YAChE,2EAA2E;YAC3E,yEAAyE;YACzE,6EAA6E;YAC7E,sBAAsB,EAAE,GAAG,EAAE;gBAC3B,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC;gBACxC,OAAO,SAAS,CAAC,sBAAsB,EAAE,CAAC;YAC5C,CAAC;YACD,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE;YAC3C,kCAAkC,EAAE,CAAC,WAAW,EAAE,EAAE,CAClD,0CAA0C,CAAC,KAAK,EAAE,WAAW,CAAC;YAChE,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ;YACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE,CACtB,iCAAiC,CAAC,KAAK,EAAE,QAAQ,CAAC;YACpD,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CACzB,mCAAmC,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC;SACjE;QACD,aAAa,EAAE,CAAC,WAAW,EAAE,EAAE,CAC7B,kCAAkC,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC;KACpE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,cAA6C,EAC7C,cAA4C,mCAAmC,EAC/E,UAAyC,EAAE;IAE3C,OAAO,iCAAiC,CAAC,cAAc,EAAE,WAAW,EAAE,OAAO,CAAC;SAC3E,KAAK,CAAC;AACX,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,WAAwB,EACxB,OAAsC,EACtC,UAAyC,EAAE;IAE3C,MAAM,aAAa,GAAG,8BAA8B,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtE,IAAI,aAAa,EAAE,CAAC;QAClB,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,aAAa,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED,MAAM,SAAS,GAAG,iCAAiC,CACjD,OAAO,EACP,mCAAmC,EACnC,OAAO,CACR,CAAC;IACF,8BAA8B,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC3D,OAAO,SAAS,CAAC,KAAK,CAAC;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uCAAuC,CACrD,WAAwB;IAExB,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC9D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,sBAAsB,EAAE,CAAC;IAC/B,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { DomainScope } from \"../../data/shared/domainScope\";\nimport { getCachedContainerWriterProjection } from \"../../workflows/container-contents/container-state/projectionCache\";\nimport {\n type ContainerContentsPersistence,\n defaultContainerContentsPersistence,\n} from \"../../workflows/container-contents/containerPersistence\";\nimport { persistContainerState } from \"./containerState/containerStatePersistence\";\nimport {\n createChildContainer,\n deleteContainer,\n ensureSystemContainer,\n moveContainer,\n renameContainer,\n} from \"./operations\";\nimport { emptyTrash } from \"./operations/emptyTrashOperation\";\nimport {\n prepareContainerGroupRewrap,\n verifyContainerGroupRewrapCurrent,\n} from \"./operations/groupRewrapOperation\";\nimport { purgeContainer } from \"./operations/purgeContainerOperation\";\nimport { chainPurgeAfterScopeMoves } from \"./operations/purgeMoveSettlementOperation\";\nimport { setContainerIcon } from \"./operations/setContainerIconOperation\";\nimport {\n shareContainerWithGroup,\n shareContainerWithUser,\n} from \"./operations/shareOperations\";\nimport { invalidateRemoteContainerWrites } from \"./remoteWrites/remoteWriteGuards\";\nimport { chainRemoteContainerTask } from \"./remoteWrites/remoteWriteQueue\";\nimport { captureContainerWriteGeneration } from \"./remoteWrites/writeGeneration\";\nimport {\n createContainerContentsStoreState,\n subscribeToContainerContentsStore,\n updateContainerContentsSnapshot,\n updateContainerContentsStorePersistence,\n updateContainerContentsStoreRuntime,\n} from \"./state\";\nimport {\n type ContainerContentsStoreRuntime,\n type ContainerContentsStoreSyncAgent,\n createContainerContentsStoreSyncAgent,\n} from \"./syncAgent\";\nimport { findRootContainerState } from \"./systemContainers/systemContainerLookup\";\nimport type {\n ContainerContentsStore,\n ContainerContentsStoreOptions,\n ContainerContentsStoreState,\n} from \"./types\";\n\nconst containerContentsStoresByScope = new WeakMap<\n DomainScope,\n ContainerContentsStoreEntry\n>();\n\ninterface ContainerContentsStoreEntry {\n requestDocumentPriming: () => void;\n store: ContainerContentsStore;\n updateOptions: (options: ContainerContentsStoreOptions) => void;\n}\n\nfunction applyContainerContentsStoreOptions(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n options: ContainerContentsStoreOptions,\n): void {\n if (\"logLabel\" in options) {\n state.logLabel = options.logLabel;\n }\n\n if (\"persistence\" in options) {\n updateContainerContentsStorePersistence(\n state,\n options.persistence ?? defaultContainerContentsPersistence,\n syncAgent,\n );\n }\n}\n\nfunction getCachedContainerWriterProjectionForStore(\n state: ContainerContentsStoreState,\n containerId: string,\n) {\n const containerState = state.containersById.get(containerId);\n return containerState\n ? getCachedContainerWriterProjection(containerState)\n : null;\n}\n\nfunction createContainerContentsStoreSyncHost(\n state: ContainerContentsStoreState,\n): Parameters<typeof createContainerContentsStoreSyncAgent>[0][\"host\"] {\n return {\n persistContainerState: (\n containerState,\n patch,\n updateView,\n saveOptions,\n mutationOptions,\n ) =>\n persistContainerState(state, containerState, {\n patch,\n updateView,\n saveOptions,\n ...mutationOptions,\n }),\n requestDocumentPriming: () => {\n state.documentStoresNeedPriming = true;\n },\n updateSnapshot: () => updateContainerContentsSnapshot(state),\n };\n}\n\n// null marks an unknown mutation scope; [] delegates invalidation to actual writes.\nfunction chainContainerWrite(\n state: ContainerContentsStoreState,\n work: (isCurrent: () => boolean) => ContainerContentsStoreState[\"writeChain\"],\n changedIds: readonly string[] | null = null,\n movedId?: string,\n): ContainerContentsStoreState[\"writeChain\"] {\n const isCurrent = captureContainerWriteGeneration(state);\n invalidateRemoteContainerWrites(state, changedIds, movedId);\n state.writeChain = state.writeChain\n .catch(() => null)\n .then(() => {\n if (!isCurrent()) return null;\n invalidateRemoteContainerWrites(state, changedIds, movedId);\n return work(isCurrent);\n })\n .then((node) => (isCurrent() ? node : null));\n return state.writeChain;\n}\n\ntype ContainerWriteMethods = Pick<\n ContainerContentsStore,\n | \"createChild\"\n | \"deleteContainer\"\n | \"emptyTrash\"\n | \"ensureSystemContainer\"\n | \"moveContainer\"\n | \"prepareGroupRewrap\"\n | \"purgeContainer\"\n | \"renameContainer\"\n | \"setContainerIcon\"\n | \"shareWithGroup\"\n | \"shareWithUser\"\n>;\n\n// The group-rewrap builder verifies any required existing grant before capturing\n// the container KEK, then returns a check/rewrap pair. A verified non-match is\n// distinct from an unavailable preparation so security-critical callers can\n// no-op unrelated groups without failing open for a real grant.\nfunction createPrepareGroupRewrapMethod(\n state: ContainerContentsStoreState,\n syncAgent: ReturnType<typeof createContainerContentsStoreSyncAgent>,\n): ContainerContentsStore[\"prepareGroupRewrap\"] {\n return async (containerId, groupId, accessLevel, options) => {\n const preparation = await chainRemoteContainerTask(\n state,\n syncAgent,\n null,\n (isCurrent) =>\n prepareContainerGroupRewrap(\n state,\n containerId,\n groupId,\n accessLevel,\n options,\n isCurrent,\n ),\n containerId,\n );\n return preparation?.status === \"prepared\"\n ? {\n isCurrent: (\n expectedGroupHead,\n expectedContainerId,\n expectedOrganizationId,\n ) =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n verifyContainerGroupRewrapCurrent(\n state,\n containerId,\n groupId,\n accessLevel,\n expectedGroupHead,\n expectedContainerId,\n expectedOrganizationId,\n isCurrent,\n ),\n containerId,\n ),\n rewrap: () =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n shareContainerWithGroup(\n state,\n syncAgent,\n containerId,\n groupId,\n accessLevel,\n {\n ...options,\n knownContainerKeks: preparation.knownContainerKeks,\n // A prepared re-wrap is grant-preserving by definition, so\n // it never mints a grant and never needs the chosen name.\n requireExistingGrant: true,\n },\n isCurrent,\n ),\n containerId,\n { preserveResultOnLocalWrite: true },\n ),\n status: \"prepared\" as const,\n }\n : (preparation ?? null);\n };\n}\n\nfunction createContainerSharingMethods(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n): Pick<ContainerWriteMethods, \"shareWithUser\" | \"shareWithGroup\"> {\n return {\n shareWithUser: (containerId, userId) =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n shareContainerWithUser(\n state,\n syncAgent,\n containerId,\n userId,\n isCurrent,\n ),\n containerId,\n { preserveResultOnLocalWrite: true },\n ),\n shareWithGroup: (containerId, groupId, accessLevel, options) =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n shareContainerWithGroup(\n state,\n syncAgent,\n containerId,\n groupId,\n accessLevel,\n options,\n isCurrent,\n ),\n containerId,\n { preserveResultOnLocalWrite: true },\n ),\n };\n}\n\nfunction createDeleteContainerMethod(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n): ContainerContentsStore[\"deleteContainer\"] {\n return (containerId) => {\n const current = captureContainerWriteGeneration(state);\n const remoteDelete = () =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n null,\n (isCurrent) =>\n deleteContainer(state, syncAgent, containerId, isCurrent),\n containerId,\n ).then((node) => node !== null);\n if (state.containersById.get(containerId)?.record.documentId)\n return remoteDelete();\n let promoted = false;\n return chainContainerWrite(\n state,\n (isCurrent) => {\n // Promotion can win while this local operation was queued. Hand it to\n // the remote queue after releasing the local chain, before any HTTP I/O.\n promoted = Boolean(\n state.containersById.get(containerId)?.record.documentId,\n );\n return promoted\n ? Promise.resolve(null)\n : deleteContainer(state, syncAgent, containerId, isCurrent);\n },\n [containerId],\n ).then((node) => (promoted && current() ? remoteDelete() : node !== null));\n };\n}\n\nfunction createEnsureSystemContainerMethod(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n): ContainerContentsStore[\"ensureSystemContainer\"] {\n return (systemSlot, name, options) => {\n const work = (isCurrent: () => boolean) =>\n ensureSystemContainer(\n state,\n syncAgent,\n systemSlot,\n name,\n options,\n isCurrent,\n );\n const rootId = findRootContainerState(state)?.container.id;\n return options?.deferRemoteBootstrap\n ? chainContainerWrite(state, work, [])\n : chainRemoteContainerTask(\n state,\n syncAgent,\n null,\n work,\n rootId ? { rootId, systemSlot } : undefined,\n );\n };\n}\n\nexport function createContainerWriteMethods(\n state: ContainerContentsStoreState,\n syncAgent: ReturnType<typeof createContainerContentsStoreSyncAgent>,\n): ContainerWriteMethods {\n return {\n ...createContainerSharingMethods(state, syncAgent),\n createChild: (parentId, name) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n createChildContainer(state, syncAgent, parentId, name, isCurrent),\n [parentId],\n ),\n deleteContainer: createDeleteContainerMethod(state, syncAgent),\n purgeContainer: (containerId, options) =>\n chainPurgeAfterScopeMoves(\n state,\n syncAgent,\n containerId,\n options,\n (isCurrent) =>\n purgeContainer(state, syncAgent, containerId, options, isCurrent),\n ),\n emptyTrash: (trashContainerId, options) =>\n chainPurgeAfterScopeMoves(\n state,\n syncAgent,\n trashContainerId,\n options,\n (isCurrent) =>\n emptyTrash(state, syncAgent, trashContainerId, options, isCurrent),\n ),\n ensureSystemContainer: createEnsureSystemContainerMethod(state, syncAgent),\n moveContainer: (containerId, parentId) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n moveContainer(state, syncAgent, containerId, parentId, isCurrent),\n [containerId, parentId],\n containerId,\n ),\n prepareGroupRewrap: createPrepareGroupRewrapMethod(state, syncAgent),\n renameContainer: (containerId, name) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n renameContainer(state, syncAgent, containerId, name, isCurrent),\n [containerId],\n ),\n setContainerIcon: (containerId, icon) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n setContainerIcon(state, syncAgent, containerId, icon, isCurrent),\n [containerId],\n ),\n };\n}\n\nfunction createContainerContentsStoreEntry(\n initialRuntime: ContainerContentsStoreRuntime,\n persistence: ContainerContentsPersistence = defaultContainerContentsPersistence,\n options: ContainerContentsStoreOptions = {},\n): ContainerContentsStoreEntry {\n const state = createContainerContentsStoreState(\n initialRuntime,\n options.persistence ?? persistence,\n options.logLabel,\n );\n const syncAgent = createContainerContentsStoreSyncAgent({\n host: createContainerContentsStoreSyncHost(state),\n state,\n });\n const writeMethods = createContainerWriteMethods(state, syncAgent);\n\n return {\n requestDocumentPriming: () => {\n state.documentStoresNeedPriming = true;\n syncAgent.scheduleSync();\n },\n store: {\n ...writeMethods,\n refresh: () => syncAgent.refresh({ resetAllLaneWatermarks: true }),\n refreshRootLane: (options) => syncAgent.refreshRootLane(options),\n // Force an on-demand local SQLite re-read (see the interface doc): arm the\n // gate refreshLocalContainerStates otherwise requires, which the runtime\n // auto-arms only on a context transition an on-demand caller cannot rely on.\n refreshLocalContainers: () => {\n state.localContainersNeedRefresh = true;\n return syncAgent.refreshLocalContainers();\n },\n requestSync: () => syncAgent.scheduleSync(),\n getCachedContainerWriterProjection: (containerId) =>\n getCachedContainerWriterProjectionForStore(state, containerId),\n getSnapshot: () => state.snapshot,\n subscribe: (listener) =>\n subscribeToContainerContentsStore(state, listener),\n updateRuntime: (runtime) =>\n updateContainerContentsStoreRuntime(state, runtime, syncAgent),\n },\n updateOptions: (nextOptions) =>\n applyContainerContentsStoreOptions(state, syncAgent, nextOptions),\n };\n}\n\nexport function createContainerContentsStore(\n initialRuntime: ContainerContentsStoreRuntime,\n persistence: ContainerContentsPersistence = defaultContainerContentsPersistence,\n options: ContainerContentsStoreOptions = {},\n): ContainerContentsStore {\n return createContainerContentsStoreEntry(initialRuntime, persistence, options)\n .store;\n}\n\nexport function getOrCreateContainerContentsStore(\n domainScope: DomainScope,\n runtime: ContainerContentsStoreRuntime,\n options: ContainerContentsStoreOptions = {},\n): ContainerContentsStore {\n const existingEntry = containerContentsStoresByScope.get(domainScope);\n if (existingEntry) {\n existingEntry.updateOptions(options);\n return existingEntry.store;\n }\n\n const nextEntry = createContainerContentsStoreEntry(\n runtime,\n defaultContainerContentsPersistence,\n options,\n );\n containerContentsStoresByScope.set(domainScope, nextEntry);\n return nextEntry.store;\n}\n\n/**\n * Arm the next structural pass's document-priming scan for a domain scope.\n * Priming normally re-arms only on store creation and topology changes, so a\n * caller that just tore down a document's local state uses this to have the\n * still-listed server document re-created without waiting for an app\n * restart. Returns false when the scope has no container-contents store yet;\n * the startup priming pass covers that case.\n */\nexport function requestContainerContentsDocumentPriming(\n domainScope: DomainScope,\n): boolean {\n const entry = containerContentsStoresByScope.get(domainScope);\n if (!entry) {\n return false;\n }\n\n entry.requestDocumentPriming();\n return true;\n}\n"]}
1
+ {"version":3,"file":"containerContentsStore.js","sourceRoot":"","sources":["containerContentsStore.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DomainScope } from \"../../data/shared/domainScope\";\nimport { getCachedContainerWriterProjection } from \"../../workflows/container-contents/container-state/projectionCache\";\nimport {\n type ContainerContentsPersistence,\n defaultContainerContentsPersistence,\n} from \"../../workflows/container-contents/containerPersistence\";\nimport { persistContainerState } from \"./containerState/containerStatePersistence\";\nimport {\n createChildContainer,\n deleteContainer,\n ensureSystemContainer,\n moveContainer,\n renameContainer,\n} from \"./operations\";\nimport { emptyTrash } from \"./operations/emptyTrashOperation\";\nimport { createForgetOrganizationContentMethod } from \"./operations/forgetOrganizationContentOperation\";\nimport {\n prepareContainerGroupRewrap,\n verifyContainerGroupRewrapCurrent,\n} from \"./operations/groupRewrapOperation\";\nimport { purgeContainer } from \"./operations/purgeContainerOperation\";\nimport { chainPurgeAfterScopeMoves } from \"./operations/purgeMoveSettlementOperation\";\nimport { setContainerIcon } from \"./operations/setContainerIconOperation\";\nimport {\n shareContainerWithGroup,\n shareContainerWithUser,\n} from \"./operations/shareOperations\";\nimport { invalidateRemoteContainerWrites } from \"./remoteWrites/remoteWriteGuards\";\nimport { chainRemoteContainerTask } from \"./remoteWrites/remoteWriteQueue\";\nimport { captureContainerWriteGeneration } from \"./remoteWrites/writeGeneration\";\nimport {\n createContainerContentsStoreState,\n subscribeToContainerContentsStore,\n updateContainerContentsSnapshot,\n updateContainerContentsStorePersistence,\n updateContainerContentsStoreRuntime,\n} from \"./state\";\nimport {\n type ContainerContentsStoreRuntime,\n type ContainerContentsStoreSyncAgent,\n createContainerContentsStoreSyncAgent,\n} from \"./syncAgent\";\nimport { findRootContainerState } from \"./systemContainers/systemContainerLookup\";\nimport type {\n ContainerContentsStore,\n ContainerContentsStoreOptions,\n ContainerContentsStoreState,\n} from \"./types\";\n\nconst containerContentsStoresByScope = new WeakMap<\n DomainScope,\n ContainerContentsStoreEntry\n>();\n\ninterface ContainerContentsStoreEntry {\n requestDocumentPriming: () => void;\n store: ContainerContentsStore;\n updateOptions: (options: ContainerContentsStoreOptions) => void;\n}\n\nfunction applyContainerContentsStoreOptions(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n options: ContainerContentsStoreOptions,\n): void {\n if (\"logLabel\" in options) {\n state.logLabel = options.logLabel;\n }\n\n if (\"persistence\" in options) {\n updateContainerContentsStorePersistence(\n state,\n options.persistence ?? defaultContainerContentsPersistence,\n syncAgent,\n );\n }\n}\n\nfunction getCachedContainerWriterProjectionForStore(\n state: ContainerContentsStoreState,\n containerId: string,\n) {\n const containerState = state.containersById.get(containerId);\n return containerState\n ? getCachedContainerWriterProjection(containerState)\n : null;\n}\n\nfunction createContainerContentsStoreSyncHost(\n state: ContainerContentsStoreState,\n): Parameters<typeof createContainerContentsStoreSyncAgent>[0][\"host\"] {\n return {\n persistContainerState: (\n containerState,\n patch,\n updateView,\n saveOptions,\n mutationOptions,\n ) =>\n persistContainerState(state, containerState, {\n patch,\n updateView,\n saveOptions,\n ...mutationOptions,\n }),\n requestDocumentPriming: () => {\n state.documentStoresNeedPriming = true;\n },\n updateSnapshot: () => updateContainerContentsSnapshot(state),\n };\n}\n\n// null marks an unknown mutation scope; [] delegates invalidation to actual writes.\nfunction chainContainerWrite(\n state: ContainerContentsStoreState,\n work: (isCurrent: () => boolean) => ContainerContentsStoreState[\"writeChain\"],\n changedIds: readonly string[] | null = null,\n movedId?: string,\n): ContainerContentsStoreState[\"writeChain\"] {\n const isCurrent = captureContainerWriteGeneration(state);\n invalidateRemoteContainerWrites(state, changedIds, movedId);\n state.writeChain = state.writeChain\n .catch(() => null)\n .then(() => {\n if (!isCurrent()) return null;\n invalidateRemoteContainerWrites(state, changedIds, movedId);\n return work(isCurrent);\n })\n .then((node) => (isCurrent() ? node : null));\n return state.writeChain;\n}\n\ntype ContainerWriteMethods = Pick<\n ContainerContentsStore,\n | \"createChild\"\n | \"deleteContainer\"\n | \"emptyTrash\"\n | \"ensureSystemContainer\"\n | \"forgetOrganizationContent\"\n | \"moveContainer\"\n | \"prepareGroupRewrap\"\n | \"purgeContainer\"\n | \"renameContainer\"\n | \"setContainerIcon\"\n | \"shareWithGroup\"\n | \"shareWithUser\"\n>;\n\n// The group-rewrap builder verifies any required existing grant before capturing\n// the container KEK, then returns a check/rewrap pair. A verified non-match is\n// distinct from an unavailable preparation so security-critical callers can\n// no-op unrelated groups without failing open for a real grant.\nfunction createPrepareGroupRewrapMethod(\n state: ContainerContentsStoreState,\n syncAgent: ReturnType<typeof createContainerContentsStoreSyncAgent>,\n): ContainerContentsStore[\"prepareGroupRewrap\"] {\n return async (containerId, groupId, accessLevel, options) => {\n const preparation = await chainRemoteContainerTask(\n state,\n syncAgent,\n null,\n (isCurrent) =>\n prepareContainerGroupRewrap(\n state,\n containerId,\n groupId,\n accessLevel,\n options,\n isCurrent,\n ),\n containerId,\n );\n return preparation?.status === \"prepared\"\n ? {\n isCurrent: (\n expectedGroupHead,\n expectedContainerId,\n expectedOrganizationId,\n ) =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n verifyContainerGroupRewrapCurrent(\n state,\n containerId,\n groupId,\n accessLevel,\n expectedGroupHead,\n expectedContainerId,\n expectedOrganizationId,\n isCurrent,\n ),\n containerId,\n ),\n rewrap: () =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n shareContainerWithGroup(\n state,\n syncAgent,\n containerId,\n groupId,\n accessLevel,\n {\n ...options,\n knownContainerKeks: preparation.knownContainerKeks,\n // A prepared re-wrap is grant-preserving by definition, so\n // it never mints a grant and never needs the chosen name.\n requireExistingGrant: true,\n },\n isCurrent,\n ),\n containerId,\n { preserveResultOnLocalWrite: true },\n ),\n status: \"prepared\" as const,\n }\n : (preparation ?? null);\n };\n}\n\nfunction createContainerSharingMethods(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n): Pick<ContainerWriteMethods, \"shareWithUser\" | \"shareWithGroup\"> {\n return {\n shareWithUser: (containerId, userId) =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n shareContainerWithUser(\n state,\n syncAgent,\n containerId,\n userId,\n isCurrent,\n ),\n containerId,\n { preserveResultOnLocalWrite: true },\n ),\n shareWithGroup: (containerId, groupId, accessLevel, options) =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n false,\n (isCurrent) =>\n shareContainerWithGroup(\n state,\n syncAgent,\n containerId,\n groupId,\n accessLevel,\n options,\n isCurrent,\n ),\n containerId,\n { preserveResultOnLocalWrite: true },\n ),\n };\n}\n\nfunction createDeleteContainerMethod(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n): ContainerContentsStore[\"deleteContainer\"] {\n return (containerId) => {\n const current = captureContainerWriteGeneration(state);\n const remoteDelete = () =>\n chainRemoteContainerTask(\n state,\n syncAgent,\n null,\n (isCurrent) =>\n deleteContainer(state, syncAgent, containerId, isCurrent),\n containerId,\n ).then((node) => node !== null);\n if (state.containersById.get(containerId)?.record.documentId)\n return remoteDelete();\n let promoted = false;\n return chainContainerWrite(\n state,\n (isCurrent) => {\n // Promotion can win while this local operation was queued. Hand it to\n // the remote queue after releasing the local chain, before any HTTP I/O.\n promoted = Boolean(\n state.containersById.get(containerId)?.record.documentId,\n );\n return promoted\n ? Promise.resolve(null)\n : deleteContainer(state, syncAgent, containerId, isCurrent);\n },\n [containerId],\n ).then((node) => (promoted && current() ? remoteDelete() : node !== null));\n };\n}\n\nfunction createEnsureSystemContainerMethod(\n state: ContainerContentsStoreState,\n syncAgent: ContainerContentsStoreSyncAgent,\n): ContainerContentsStore[\"ensureSystemContainer\"] {\n return (systemSlot, name, options) => {\n const work = (isCurrent: () => boolean) =>\n ensureSystemContainer(\n state,\n syncAgent,\n systemSlot,\n name,\n options,\n isCurrent,\n );\n const rootId = findRootContainerState(state)?.container.id;\n return options?.deferRemoteBootstrap\n ? chainContainerWrite(state, work, [])\n : chainRemoteContainerTask(\n state,\n syncAgent,\n null,\n work,\n rootId ? { rootId, systemSlot } : undefined,\n );\n };\n}\n\nexport function createContainerWriteMethods(\n state: ContainerContentsStoreState,\n syncAgent: ReturnType<typeof createContainerContentsStoreSyncAgent>,\n): ContainerWriteMethods {\n return {\n ...createContainerSharingMethods(state, syncAgent),\n createChild: (parentId, name) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n createChildContainer(state, syncAgent, parentId, name, isCurrent),\n [parentId],\n ),\n deleteContainer: createDeleteContainerMethod(state, syncAgent),\n purgeContainer: (containerId, options) =>\n chainPurgeAfterScopeMoves(\n state,\n syncAgent,\n containerId,\n options,\n (isCurrent) =>\n purgeContainer(state, syncAgent, containerId, options, isCurrent),\n ),\n emptyTrash: (trashContainerId, options) =>\n chainPurgeAfterScopeMoves(\n state,\n syncAgent,\n trashContainerId,\n options,\n (isCurrent) =>\n emptyTrash(state, syncAgent, trashContainerId, options, isCurrent),\n ),\n ensureSystemContainer: createEnsureSystemContainerMethod(state, syncAgent),\n forgetOrganizationContent: createForgetOrganizationContentMethod(\n state,\n chainContainerWrite,\n ),\n moveContainer: (containerId, parentId) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n moveContainer(state, syncAgent, containerId, parentId, isCurrent),\n [containerId, parentId],\n containerId,\n ),\n prepareGroupRewrap: createPrepareGroupRewrapMethod(state, syncAgent),\n renameContainer: (containerId, name) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n renameContainer(state, syncAgent, containerId, name, isCurrent),\n [containerId],\n ),\n setContainerIcon: (containerId, icon) =>\n chainContainerWrite(\n state,\n (isCurrent) =>\n setContainerIcon(state, syncAgent, containerId, icon, isCurrent),\n [containerId],\n ),\n };\n}\n\nfunction createContainerContentsStoreEntry(\n initialRuntime: ContainerContentsStoreRuntime,\n persistence: ContainerContentsPersistence = defaultContainerContentsPersistence,\n options: ContainerContentsStoreOptions = {},\n): ContainerContentsStoreEntry {\n const state = createContainerContentsStoreState(\n initialRuntime,\n options.persistence ?? persistence,\n options.logLabel,\n );\n const syncAgent = createContainerContentsStoreSyncAgent({\n host: createContainerContentsStoreSyncHost(state),\n state,\n });\n const writeMethods = createContainerWriteMethods(state, syncAgent);\n\n return {\n requestDocumentPriming: () => {\n state.documentStoresNeedPriming = true;\n syncAgent.scheduleSync();\n },\n store: {\n ...writeMethods,\n refresh: () => syncAgent.refresh({ resetAllLaneWatermarks: true }),\n refreshRootLane: (options) => syncAgent.refreshRootLane(options),\n // Force an on-demand local SQLite re-read (see the interface doc): arm the\n // gate refreshLocalContainerStates otherwise requires, which the runtime\n // auto-arms only on a context transition an on-demand caller cannot rely on.\n refreshLocalContainers: () => {\n state.localContainersNeedRefresh = true;\n return syncAgent.refreshLocalContainers();\n },\n requestSync: () => syncAgent.scheduleSync(),\n getCachedContainerWriterProjection: (containerId) =>\n getCachedContainerWriterProjectionForStore(state, containerId),\n getSnapshot: () => state.snapshot,\n subscribe: (listener) =>\n subscribeToContainerContentsStore(state, listener),\n updateRuntime: (runtime) =>\n updateContainerContentsStoreRuntime(state, runtime, syncAgent),\n },\n updateOptions: (nextOptions) =>\n applyContainerContentsStoreOptions(state, syncAgent, nextOptions),\n };\n}\n\nexport function createContainerContentsStore(\n initialRuntime: ContainerContentsStoreRuntime,\n persistence: ContainerContentsPersistence = defaultContainerContentsPersistence,\n options: ContainerContentsStoreOptions = {},\n): ContainerContentsStore {\n return createContainerContentsStoreEntry(initialRuntime, persistence, options)\n .store;\n}\n\nexport function getOrCreateContainerContentsStore(\n domainScope: DomainScope,\n runtime: ContainerContentsStoreRuntime,\n options: ContainerContentsStoreOptions = {},\n): ContainerContentsStore {\n const existingEntry = containerContentsStoresByScope.get(domainScope);\n if (existingEntry) {\n existingEntry.updateOptions(options);\n return existingEntry.store;\n }\n\n const nextEntry = createContainerContentsStoreEntry(\n runtime,\n defaultContainerContentsPersistence,\n options,\n );\n containerContentsStoresByScope.set(domainScope, nextEntry);\n return nextEntry.store;\n}\n\n/**\n * Arm the next structural pass's document-priming scan for a domain scope.\n * Priming normally re-arms only on store creation and topology changes, so a\n * caller that just tore down a document's local state uses this to have the\n * still-listed server document re-created without waiting for an app\n * restart. Returns false when the scope has no container-contents store yet;\n * the startup priming pass covers that case.\n */\nexport function requestContainerContentsDocumentPriming(\n domainScope: DomainScope,\n): boolean {\n const entry = containerContentsStoresByScope.get(domainScope);\n if (!entry) {\n return false;\n }\n\n entry.requestDocumentPriming();\n return true;\n}\n"]}
@@ -0,0 +1,76 @@
1
+ import { removeOrganizationContentUnlessPending } from "../../../workflows/container-contents/syncPause/documentRemoval.js";
2
+ import { reclaimDocumentOrphanBlobs } from "../../../workflows/documents/index.js";
3
+ import { getOrCreateOrganizationSyncPauses, isRetainedWhileSyncPaused, } from "../../../workflows/sync/index.js";
4
+ import { emitPersistedDocumentDeletion, hasQueuedDocumentStoreWrites, restoreDocumentStore, retireDocumentStore, } from "../../documents/registry.js";
5
+ import { updateContainerContentsSnapshot } from "../state.js";
6
+ /** The local containers forgetting an organization's content removes. */
7
+ function listForgettableOrganizationContainerIds(state, organizationId) {
8
+ return [...state.containersById.values()].flatMap(({ container }) => container.organizationId === organizationId &&
9
+ !isRetainedWhileSyncPaused(container)
10
+ ? [container.id]
11
+ : []);
12
+ }
13
+ /**
14
+ * Removes one organization's content from this device after its sync was
15
+ * paused: every container except its retained metadata root, and every
16
+ * document placed only in those containers. Nothing changes on the server, so
17
+ * resuming downloads it again.
18
+ *
19
+ * Unsynced work is never removed: the removal refuses while any pending write
20
+ * touches the organization, checked under the same lock as the deletions, and
21
+ * while an open store holds edits for any of its documents that have not
22
+ * reached SQLite. It also refuses the session's active organization, whose
23
+ * root the session still writes to. Returns whether nothing is left to retry.
24
+ */
25
+ async function forgetOrganizationContent(state, organizationId, isCurrent) {
26
+ if (state.runtime.infra.dbStatus !== "ready" || !state.snapshot.ready) {
27
+ return false;
28
+ }
29
+ if (state.runtime.auth.organizationId === organizationId)
30
+ return false;
31
+ const containerIds = listForgettableOrganizationContainerIds(state, organizationId);
32
+ const { documentProjectors, execSql } = state.runtime.infra;
33
+ const { domainScope } = state.runtime.state;
34
+ // Switching into the organization mid-removal stops it before any deletion.
35
+ const stillCurrent = () => isCurrent() && state.runtime.auth.organizationId !== organizationId;
36
+ await state.persistence.ensureSchema(execSql);
37
+ const pauses = getOrCreateOrganizationSyncPauses(domainScope);
38
+ const removal = await removeOrganizationContentUnlessPending({
39
+ containerIds,
40
+ deleteContainers: (lockedExecSql, removals) => state.persistence.deleteContainers(lockedExecSql, removals, {
41
+ stillCurrent,
42
+ }),
43
+ documentProjectors,
44
+ execSql,
45
+ hasQueuedWrites: (localId) => hasQueuedDocumentStoreWrites(domainScope, localId),
46
+ organizationId,
47
+ restoreDocument: (localId) => restoreDocumentStore(domainScope, localId),
48
+ retireDocument: (localId) => retireDocumentStore(domainScope, localId, () => pauses.isOrganizationPaused(organizationId)),
49
+ stillCurrent,
50
+ });
51
+ for (const localId of removal.deletedLocalIds) {
52
+ emitPersistedDocumentDeletion(domainScope, localId);
53
+ }
54
+ if (removal.deletedLocalIds.length > 0) {
55
+ void reclaimDocumentOrphanBlobs(state.runtime);
56
+ }
57
+ for (const containerId of removal.deletedContainerIds) {
58
+ state.containersById.delete(containerId);
59
+ }
60
+ if (removal.deletedContainerIds.length > 0 && state.initialized) {
61
+ updateContainerContentsSnapshot(state);
62
+ }
63
+ return removal.status === "removed";
64
+ }
65
+ /** Runs `forgetOrganizationContent` in the store's container write chain. */
66
+ export function createForgetOrganizationContentMethod(state, chainContainerWrite) {
67
+ return async (organizationId) => {
68
+ let forgotten = false;
69
+ await chainContainerWrite(state, async (isCurrent) => {
70
+ forgotten = await forgetOrganizationContent(state, organizationId, isCurrent);
71
+ return null;
72
+ }, listForgettableOrganizationContainerIds(state, organizationId));
73
+ return forgotten;
74
+ };
75
+ }
76
+ //# sourceMappingURL=forgetOrganizationContentOperation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forgetOrganizationContentOperation.js","sourceRoot":"","sources":["forgetOrganizationContentOperation.ts"],"names":[],"mappings":"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","sourcesContent":["import { removeOrganizationContentUnlessPending } from \"../../../workflows/container-contents/syncPause/documentRemoval\";\nimport { reclaimDocumentOrphanBlobs } from \"../../../workflows/documents\";\nimport {\n getOrCreateOrganizationSyncPauses,\n isRetainedWhileSyncPaused,\n} from \"../../../workflows/sync\";\nimport {\n emitPersistedDocumentDeletion,\n hasQueuedDocumentStoreWrites,\n restoreDocumentStore,\n retireDocumentStore,\n} from \"../../documents/registry\";\nimport type { ContainerWriteGuard } from \"../remoteWrites/writeGeneration\";\nimport { updateContainerContentsSnapshot } from \"../state\";\nimport type { ContainerContentsStoreState } from \"../types\";\n\n/** The local containers forgetting an organization's content removes. */\nfunction listForgettableOrganizationContainerIds(\n state: Pick<ContainerContentsStoreState, \"containersById\">,\n organizationId: string,\n): string[] {\n return [...state.containersById.values()].flatMap(({ container }) =>\n container.organizationId === organizationId &&\n !isRetainedWhileSyncPaused(container)\n ? [container.id]\n : [],\n );\n}\n\n/**\n * Removes one organization's content from this device after its sync was\n * paused: every container except its retained metadata root, and every\n * document placed only in those containers. Nothing changes on the server, so\n * resuming downloads it again.\n *\n * Unsynced work is never removed: the removal refuses while any pending write\n * touches the organization, checked under the same lock as the deletions, and\n * while an open store holds edits for any of its documents that have not\n * reached SQLite. It also refuses the session's active organization, whose\n * root the session still writes to. Returns whether nothing is left to retry.\n */\nasync function forgetOrganizationContent(\n state: ContainerContentsStoreState,\n organizationId: string,\n isCurrent: ContainerWriteGuard,\n): Promise<boolean> {\n if (state.runtime.infra.dbStatus !== \"ready\" || !state.snapshot.ready) {\n return false;\n }\n if (state.runtime.auth.organizationId === organizationId) return false;\n const containerIds = listForgettableOrganizationContainerIds(\n state,\n organizationId,\n );\n const { documentProjectors, execSql } = state.runtime.infra;\n const { domainScope } = state.runtime.state;\n // Switching into the organization mid-removal stops it before any deletion.\n const stillCurrent = () =>\n isCurrent() && state.runtime.auth.organizationId !== organizationId;\n await state.persistence.ensureSchema(execSql);\n const pauses = getOrCreateOrganizationSyncPauses(domainScope);\n const removal = await removeOrganizationContentUnlessPending({\n containerIds,\n deleteContainers: (lockedExecSql, removals) =>\n state.persistence.deleteContainers(lockedExecSql, removals, {\n stillCurrent,\n }),\n documentProjectors,\n execSql,\n hasQueuedWrites: (localId) =>\n hasQueuedDocumentStoreWrites(domainScope, localId),\n organizationId,\n restoreDocument: (localId) => restoreDocumentStore(domainScope, localId),\n retireDocument: (localId) =>\n retireDocumentStore(domainScope, localId, () =>\n pauses.isOrganizationPaused(organizationId),\n ),\n stillCurrent,\n });\n for (const localId of removal.deletedLocalIds) {\n emitPersistedDocumentDeletion(domainScope, localId);\n }\n if (removal.deletedLocalIds.length > 0) {\n void reclaimDocumentOrphanBlobs(state.runtime);\n }\n for (const containerId of removal.deletedContainerIds) {\n state.containersById.delete(containerId);\n }\n if (removal.deletedContainerIds.length > 0 && state.initialized) {\n updateContainerContentsSnapshot(state);\n }\n return removal.status === \"removed\";\n}\n\ntype ContainerWriteChain = (\n state: ContainerContentsStoreState,\n work: (isCurrent: () => boolean) => ContainerContentsStoreState[\"writeChain\"],\n changedIds: readonly string[],\n) => ContainerContentsStoreState[\"writeChain\"];\n\n/** Runs `forgetOrganizationContent` in the store's container write chain. */\nexport function createForgetOrganizationContentMethod(\n state: ContainerContentsStoreState,\n chainContainerWrite: ContainerWriteChain,\n): (organizationId: string) => Promise<boolean> {\n return async (organizationId) => {\n let forgotten = false;\n await chainContainerWrite(\n state,\n async (isCurrent) => {\n forgotten = await forgetOrganizationContent(\n state,\n organizationId,\n isCurrent,\n );\n return null;\n },\n listForgettableOrganizationContainerIds(state, organizationId),\n );\n return forgotten;\n };\n}\n"]}
@@ -53,6 +53,12 @@ export interface ContainerContentsStore {
53
53
  moveContainer: (containerId: string, parentId: string) => Promise<ContainerNode | null>;
54
54
  purgeContainer: (containerId: string, options?: PurgeOptions) => Promise<boolean>;
55
55
  emptyTrash: (trashContainerId: string, options?: PurgeOptions) => Promise<boolean>;
56
+ /**
57
+ * Removes a paused organization's content from this device: every container
58
+ * except its metadata root, and every document placed only in them. Local
59
+ * only; the caller first confirms the organization has no unsynced writes.
60
+ */
61
+ forgetOrganizationContent: (organizationId: string) => Promise<boolean>;
56
62
  prepareGroupRewrap: (containerId: string, groupId: string, accessLevel: ContainerContentsShareAccessLevel, options?: {
57
63
  requireExistingGrant?: boolean;
58
64
  } | undefined) => Promise<ContainerGroupRewrapPreparation | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ContainerAccessLevel,\n ReferencedPrincipalHead,\n} from \"@tearleads/crypto\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type { PurgeOptions } from \"../../workflows/container-contents/container-state/purge/purgeProgress\";\nimport type { ContainerContentsPersistence } from \"../../workflows/container-contents/containerPersistence\";\nimport type { ContainerDocumentObjectSyncState } from \"../../workflows/container-contents/syncState\";\nimport type {\n ContainerContentsStoreRuntime,\n ContainerContentsStoreSyncState,\n RefreshRootLaneOptions,\n} from \"./syncAgent/syncAgentTypes\";\n\n// Reuse the canonical access-level union from the crypto layer (the same source\n// `ContainerShareAccessLevel` chains to) rather than re-spelling the literals,\n// so the two can't drift.\nexport type ContainerContentsShareAccessLevel = ContainerAccessLevel;\n\nexport interface ContainerContentsStoreOptions {\n logLabel?: string | undefined;\n persistence?: ContainerContentsPersistence | undefined;\n}\n\nexport interface ContainerNode {\n systemSlot?: ContainerSystemSlot | null;\n createdAt?: string | null;\n effectiveAccessLevel?: ContainerAccessLevel | undefined;\n id: string;\n icon?: string | null;\n metadataDocumentId?: string | null;\n /** False while a discovered remote folder has no local metadata content. */\n metadataReady?: boolean;\n organizationId: string;\n name: string;\n parentId: string | null;\n syncState: ContainerDocumentObjectSyncState;\n kind: \"container\";\n updatedAt?: string | null;\n}\n\n// The store surface exposed through context: the snapshot fields plus the\n// store's mutation/refresh methods, spelled as a Pick so the two can't drift.\nexport type ContainerContentsContextValue = ContainerContentsSnapshot &\n Pick<\n ContainerContentsStore,\n | \"createChild\"\n | \"deleteContainer\"\n | \"emptyTrash\"\n | \"ensureSystemContainer\"\n | \"moveContainer\"\n | \"purgeContainer\"\n | \"refresh\"\n | \"refreshRootLane\"\n | \"renameContainer\"\n | \"requestSync\"\n | \"setContainerIcon\"\n | \"shareWithGroup\"\n | \"shareWithUser\"\n >;\n\nexport interface ContainerContentsSnapshot {\n nodes: ReadonlyArray<ContainerNode>;\n ready: boolean;\n}\n\nexport type ContainerGroupRewrapPreparation =\n | {\n status: \"not-granted\";\n }\n | {\n isCurrent(\n expectedGroupHead: ReferencedPrincipalHead,\n expectedContainerId: string,\n expectedOrganizationId: string,\n ): Promise<boolean>;\n rewrap(): Promise<boolean>;\n status: \"prepared\";\n };\n\n/**\n * Shared per-scope container tree and mutation store.\n *\n * Ordinary metadata/topology writes (`createChild`, `moveContainer`,\n * `renameContainer`, and `setContainerIcon`) commit to local persistence and\n * update subscribers before their queued remote sync converges. Destructive\n * and access-control operations retain their explicit remote-authority gates.\n */\nexport interface ContainerContentsStore {\n createChild: (\n parentId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n deleteContainer: (containerId: string) => Promise<boolean>;\n ensureSystemContainer: (\n systemSlot: ContainerSystemSlot,\n name: string,\n options?: EnsureSystemContainerOptions | undefined,\n ) => Promise<ContainerNode | null>;\n moveContainer: (\n containerId: string,\n parentId: string,\n ) => Promise<ContainerNode | null>;\n purgeContainer: (\n containerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n emptyTrash: (\n trashContainerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n // `options.requireExistingGrant` gates the preparation check only. The\n // prepared `rewrap` is always grant-preserving: it re-wraps a signed grant\n // and never mints one, so it carries no chosen group name, and it throws\n // (rather than healing through a policy mutation) when the container\n // manifest grants the group but the verified policy has no matching grant.\n prepareGroupRewrap: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options?: { requireExistingGrant?: boolean } | undefined,\n ) => Promise<ContainerGroupRewrapPreparation | null>;\n refresh: () => Promise<boolean>;\n refreshRootLane: (options?: RefreshRootLaneOptions) => Promise<boolean>;\n // Re-read root-lane containers from local SQLite into the snapshot with NO\n // server round-trip. Surfaces a just-persisted container — e.g. the Trash bin\n // that registration/org-creation provisioned server-side and wrote to SQLite\n // via persistRegistrationBootstrap — instantly, instead of waiting for the\n // remote root-lane pull. Idempotent with a later remote pull: the merge is\n // keyed by container id, so the pull reconciles in place rather than duplicating.\n refreshLocalContainers: () => Promise<void>;\n requestSync: () => void;\n renameContainer: (\n containerId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n setContainerIcon: (\n containerId: string,\n icon: string | null,\n ) => Promise<ContainerNode | null>;\n shareWithGroup: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options: {\n /**\n * The display name the group was chosen by. Required: the share fails\n * closed if the verified group policy commits a different name. Signed\n * names are unique within an organization by construction (enforced at\n * group creation), so the target's own name identifies it.\n */\n expectedGroupName: string;\n },\n ) => Promise<boolean>;\n shareWithUser: (containerId: string, userId: string) => Promise<boolean>;\n getCachedContainerWriterProjection: (\n containerId: string,\n ) => ContainerWriterProjectionResponse | null;\n getSnapshot: () => ContainerContentsSnapshot;\n subscribe: (listener: () => void) => () => void;\n updateRuntime: (runtime: ContainerContentsStoreRuntime) => void;\n}\n\nexport interface EnsureSystemContainerOptions {\n icon?: string | null | undefined;\n skipAdvancedManagedRoot?: boolean | undefined;\n // For local-first bootstrap paths where slow remote I/O must not block the\n // caller from creating the deterministic local system container.\n deferRemoteBootstrap?: boolean | undefined;\n // Create the deterministic local system container without queuing the remote\n // create. A later ensureSystemContainer call without this flag promotes the\n // local slot into the sync queue.\n deferRemoteSync?: boolean | undefined;\n}\n\nexport interface ContainerContentsStoreState\n extends ContainerContentsStoreSyncState {\n listeners: Set<() => void>;\n snapshot: ContainerContentsSnapshot;\n writeChain: Promise<ContainerNode | null>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ContainerAccessLevel,\n ReferencedPrincipalHead,\n} from \"@tearleads/crypto\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type { PurgeOptions } from \"../../workflows/container-contents/container-state/purge/purgeProgress\";\nimport type { ContainerContentsPersistence } from \"../../workflows/container-contents/containerPersistence\";\nimport type { ContainerDocumentObjectSyncState } from \"../../workflows/container-contents/syncState\";\nimport type {\n ContainerContentsStoreRuntime,\n ContainerContentsStoreSyncState,\n RefreshRootLaneOptions,\n} from \"./syncAgent/syncAgentTypes\";\n\n// Reuse the canonical access-level union from the crypto layer (the same source\n// `ContainerShareAccessLevel` chains to) rather than re-spelling the literals,\n// so the two can't drift.\nexport type ContainerContentsShareAccessLevel = ContainerAccessLevel;\n\nexport interface ContainerContentsStoreOptions {\n logLabel?: string | undefined;\n persistence?: ContainerContentsPersistence | undefined;\n}\n\nexport interface ContainerNode {\n systemSlot?: ContainerSystemSlot | null;\n createdAt?: string | null;\n effectiveAccessLevel?: ContainerAccessLevel | undefined;\n id: string;\n icon?: string | null;\n metadataDocumentId?: string | null;\n /** False while a discovered remote folder has no local metadata content. */\n metadataReady?: boolean;\n organizationId: string;\n name: string;\n parentId: string | null;\n syncState: ContainerDocumentObjectSyncState;\n kind: \"container\";\n updatedAt?: string | null;\n}\n\n// The store surface exposed through context: the snapshot fields plus the\n// store's mutation/refresh methods, spelled as a Pick so the two can't drift.\nexport type ContainerContentsContextValue = ContainerContentsSnapshot &\n Pick<\n ContainerContentsStore,\n | \"createChild\"\n | \"deleteContainer\"\n | \"emptyTrash\"\n | \"ensureSystemContainer\"\n | \"moveContainer\"\n | \"purgeContainer\"\n | \"refresh\"\n | \"refreshRootLane\"\n | \"renameContainer\"\n | \"requestSync\"\n | \"setContainerIcon\"\n | \"shareWithGroup\"\n | \"shareWithUser\"\n >;\n\nexport interface ContainerContentsSnapshot {\n nodes: ReadonlyArray<ContainerNode>;\n ready: boolean;\n}\n\nexport type ContainerGroupRewrapPreparation =\n | {\n status: \"not-granted\";\n }\n | {\n isCurrent(\n expectedGroupHead: ReferencedPrincipalHead,\n expectedContainerId: string,\n expectedOrganizationId: string,\n ): Promise<boolean>;\n rewrap(): Promise<boolean>;\n status: \"prepared\";\n };\n\n/**\n * Shared per-scope container tree and mutation store.\n *\n * Ordinary metadata/topology writes (`createChild`, `moveContainer`,\n * `renameContainer`, and `setContainerIcon`) commit to local persistence and\n * update subscribers before their queued remote sync converges. Destructive\n * and access-control operations retain their explicit remote-authority gates.\n */\nexport interface ContainerContentsStore {\n createChild: (\n parentId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n deleteContainer: (containerId: string) => Promise<boolean>;\n ensureSystemContainer: (\n systemSlot: ContainerSystemSlot,\n name: string,\n options?: EnsureSystemContainerOptions | undefined,\n ) => Promise<ContainerNode | null>;\n moveContainer: (\n containerId: string,\n parentId: string,\n ) => Promise<ContainerNode | null>;\n purgeContainer: (\n containerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n emptyTrash: (\n trashContainerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n /**\n * Removes a paused organization's content from this device: every container\n * except its metadata root, and every document placed only in them. Local\n * only; the caller first confirms the organization has no unsynced writes.\n */\n forgetOrganizationContent: (organizationId: string) => Promise<boolean>;\n // `options.requireExistingGrant` gates the preparation check only. The\n // prepared `rewrap` is always grant-preserving: it re-wraps a signed grant\n // and never mints one, so it carries no chosen group name, and it throws\n // (rather than healing through a policy mutation) when the container\n // manifest grants the group but the verified policy has no matching grant.\n prepareGroupRewrap: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options?: { requireExistingGrant?: boolean } | undefined,\n ) => Promise<ContainerGroupRewrapPreparation | null>;\n refresh: () => Promise<boolean>;\n refreshRootLane: (options?: RefreshRootLaneOptions) => Promise<boolean>;\n // Re-read root-lane containers from local SQLite into the snapshot with NO\n // server round-trip. Surfaces a just-persisted container — e.g. the Trash bin\n // that registration/org-creation provisioned server-side and wrote to SQLite\n // via persistRegistrationBootstrap — instantly, instead of waiting for the\n // remote root-lane pull. Idempotent with a later remote pull: the merge is\n // keyed by container id, so the pull reconciles in place rather than duplicating.\n refreshLocalContainers: () => Promise<void>;\n requestSync: () => void;\n renameContainer: (\n containerId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n setContainerIcon: (\n containerId: string,\n icon: string | null,\n ) => Promise<ContainerNode | null>;\n shareWithGroup: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options: {\n /**\n * The display name the group was chosen by. Required: the share fails\n * closed if the verified group policy commits a different name. Signed\n * names are unique within an organization by construction (enforced at\n * group creation), so the target's own name identifies it.\n */\n expectedGroupName: string;\n },\n ) => Promise<boolean>;\n shareWithUser: (containerId: string, userId: string) => Promise<boolean>;\n getCachedContainerWriterProjection: (\n containerId: string,\n ) => ContainerWriterProjectionResponse | null;\n getSnapshot: () => ContainerContentsSnapshot;\n subscribe: (listener: () => void) => () => void;\n updateRuntime: (runtime: ContainerContentsStoreRuntime) => void;\n}\n\nexport interface EnsureSystemContainerOptions {\n icon?: string | null | undefined;\n skipAdvancedManagedRoot?: boolean | undefined;\n // For local-first bootstrap paths where slow remote I/O must not block the\n // caller from creating the deterministic local system container.\n deferRemoteBootstrap?: boolean | undefined;\n // Create the deterministic local system container without queuing the remote\n // create. A later ensureSystemContainer call without this flag promotes the\n // local slot into the sync queue.\n deferRemoteSync?: boolean | undefined;\n}\n\nexport interface ContainerContentsStoreState\n extends ContainerContentsStoreSyncState {\n listeners: Set<() => void>;\n snapshot: ContainerContentsSnapshot;\n writeChain: Promise<ContainerNode | null>;\n}\n"]}
@@ -6,7 +6,7 @@ import { ensureDocumentStoreReady } from "../initialization/index.js";
6
6
  import { runDocumentOrphanMaintenance } from "../orphanMaintenance.js";
7
7
  import { advancePendingBaseVersion, pendingDeltaSinceBase, persistDocument, } from "../persistence.js";
8
8
  import { reportDocumentStoreWriteFailure } from "../reportWriteFailure.js";
9
- import { canWriteDocument, setReadySnapshot, } from "../state.js";
9
+ import { canWriteDocument, chainQueuedWrite, setReadySnapshot, } from "../state.js";
10
10
  import { captureDocumentStoreSyncGeneration } from "../sync/syncGeneration.js";
11
11
  import { restoreFailedAttachmentMutation } from "./attachmentMutationPersistence.js";
12
12
  import { assignLocalAttachmentSlots, removeLocalAttachmentSlot, } from "./attachmentPersistence.js";
@@ -125,12 +125,11 @@ export async function removeAttachmentFromDocumentStore(state, scheduleSync, slo
125
125
  const writeGeneration = captureAttachmentWriteGeneration(state);
126
126
  if (!writeGeneration)
127
127
  return;
128
- state.writeChain = state.writeChain
128
+ return chainQueuedWrite(state, state.writeChain
129
129
  .catch(() => undefined)
130
130
  .then(async () => persistRemovedAttachment(state, slotId, writeGeneration))
131
131
  .catch((error) => {
132
132
  reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);
133
- });
134
- return state.writeChain;
133
+ }));
135
134
  }
136
135
  //# sourceMappingURL=attachmentRemoval.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"attachmentRemoval.js","sourceRoot":"","sources":["attachmentRemoval.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EACL,gBAAgB,EAEhB,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kCAAkC,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,EAAE,+BAA+B,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,gCAAgC,EAChC,kCAAkC,EAClC,oCAAoC,GACrC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAErD,SAAS,iCAAiC,CAAC,KAM1C;IACC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAC5C,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,MAAM,OAAO,GAAG,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAC3C,CAAC,UAAU,EAAE,EAAE,CACb,UAAU,CAAC,MAAM,KAAK,MAAM,IAAI,UAAU,CAAC,UAAU,KAAK,UAAU,CACvE,CAAC;IACF,IAAI,KAAK,CAAC,gBAAgB,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QAC9C,0BAA0B,CAAC,KAAK,EAAE;YAChC;gBACE,MAAM;gBACN,UAAU;gBACV,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM;gBAC7B,aAAa,EAAE,OAAO,CAAC,aAAa;aACrC;SACF,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,kBAAkB,CAAC,MAAM,CACxD,CAAC,UAAU,EAAE,EAAE,CACb,UAAU,CAAC,MAAM,KAAK,MAAM,IAAI,UAAU,CAAC,UAAU,KAAK,UAAU,CACvE,CAAC;IACF,4EAA4E;IAC5E,uEAAuE;IACvE,KAAK,4BAA4B,CAAC,KAAK,CAAC,CAAC;IACzC,IACE,KAAK,CAAC,gBAAgB;QACtB,KAAK,CAAC,4BAA4B,CAAC,MAAM,CAAC,KAAK,UAAU,EACzD,CAAC;QACD,OAAO;IACT,CAAC;IACD,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACzC,gBAAgB,CACd,KAAK,EACL,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,QAAQ,CAAC,OAAO,EACtB,KAAK,CAAC,QAAQ,CAAC,IAAI,EACnB,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAChC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,KAAyB,EACzB,MAAc,EACd,eAA0C;IAE1C,IAAI,CAAC,kCAAkC,CAAC,KAAK,EAAE,eAAe,CAAC;QAAE,OAAO;IACxE,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC;IAC7B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;IACT,CAAC;IACD,MAAM,UAAU,GAAG,kCAAkC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACzE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;IACT,CAAC;IAED,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC,IAAI,CAChE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,MAAM,CAC7C,CAAC;IACF,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,MAAM,UAAU,GACd,KAAK,CAAC,4BAA4B,CAAC,MAAM,CAAC;QAC1C,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,MAAM,CAAC;YACzE,EAAE,UAAU,CAAC;IACjB,IACE,CAAC,kCAAkC,CAAC,KAAK,EAAE,eAAe,CAAC;QAC3D,KAAK,CAAC,GAAG,KAAK,UAAU;QAExB,OAAO;IACT,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC;IACvE,wBAAwB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAClE,MAAM,cAAc,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,yBAAyB,CAAC,gBAAgB,CAAC,CAAC;IAClE,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAE3D,6EAA6E;IAC7E,mEAAmE;IACnE,IAAI,SAAsD,CAAC;IAC3D,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,eAAe,CAC/B,KAAK,EACL,UAAU,EACV,EAAE,kBAAkB,EAAE,cAAc,EAAE,EACtC;YACE,GAAG,CAAC,UAAU;gBACZ,CAAC,CAAC;oBACE,iBAAiB,EAAE;wBACjB,IAAI,EAAE,gBAAgB;4BACpB,CAAC,CAAE,QAAkB;4BACrB,CAAC,CAAE,QAAkB;wBACvB,MAAM;wBACN,UAAU;qBACX;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,gCAAgC,EAAE,IAAI;YACtC,oBAAoB,EAAE,IAAI;SAC3B,EACD,UAAU,CACX,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,+BAA+B,CAAC;YACpC,UAAU;YACV,gBAAgB;YAChB,KAAK;SACN,CAAC,CAAC;QACH,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IACE,oCAAoC,CAClC,KAAK,EACL,eAAe,EACf,UAAU,EACV,SAAS,CACV,EACD,CAAC;QACD,0EAA0E;QAC1E,OAAO;IACT,CAAC;IACD,iCAAiC,CAAC;QAChC,UAAU;QACV,MAAM;QACN,KAAK;QACL,UAAU;QACV,gBAAgB;KACjB,CAAC,CAAC;IACH,yBAAyB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC7C,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CACpB,sBAAsB,kBAAkB,CAAC,IAAI,kBAAkB,KAAK,CAAC,OAAO,GAAG,CAChF,CAAC;IACF,wBAAwB,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,KAAyB,EACzB,YAAwB,EACxB,MAAc;IAEd,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,wBAAwB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+BAA+B,CAAC,KAAK,EAAE,0BAA0B,EAAE,KAAK,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IAED,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO;IACT,CAAC;IAED,MAAM,eAAe,GAAG,gCAAgC,CAAC,KAAK,CAAC,CAAC;IAChE,IAAI,CAAC,eAAe;QAAE,OAAO;IAC7B,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU;SAChC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;SACtB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;SAC1E,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,+BAA+B,CAAC,KAAK,EAAE,0BAA0B,EAAE,KAAK,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IACL,OAAO,KAAK,CAAC,UAAU,CAAC;AAC1B,CAAC","sourcesContent":["import {\n encodeVersionVector,\n exportFullHistorySnapshot,\n} from \"@tearleads/loro\";\nimport {\n getDocumentAttachments,\n removeDocumentAttachment,\n} from \"../../../../data/documents/documentContent\";\nimport { createPendingUpdateFields } from \"../../../../data/documents/documentSync\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { ensureDocumentStoreReady } from \"../initialization\";\nimport { runDocumentOrphanMaintenance } from \"../orphanMaintenance\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n persistDocument,\n} from \"../persistence\";\nimport { reportDocumentStoreWriteFailure } from \"../reportWriteFailure\";\nimport {\n canWriteDocument,\n type DocumentStoreState,\n setReadySnapshot,\n} from \"../state\";\nimport { captureDocumentStoreSyncGeneration } from \"../sync/syncGeneration\";\nimport { restoreFailedAttachmentMutation } from \"./attachmentMutationPersistence\";\nimport {\n assignLocalAttachmentSlots,\n removeLocalAttachmentSlot,\n} from \"./attachmentPersistence\";\nimport {\n type AttachmentWriteGeneration,\n captureAttachmentWriteGeneration,\n isAttachmentWriteGenerationCurrent,\n shouldAbortAttachmentPersistFollowup,\n} from \"./attachmentWriteGeneration\";\nimport { ATTACHMENT_FAILURE_MESSAGE } from \"./index\";\n\nfunction installCommittedAttachmentRemoval(input: {\n currentDoc: NonNullable<DocumentStoreState[\"doc\"]>;\n slotId: string;\n state: DocumentStoreState;\n storageKey: string | undefined;\n syncedAttachment: boolean;\n}): void {\n const { slotId, state, storageKey } = input;\n if (!storageKey) return;\n const pending = state.pendingAttachments.find(\n (attachment) =>\n attachment.slotId === slotId && attachment.storageKey === storageKey,\n );\n if (input.syncedAttachment && pending?.upload) {\n assignLocalAttachmentSlots(state, [\n {\n slotId,\n storageKey,\n blobId: pending.upload.blobId,\n contentSha256: pending.contentSha256,\n },\n ]);\n }\n state.pendingAttachments = state.pendingAttachments.filter(\n (attachment) =>\n attachment.slotId !== slotId || attachment.storageKey !== storageKey,\n );\n // The committed removal queued this key. A reset can leave another document\n // uploading from the same copy; a detached marker keeps it until sync.\n void runDocumentOrphanMaintenance(state);\n if (\n input.syncedAttachment ||\n state.attachmentStorageKeyBySlotId[slotId] !== storageKey\n ) {\n return;\n }\n removeLocalAttachmentSlot(state, slotId);\n setReadySnapshot(\n state,\n input.currentDoc,\n state.snapshot.syncing,\n state.snapshot.text,\n state.snapshot.structuredFields,\n );\n}\n\nasync function persistRemovedAttachment(\n state: DocumentStoreState,\n slotId: string,\n writeGeneration: AttachmentWriteGeneration,\n) {\n if (!isAttachmentWriteGenerationCurrent(state, writeGeneration)) return;\n const currentDoc = state.doc;\n if (!currentDoc) {\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n const existingAttachment = getDocumentAttachments(currentDoc).find(\n (attachment) => attachment.slotId === slotId,\n );\n if (!existingAttachment) {\n return;\n }\n\n // After a reset, a store opened cold holds the slot only as a pending upload.\n const storageKey =\n state.attachmentStorageKeyBySlotId[slotId] ??\n state.pendingAttachments.find((attachment) => attachment.slotId === slotId)\n ?.storageKey;\n if (\n !isAttachmentWriteGenerationCurrent(state, writeGeneration) ||\n state.doc !== currentDoc\n )\n return;\n const rollbackSnapshot = exportFullHistorySnapshot(currentDoc).slice();\n removeDocumentAttachment(currentDoc, slotId);\n const attachmentUpdate = pendingDeltaSinceBase(state, currentDoc);\n const coveredVersion = encodeVersionVector(currentDoc);\n const pendingUpdate = createPendingUpdateFields(attachmentUpdate);\n const syncedAttachment = Boolean(state.record?.documentId);\n\n // Preserve the optimistic text/structured fields (see persistAttachedFiles):\n // removing an attachment while typing must not regress the editor.\n let persisted: Awaited<ReturnType<typeof persistDocument>>;\n try {\n persisted = await persistDocument(\n state,\n currentDoc,\n { snapshotEndVersion: coveredVersion },\n {\n ...(storageKey\n ? {\n attachmentRemoval: {\n mode: syncedAttachment\n ? (\"detach\" as const)\n : (\"delete\" as const),\n slotId,\n storageKey,\n },\n }\n : {}),\n ...(pendingUpdate ? { pendingUpdate } : {}),\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n },\n generation,\n );\n } catch (error) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n throw error;\n }\n if (\n shouldAbortAttachmentPersistFollowup(\n state,\n writeGeneration,\n generation,\n persisted,\n )\n ) {\n // See persistAttachedFiles: only durable same-identity work re-arms sync.\n return;\n }\n installCommittedAttachmentRemoval({\n currentDoc,\n slotId,\n state,\n storageKey,\n syncedAttachment,\n });\n advancePendingBaseVersion(state, currentDoc);\n state.runtime.util.log(\n `Removed attachment ${existingAttachment.name} from document ${state.localId}.`,\n );\n requestDocumentStoreSync(state);\n}\n\nexport async function removeAttachmentFromDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n slotId: string,\n) {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n const writeGeneration = captureAttachmentWriteGeneration(state);\n if (!writeGeneration) return;\n state.writeChain = state.writeChain\n .catch(() => undefined)\n .then(async () => persistRemovedAttachment(state, slotId, writeGeneration))\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n });\n return state.writeChain;\n}\n"]}
1
+ {"version":3,"file":"attachmentRemoval.js","sourceRoot":"","sources":["attachmentRemoval.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n encodeVersionVector,\n exportFullHistorySnapshot,\n} from \"@tearleads/loro\";\nimport {\n getDocumentAttachments,\n removeDocumentAttachment,\n} from \"../../../../data/documents/documentContent\";\nimport { createPendingUpdateFields } from \"../../../../data/documents/documentSync\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { ensureDocumentStoreReady } from \"../initialization\";\nimport { runDocumentOrphanMaintenance } from \"../orphanMaintenance\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n persistDocument,\n} from \"../persistence\";\nimport { reportDocumentStoreWriteFailure } from \"../reportWriteFailure\";\nimport {\n canWriteDocument,\n chainQueuedWrite,\n type DocumentStoreState,\n setReadySnapshot,\n} from \"../state\";\nimport { captureDocumentStoreSyncGeneration } from \"../sync/syncGeneration\";\nimport { restoreFailedAttachmentMutation } from \"./attachmentMutationPersistence\";\nimport {\n assignLocalAttachmentSlots,\n removeLocalAttachmentSlot,\n} from \"./attachmentPersistence\";\nimport {\n type AttachmentWriteGeneration,\n captureAttachmentWriteGeneration,\n isAttachmentWriteGenerationCurrent,\n shouldAbortAttachmentPersistFollowup,\n} from \"./attachmentWriteGeneration\";\nimport { ATTACHMENT_FAILURE_MESSAGE } from \"./index\";\n\nfunction installCommittedAttachmentRemoval(input: {\n currentDoc: NonNullable<DocumentStoreState[\"doc\"]>;\n slotId: string;\n state: DocumentStoreState;\n storageKey: string | undefined;\n syncedAttachment: boolean;\n}): void {\n const { slotId, state, storageKey } = input;\n if (!storageKey) return;\n const pending = state.pendingAttachments.find(\n (attachment) =>\n attachment.slotId === slotId && attachment.storageKey === storageKey,\n );\n if (input.syncedAttachment && pending?.upload) {\n assignLocalAttachmentSlots(state, [\n {\n slotId,\n storageKey,\n blobId: pending.upload.blobId,\n contentSha256: pending.contentSha256,\n },\n ]);\n }\n state.pendingAttachments = state.pendingAttachments.filter(\n (attachment) =>\n attachment.slotId !== slotId || attachment.storageKey !== storageKey,\n );\n // The committed removal queued this key. A reset can leave another document\n // uploading from the same copy; a detached marker keeps it until sync.\n void runDocumentOrphanMaintenance(state);\n if (\n input.syncedAttachment ||\n state.attachmentStorageKeyBySlotId[slotId] !== storageKey\n ) {\n return;\n }\n removeLocalAttachmentSlot(state, slotId);\n setReadySnapshot(\n state,\n input.currentDoc,\n state.snapshot.syncing,\n state.snapshot.text,\n state.snapshot.structuredFields,\n );\n}\n\nasync function persistRemovedAttachment(\n state: DocumentStoreState,\n slotId: string,\n writeGeneration: AttachmentWriteGeneration,\n) {\n if (!isAttachmentWriteGenerationCurrent(state, writeGeneration)) return;\n const currentDoc = state.doc;\n if (!currentDoc) {\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n const existingAttachment = getDocumentAttachments(currentDoc).find(\n (attachment) => attachment.slotId === slotId,\n );\n if (!existingAttachment) {\n return;\n }\n\n // After a reset, a store opened cold holds the slot only as a pending upload.\n const storageKey =\n state.attachmentStorageKeyBySlotId[slotId] ??\n state.pendingAttachments.find((attachment) => attachment.slotId === slotId)\n ?.storageKey;\n if (\n !isAttachmentWriteGenerationCurrent(state, writeGeneration) ||\n state.doc !== currentDoc\n )\n return;\n const rollbackSnapshot = exportFullHistorySnapshot(currentDoc).slice();\n removeDocumentAttachment(currentDoc, slotId);\n const attachmentUpdate = pendingDeltaSinceBase(state, currentDoc);\n const coveredVersion = encodeVersionVector(currentDoc);\n const pendingUpdate = createPendingUpdateFields(attachmentUpdate);\n const syncedAttachment = Boolean(state.record?.documentId);\n\n // Preserve the optimistic text/structured fields (see persistAttachedFiles):\n // removing an attachment while typing must not regress the editor.\n let persisted: Awaited<ReturnType<typeof persistDocument>>;\n try {\n persisted = await persistDocument(\n state,\n currentDoc,\n { snapshotEndVersion: coveredVersion },\n {\n ...(storageKey\n ? {\n attachmentRemoval: {\n mode: syncedAttachment\n ? (\"detach\" as const)\n : (\"delete\" as const),\n slotId,\n storageKey,\n },\n }\n : {}),\n ...(pendingUpdate ? { pendingUpdate } : {}),\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n },\n generation,\n );\n } catch (error) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n throw error;\n }\n if (\n shouldAbortAttachmentPersistFollowup(\n state,\n writeGeneration,\n generation,\n persisted,\n )\n ) {\n // See persistAttachedFiles: only durable same-identity work re-arms sync.\n return;\n }\n installCommittedAttachmentRemoval({\n currentDoc,\n slotId,\n state,\n storageKey,\n syncedAttachment,\n });\n advancePendingBaseVersion(state, currentDoc);\n state.runtime.util.log(\n `Removed attachment ${existingAttachment.name} from document ${state.localId}.`,\n );\n requestDocumentStoreSync(state);\n}\n\nexport async function removeAttachmentFromDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n slotId: string,\n) {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n const writeGeneration = captureAttachmentWriteGeneration(state);\n if (!writeGeneration) return;\n return chainQueuedWrite(\n state,\n state.writeChain\n .catch(() => undefined)\n .then(async () =>\n persistRemovedAttachment(state, slotId, writeGeneration),\n )\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(\n state,\n ATTACHMENT_FAILURE_MESSAGE,\n error,\n );\n }),\n );\n}\n"]}
@@ -6,7 +6,7 @@ import { ensureDocumentStoreReady } from "../initialization/index.js";
6
6
  import { settleDeferredInitialUpdate } from "../initialization/deferredInitialUpdate.js";
7
7
  import { advancePendingBaseVersion, pendingDeltaSinceBase, } from "../persistence.js";
8
8
  import { reportDocumentStoreWriteFailure } from "../reportWriteFailure.js";
9
- import { canAttachFiles, canWriteDocument, } from "../state.js";
9
+ import { canAttachFiles, canWriteDocument, chainQueuedWrite, } from "../state.js";
10
10
  import { captureDocumentStoreSyncGeneration } from "../sync/syncGeneration.js";
11
11
  import { buildAttachmentIntent, buildPendingAttachments, } from "./attachmentIntents.js";
12
12
  import { persistStagedAttachmentMutation, restoreFailedAttachmentMutation, } from "./attachmentMutationPersistence.js";
@@ -207,13 +207,12 @@ export async function attachFilesToDocumentStore(state, scheduleSync, files) {
207
207
  // only behind every earlier attach, never while one is still staging. The
208
208
  // caller's document is captured now (a cold store captures once ready).
209
209
  const callGeneration = captureAttachmentWriteGeneration(state);
210
- state.writeChain = state.writeChain
210
+ return chainQueuedWrite(state, state.writeChain
211
211
  .catch(() => undefined)
212
212
  .then(async () => attachThenSettle(state, scheduleSync, files, callGeneration))
213
213
  .catch((error) => {
214
214
  reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);
215
- });
216
- return state.writeChain;
215
+ }));
217
216
  }
218
217
  export async function replaceAttachmentInDocumentStore(state, scheduleSync, slotId, file) {
219
218
  let ready;
@@ -230,12 +229,11 @@ export async function replaceAttachmentInDocumentStore(state, scheduleSync, slot
230
229
  const writeGeneration = captureAttachmentWriteGeneration(state);
231
230
  if (!writeGeneration)
232
231
  return;
233
- state.writeChain = state.writeChain
232
+ return chainQueuedWrite(state, state.writeChain
234
233
  .catch(() => undefined)
235
234
  .then(async () => persistSlotAttachmentFile(state, slotId, file, writeGeneration))
236
235
  .catch((error) => {
237
236
  reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);
238
- });
239
- return state.writeChain;
237
+ }));
240
238
  }
241
239
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n encodeVersionVector,\n exportFullHistorySnapshot,\n} from \"@tearleads/loro\";\nimport { addDocumentAttachments } from \"../../../../data/documents/documentContent\";\nimport type { PendingAttachmentRecord } from \"../../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport type { DocumentAttachmentUpload } from \"../../types\";\nimport {\n deleteUnreferencedStagedAttachmentBytes,\n installPendingAttachmentRows,\n stagePendingAttachments,\n} from \"../attachmentUpload/attachmentStaging\";\nimport { ensureDocumentStoreReady } from \"../initialization\";\nimport { settleDeferredInitialUpdate } from \"../initialization/deferredInitialUpdate\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n} from \"../persistence\";\nimport { reportDocumentStoreWriteFailure } from \"../reportWriteFailure\";\nimport {\n canAttachFiles,\n canWriteDocument,\n type DocumentStoreState,\n} from \"../state\";\nimport { captureDocumentStoreSyncGeneration } from \"../sync/syncGeneration\";\nimport {\n buildAttachmentIntent,\n buildPendingAttachments,\n} from \"./attachmentIntents\";\nimport {\n persistStagedAttachmentMutation,\n restoreFailedAttachmentMutation,\n} from \"./attachmentMutationPersistence\";\nimport {\n type AttachmentWriteGeneration,\n captureAttachmentWriteGeneration,\n isAttachmentWriteGenerationCurrent,\n shouldAbortAttachmentPersistFollowup,\n} from \"./attachmentWriteGeneration\";\n\n// Fixed literal: a reported message must never carry file names or slot ids.\nexport const ATTACHMENT_FAILURE_MESSAGE =\n \"Documents: attachment mutation failed\";\n\nfunction logAttachedFiles(state: DocumentStoreState, count: number) {\n state.runtime.util.log(\n state.runtime.state.online && state.runtime.auth.isAuthenticated\n ? `Attached ${count} file${count === 1 ? \"\" : \"s\"} to document ${state.localId}.`\n : `Stored ${count} attachment${count === 1 ? \"\" : \"s\"} locally for document ${state.localId}.`,\n );\n}\n\nasync function persistAttachedFiles(\n state: DocumentStoreState,\n files: ReadonlyArray<DocumentAttachmentUpload>,\n writeGeneration: AttachmentWriteGeneration,\n) {\n if (!isAttachmentWriteGenerationCurrent(state, writeGeneration)) return;\n const currentDoc = state.doc;\n\n if (!currentDoc || !canAttachFiles(state)) {\n state.runtime.util.log(\n \"Documents: attachments require a local key package.\",\n );\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n const { nextAttachments, nextPendingAttachments } =\n await buildPendingAttachments(state.localId, files);\n if (\n !isAttachmentWriteGenerationCurrent(state, writeGeneration) ||\n state.doc !== currentDoc\n )\n return;\n const rollbackSnapshot = exportFullHistorySnapshot(currentDoc).slice();\n addDocumentAttachments(currentDoc, nextAttachments);\n const attachmentUpdate = pendingDeltaSinceBase(state, currentDoc);\n // Captured at delta time: the enqueued row proves coverage up to exactly\n // this version, so it is the frontier the persist below may publish.\n const coveredVersion = encodeVersionVector(currentDoc);\n\n let staged: Awaited<ReturnType<typeof stagePendingAttachments>>;\n try {\n staged = await stagePendingAttachments({\n files,\n generation,\n pendingAttachments: nextPendingAttachments,\n state,\n });\n } catch (error) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n throw error;\n }\n if (!staged) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n return;\n }\n // This persist changes attachments, not prose. setReadySnapshot always\n // re-derives attachments from the doc, but preserve the text/structured\n // fields so an attach that overlaps an in-flight keystroke does not republish\n // a stale doc read over the live optimistic editor value.\n const persisted = await persistStagedAttachmentMutation({\n attachmentUpdate,\n coveredVersion,\n currentDoc,\n generation,\n rollbackSnapshot,\n staged,\n state,\n });\n if (\n shouldAbortAttachmentPersistFollowup(\n state,\n writeGeneration,\n generation,\n persisted,\n )\n ) {\n await deleteUnreferencedStagedAttachmentBytes({\n generation,\n pendingAttachments: staged.pendingAttachments,\n state,\n });\n return;\n }\n installPendingAttachmentRows({ ...staged, state });\n advancePendingBaseVersion(state, currentDoc);\n logAttachedFiles(state, files.length);\n requestDocumentStoreSync(state);\n}\n\nasync function persistSlotAttachmentFile(\n state: DocumentStoreState,\n slotId: string,\n file: DocumentAttachmentUpload,\n writeGeneration: AttachmentWriteGeneration,\n) {\n if (!isAttachmentWriteGenerationCurrent(state, writeGeneration)) return;\n const currentDoc = state.doc;\n\n if (!currentDoc || !canAttachFiles(state)) {\n state.runtime.util.log(\n \"Documents: slot attachments require a local key package.\",\n );\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n const replacementAttachment = await buildAttachmentIntent(slotId, file);\n if (\n !isAttachmentWriteGenerationCurrent(state, writeGeneration) ||\n state.doc !== currentDoc\n )\n return;\n const rollbackSnapshot = exportFullHistorySnapshot(currentDoc).slice();\n addDocumentAttachments(currentDoc, [replacementAttachment]);\n const attachmentUpdate = pendingDeltaSinceBase(state, currentDoc);\n const coveredVersion = encodeVersionVector(currentDoc);\n\n const storageKey = `${state.localId}-${slotId}-${crypto.randomUUID()}`;\n const pendingAttachment: PendingAttachmentRecord = {\n byteLength: replacementAttachment.byteLength,\n contentSha256: replacementAttachment.contentSha256,\n localId: state.localId,\n mimeType: replacementAttachment.mimeType,\n name: replacementAttachment.name,\n slotId,\n storageKey,\n };\n let staged: Awaited<ReturnType<typeof stagePendingAttachments>>;\n try {\n staged = await stagePendingAttachments({\n files: [file],\n generation,\n pendingAttachments: [pendingAttachment],\n state,\n });\n } catch (error) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n throw error;\n }\n if (!staged) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n return;\n }\n // Preserve the optimistic text/structured fields (see persistAttachedFiles):\n // a slot replacement overlapping a keystroke must not regress the editor.\n const persisted = await persistStagedAttachmentMutation({\n attachmentUpdate,\n coveredVersion,\n currentDoc,\n generation,\n rollbackSnapshot,\n staged,\n state,\n });\n if (\n shouldAbortAttachmentPersistFollowup(\n state,\n writeGeneration,\n generation,\n persisted,\n )\n ) {\n await deleteUnreferencedStagedAttachmentBytes({\n generation,\n pendingAttachments: staged.pendingAttachments,\n state,\n });\n return;\n }\n installPendingAttachmentRows({ ...staged, state });\n advancePendingBaseVersion(state, currentDoc);\n state.runtime.util.log(`Queued attachment ${file.name} for slot ${slotId}.`);\n requestDocumentStoreSync(state);\n}\n\nasync function captureReadyAttachWrite(\n state: DocumentStoreState,\n scheduleSync: () => void,\n callGeneration: AttachmentWriteGeneration | null,\n) {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n return null;\n }\n if (!ready || !state.doc || !canWriteDocument(state)) return null;\n // A reset or relink while this call waited owns the replacement document.\n if (\n callGeneration &&\n !isAttachmentWriteGenerationCurrent(state, callGeneration)\n ) {\n return null;\n }\n return captureAttachmentWriteGeneration(state);\n}\n\nasync function attachThenSettle(\n state: DocumentStoreState,\n scheduleSync: () => void,\n files: ReadonlyArray<DocumentAttachmentUpload>,\n callGeneration: AttachmentWriteGeneration | null,\n) {\n const writeGeneration =\n files.length === 0\n ? null\n : await captureReadyAttachWrite(state, scheduleSync, callGeneration);\n try {\n if (writeGeneration) {\n await persistAttachedFiles(state, files, writeGeneration);\n }\n } finally {\n await settleDeferredInitialUpdate(state, writeGeneration);\n }\n}\n\nexport async function attachFilesToDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n files: ReadonlyArray<DocumentAttachmentUpload>,\n) {\n // Join the chain before awaiting readiness so settlements keep call order,\n // and settle even when nothing attaches: a deferred birth's sync hold lifts\n // only behind every earlier attach, never while one is still staging. The\n // caller's document is captured now (a cold store captures once ready).\n const callGeneration = captureAttachmentWriteGeneration(state);\n state.writeChain = state.writeChain\n .catch(() => undefined)\n .then(async () =>\n attachThenSettle(state, scheduleSync, files, callGeneration),\n )\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n });\n return state.writeChain;\n}\n\nexport async function replaceAttachmentInDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n slotId: string,\n file: DocumentAttachmentUpload,\n) {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n const writeGeneration = captureAttachmentWriteGeneration(state);\n if (!writeGeneration) return;\n state.writeChain = state.writeChain\n .catch(() => undefined)\n .then(async () =>\n persistSlotAttachmentFile(state, slotId, file, writeGeneration),\n )\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n });\n return state.writeChain;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n encodeVersionVector,\n exportFullHistorySnapshot,\n} from \"@tearleads/loro\";\nimport { addDocumentAttachments } from \"../../../../data/documents/documentContent\";\nimport type { PendingAttachmentRecord } from \"../../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport type { DocumentAttachmentUpload } from \"../../types\";\nimport {\n deleteUnreferencedStagedAttachmentBytes,\n installPendingAttachmentRows,\n stagePendingAttachments,\n} from \"../attachmentUpload/attachmentStaging\";\nimport { ensureDocumentStoreReady } from \"../initialization\";\nimport { settleDeferredInitialUpdate } from \"../initialization/deferredInitialUpdate\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n} from \"../persistence\";\nimport { reportDocumentStoreWriteFailure } from \"../reportWriteFailure\";\nimport {\n canAttachFiles,\n canWriteDocument,\n chainQueuedWrite,\n type DocumentStoreState,\n} from \"../state\";\nimport { captureDocumentStoreSyncGeneration } from \"../sync/syncGeneration\";\nimport {\n buildAttachmentIntent,\n buildPendingAttachments,\n} from \"./attachmentIntents\";\nimport {\n persistStagedAttachmentMutation,\n restoreFailedAttachmentMutation,\n} from \"./attachmentMutationPersistence\";\nimport {\n type AttachmentWriteGeneration,\n captureAttachmentWriteGeneration,\n isAttachmentWriteGenerationCurrent,\n shouldAbortAttachmentPersistFollowup,\n} from \"./attachmentWriteGeneration\";\n\n// Fixed literal: a reported message must never carry file names or slot ids.\nexport const ATTACHMENT_FAILURE_MESSAGE =\n \"Documents: attachment mutation failed\";\n\nfunction logAttachedFiles(state: DocumentStoreState, count: number) {\n state.runtime.util.log(\n state.runtime.state.online && state.runtime.auth.isAuthenticated\n ? `Attached ${count} file${count === 1 ? \"\" : \"s\"} to document ${state.localId}.`\n : `Stored ${count} attachment${count === 1 ? \"\" : \"s\"} locally for document ${state.localId}.`,\n );\n}\n\nasync function persistAttachedFiles(\n state: DocumentStoreState,\n files: ReadonlyArray<DocumentAttachmentUpload>,\n writeGeneration: AttachmentWriteGeneration,\n) {\n if (!isAttachmentWriteGenerationCurrent(state, writeGeneration)) return;\n const currentDoc = state.doc;\n\n if (!currentDoc || !canAttachFiles(state)) {\n state.runtime.util.log(\n \"Documents: attachments require a local key package.\",\n );\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n const { nextAttachments, nextPendingAttachments } =\n await buildPendingAttachments(state.localId, files);\n if (\n !isAttachmentWriteGenerationCurrent(state, writeGeneration) ||\n state.doc !== currentDoc\n )\n return;\n const rollbackSnapshot = exportFullHistorySnapshot(currentDoc).slice();\n addDocumentAttachments(currentDoc, nextAttachments);\n const attachmentUpdate = pendingDeltaSinceBase(state, currentDoc);\n // Captured at delta time: the enqueued row proves coverage up to exactly\n // this version, so it is the frontier the persist below may publish.\n const coveredVersion = encodeVersionVector(currentDoc);\n\n let staged: Awaited<ReturnType<typeof stagePendingAttachments>>;\n try {\n staged = await stagePendingAttachments({\n files,\n generation,\n pendingAttachments: nextPendingAttachments,\n state,\n });\n } catch (error) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n throw error;\n }\n if (!staged) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n return;\n }\n // This persist changes attachments, not prose. setReadySnapshot always\n // re-derives attachments from the doc, but preserve the text/structured\n // fields so an attach that overlaps an in-flight keystroke does not republish\n // a stale doc read over the live optimistic editor value.\n const persisted = await persistStagedAttachmentMutation({\n attachmentUpdate,\n coveredVersion,\n currentDoc,\n generation,\n rollbackSnapshot,\n staged,\n state,\n });\n if (\n shouldAbortAttachmentPersistFollowup(\n state,\n writeGeneration,\n generation,\n persisted,\n )\n ) {\n await deleteUnreferencedStagedAttachmentBytes({\n generation,\n pendingAttachments: staged.pendingAttachments,\n state,\n });\n return;\n }\n installPendingAttachmentRows({ ...staged, state });\n advancePendingBaseVersion(state, currentDoc);\n logAttachedFiles(state, files.length);\n requestDocumentStoreSync(state);\n}\n\nasync function persistSlotAttachmentFile(\n state: DocumentStoreState,\n slotId: string,\n file: DocumentAttachmentUpload,\n writeGeneration: AttachmentWriteGeneration,\n) {\n if (!isAttachmentWriteGenerationCurrent(state, writeGeneration)) return;\n const currentDoc = state.doc;\n\n if (!currentDoc || !canAttachFiles(state)) {\n state.runtime.util.log(\n \"Documents: slot attachments require a local key package.\",\n );\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n const replacementAttachment = await buildAttachmentIntent(slotId, file);\n if (\n !isAttachmentWriteGenerationCurrent(state, writeGeneration) ||\n state.doc !== currentDoc\n )\n return;\n const rollbackSnapshot = exportFullHistorySnapshot(currentDoc).slice();\n addDocumentAttachments(currentDoc, [replacementAttachment]);\n const attachmentUpdate = pendingDeltaSinceBase(state, currentDoc);\n const coveredVersion = encodeVersionVector(currentDoc);\n\n const storageKey = `${state.localId}-${slotId}-${crypto.randomUUID()}`;\n const pendingAttachment: PendingAttachmentRecord = {\n byteLength: replacementAttachment.byteLength,\n contentSha256: replacementAttachment.contentSha256,\n localId: state.localId,\n mimeType: replacementAttachment.mimeType,\n name: replacementAttachment.name,\n slotId,\n storageKey,\n };\n let staged: Awaited<ReturnType<typeof stagePendingAttachments>>;\n try {\n staged = await stagePendingAttachments({\n files: [file],\n generation,\n pendingAttachments: [pendingAttachment],\n state,\n });\n } catch (error) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n throw error;\n }\n if (!staged) {\n await restoreFailedAttachmentMutation({\n generation,\n rollbackSnapshot,\n state,\n });\n return;\n }\n // Preserve the optimistic text/structured fields (see persistAttachedFiles):\n // a slot replacement overlapping a keystroke must not regress the editor.\n const persisted = await persistStagedAttachmentMutation({\n attachmentUpdate,\n coveredVersion,\n currentDoc,\n generation,\n rollbackSnapshot,\n staged,\n state,\n });\n if (\n shouldAbortAttachmentPersistFollowup(\n state,\n writeGeneration,\n generation,\n persisted,\n )\n ) {\n await deleteUnreferencedStagedAttachmentBytes({\n generation,\n pendingAttachments: staged.pendingAttachments,\n state,\n });\n return;\n }\n installPendingAttachmentRows({ ...staged, state });\n advancePendingBaseVersion(state, currentDoc);\n state.runtime.util.log(`Queued attachment ${file.name} for slot ${slotId}.`);\n requestDocumentStoreSync(state);\n}\n\nasync function captureReadyAttachWrite(\n state: DocumentStoreState,\n scheduleSync: () => void,\n callGeneration: AttachmentWriteGeneration | null,\n) {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n return null;\n }\n if (!ready || !state.doc || !canWriteDocument(state)) return null;\n // A reset or relink while this call waited owns the replacement document.\n if (\n callGeneration &&\n !isAttachmentWriteGenerationCurrent(state, callGeneration)\n ) {\n return null;\n }\n return captureAttachmentWriteGeneration(state);\n}\n\nasync function attachThenSettle(\n state: DocumentStoreState,\n scheduleSync: () => void,\n files: ReadonlyArray<DocumentAttachmentUpload>,\n callGeneration: AttachmentWriteGeneration | null,\n) {\n const writeGeneration =\n files.length === 0\n ? null\n : await captureReadyAttachWrite(state, scheduleSync, callGeneration);\n try {\n if (writeGeneration) {\n await persistAttachedFiles(state, files, writeGeneration);\n }\n } finally {\n await settleDeferredInitialUpdate(state, writeGeneration);\n }\n}\n\nexport async function attachFilesToDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n files: ReadonlyArray<DocumentAttachmentUpload>,\n) {\n // Join the chain before awaiting readiness so settlements keep call order,\n // and settle even when nothing attaches: a deferred birth's sync hold lifts\n // only behind every earlier attach, never while one is still staging. The\n // caller's document is captured now (a cold store captures once ready).\n const callGeneration = captureAttachmentWriteGeneration(state);\n return chainQueuedWrite(\n state,\n state.writeChain\n .catch(() => undefined)\n .then(async () =>\n attachThenSettle(state, scheduleSync, files, callGeneration),\n )\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(\n state,\n ATTACHMENT_FAILURE_MESSAGE,\n error,\n );\n }),\n );\n}\n\nexport async function replaceAttachmentInDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n slotId: string,\n file: DocumentAttachmentUpload,\n) {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ATTACHMENT_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n const writeGeneration = captureAttachmentWriteGeneration(state);\n if (!writeGeneration) return;\n return chainQueuedWrite(\n state,\n state.writeChain\n .catch(() => undefined)\n .then(async () =>\n persistSlotAttachmentFile(state, slotId, file, writeGeneration),\n )\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(\n state,\n ATTACHMENT_FAILURE_MESSAGE,\n error,\n );\n }),\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_DOCUMENT_KIND } from "../../../data/documents/documentConstants.js";
2
2
  import { createDocumentProjectionUserKeyResolver, defaultDocumentsPersistence, didDocumentProjectionKeyRuntimeChange, didRegainSyncPrerequisites, requestDocumentSyncLaneAndWait, } from "../../../workflows/documents/index.js";
3
- import { createDocumentStoreFacade, emitPersistedDocument, getOrCreateDocumentStoreRegistry, registerDocumentStore, registerDocumentStoreIdentity, requestDocumentStoreSync, resolveDocumentStoreKey, } from "../registry.js";
3
+ import { createDocumentStoreFacade, emitPersistedDocument, getOrCreateDocumentStoreRegistry, registerDocumentStore, registerDocumentStoreIdentity, requestDocumentStoreSync, resolveDocumentStoreKey, takeRegisteredDocumentStore, } from "../registry.js";
4
4
  import { attachFilesToDocumentStore, replaceAttachmentInDocumentStore, } from "./attachments/index.js";
5
5
  import { removeAttachmentFromDocumentStore } from "./attachments/attachmentRemoval.js";
6
6
  import { discardDocumentStoreLocalState } from "./discard.js";
@@ -10,7 +10,7 @@ import { registerInternalDocumentRelink } from "./internalRelink.js";
10
10
  import { setDocumentStructuredFields, setDocumentText } from "./mutations.js";
11
11
  import { assertDocumentStoreCanRotateContentKey } from "./rotation/index.js";
12
12
  import { addRowToDocumentStore, removeRowFromDocumentStore, updateRowInDocumentStore, } from "./rows/index.js";
13
- import { createDocumentStoreState, refreshAttachabilitySnapshot, resetDocumentStore, subscribeToDocumentStore, } from "./state.js";
13
+ import { countQueuedWrite, createDocumentStoreState, refreshAttachabilitySnapshot, resetDocumentStore, subscribeToDocumentStore, } from "./state.js";
14
14
  import { registerDocumentStoreSyncLane } from "./sync/index.js";
15
15
  import { logRevalidationScheduled } from "./sync/remoteRevalidationTelemetry.js";
16
16
  import { allowDocumentStoreRemoteSync, captureDocumentStoreRemoteSyncRequestGeneration, captureDocumentStoreSyncLaneGeneration, didDocumentStoreRemoteSyncRequestComplete, hasPendingIndependentDocumentStoreRemoteSync, invalidateDocumentStoreRemoteSync, invalidateDocumentStoreSyncLane, isDocumentStoreRemoteSyncBlocked, isDocumentStoreRemoteSyncRequestGenerationCurrent, markDocumentStoreRemoteSyncPending, registerDocumentStoreRemoteSyncWaiter, } from "./sync/syncGeneration.js";
@@ -170,24 +170,27 @@ function createBackingStoreContext(localId, runtime, persistence, documentId, te
170
170
  }
171
171
  function createBackingDocumentStore(localId, initialRuntime, persistence = defaultDocumentsPersistence, initialDocumentId = null, initialText = "", initialDocumentKind = DEFAULT_DOCUMENT_KIND, openOptions = {}) {
172
172
  const { scheduleSync, state, withLiveSyncLane } = createBackingStoreContext(localId, initialRuntime, persistence, initialDocumentId, initialText, initialDocumentKind, openOptions);
173
+ // Local writes count as queued from the call, readiness wait included.
174
+ const liveWrite = (write) => withLiveSyncLane(() => countQueuedWrite(state, write()));
173
175
  const store = {
174
- addRow: (fields) => withLiveSyncLane(() => addRowToDocumentStore(state, scheduleSync, fields)),
176
+ addRow: (fields) => liveWrite(() => addRowToDocumentStore(state, scheduleSync, fields)),
175
177
  assertCanRotateContentKey: () => withLiveSyncLane(() => assertBackingDocumentStoreCanRotate(state, scheduleSync)),
176
- attachFiles: (files) => withLiveSyncLane(() => attachFilesToDocumentStore(state, scheduleSync, files)),
178
+ attachFiles: (files) => liveWrite(() => attachFilesToDocumentStore(state, scheduleSync, files)),
177
179
  discardLocalState: (expectedDocumentId) => withLiveSyncLane(() => discardBackingDocumentStoreLocalState(state, scheduleSync, expectedDocumentId)),
178
180
  ensureInitialized: () => withLiveSyncLane(() => ensureDocumentStoreReady(state, scheduleSync)),
179
181
  getSnapshot: () => state.snapshot,
180
- removeAttachment: (slotId) => withLiveSyncLane(() => removeAttachmentFromDocumentStore(state, scheduleSync, slotId)),
181
- removeRow: (id) => withLiveSyncLane(() => removeRowFromDocumentStore(state, scheduleSync, id)),
182
- replaceAttachment: (slotId, file) => withLiveSyncLane(() => replaceAttachmentInDocumentStore(state, scheduleSync, slotId, file)),
182
+ hasQueuedWrites: () => state.queuedWrites > 0,
183
+ removeAttachment: (slotId) => liveWrite(() => removeAttachmentFromDocumentStore(state, scheduleSync, slotId)),
184
+ removeRow: (id) => liveWrite(() => removeRowFromDocumentStore(state, scheduleSync, id)),
185
+ replaceAttachment: (slotId, file) => liveWrite(() => replaceAttachmentInDocumentStore(state, scheduleSync, slotId, file)),
183
186
  requestRemoteSync: () => withLiveSyncLane(() => requestRemoteDocumentStoreSync(state, scheduleSync)),
184
187
  requestRemoteSyncAndWait: (signal) => requestRemoteDocumentStoreSyncAndWait(state, scheduleSync, signal),
185
188
  requestSync: () => withLiveSyncLane(() => requestOrdinaryDocumentStoreSync(state, scheduleSync)),
186
189
  relink: (input) => withLiveSyncLane(() => relinkDocumentStore(state, input, scheduleSync)),
187
- setStructuredFields: (kind, patch, options) => withLiveSyncLane(() => setDocumentStructuredFields(state, scheduleSync, kind, patch, options)),
188
- setText: (value) => withLiveSyncLane(() => setDocumentText(state, scheduleSync, value)),
190
+ setStructuredFields: (kind, patch, options) => liveWrite(() => setDocumentStructuredFields(state, scheduleSync, kind, patch, options)),
191
+ setText: (value) => liveWrite(() => setDocumentText(state, scheduleSync, value)),
189
192
  subscribe: (listener) => subscribeToDocumentStore(state, listener),
190
- updateRowFields: (id, patch) => withLiveSyncLane(() => updateRowInDocumentStore(state, scheduleSync, id, patch)),
193
+ updateRowFields: (id, patch) => liveWrite(() => updateRowInDocumentStore(state, scheduleSync, id, patch)),
191
194
  updateRuntime: (runtime) => updateDocumentStoreRuntime(state, runtime, scheduleSync),
192
195
  };
193
196
  return registerBackingStoreInternalRelink({
@@ -202,12 +205,13 @@ export function createDocumentStore(localId, initialRuntime, persistence = defau
202
205
  }
203
206
  export function getOrCreateDocumentStore(domainScope, localId, runtime, initialDocumentId = null, initialText = "", initialDocumentKind = DEFAULT_DOCUMENT_KIND, options = {}) {
204
207
  const registry = getOrCreateDocumentStoreRegistry(domainScope);
205
- const existingStore = registry.storesByKey.get(resolveDocumentStoreKey(registry, localId, initialDocumentId));
208
+ const createBacking = () => createBackingDocumentStore(localId, runtime, defaultDocumentsPersistence, initialDocumentId, initialText, initialDocumentKind, options);
209
+ const existingStore = takeRegisteredDocumentStore(registry, resolveDocumentStoreKey(registry, localId, initialDocumentId), createBacking);
206
210
  if (existingStore) {
207
211
  registerDocumentStore(domainScope, localId, existingStore, initialDocumentId);
208
212
  return existingStore;
209
213
  }
210
- const nextStore = createDocumentStore(localId, runtime, defaultDocumentsPersistence, initialDocumentId, initialText, initialDocumentKind, options);
214
+ const nextStore = createDocumentStoreFacade(createBacking());
211
215
  registerDocumentStore(domainScope, localId, nextStore, initialDocumentId);
212
216
  return nextStore;
213
217
  }