@tearleads/client-sdk 0.1.113 → 0.1.115

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 (66) hide show
  1. package/data/persistence/container-contents/containerContentsPersistence.js +3 -8
  2. package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
  3. package/data/persistence/container-contents/containerHydrationPersistence.js +15 -5
  4. package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
  5. package/data/persistence/container-contents/containerMetadataMutationPersistence.js +8 -2
  6. package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
  7. package/data/persistence/container-contents/containerMetadataRows.js +34 -2
  8. package/data/persistence/container-contents/containerMetadataRows.js.map +1 -1
  9. package/data/persistence/container-contents/containerPersistence.d.ts +231 -0
  10. package/data/persistence/container-contents/containerPersistence.js +20 -16
  11. package/data/persistence/container-contents/containerPersistence.js.map +1 -1
  12. package/data/persistence/container-contents/containerRecoveryPersistence.js +167 -51
  13. package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
  14. package/data/persistence/container-contents/documentContainerProjectionPersistence.js +56 -19
  15. package/data/persistence/container-contents/documentContainerProjectionPersistence.js.map +1 -1
  16. package/data/persistence/container-contents/documentMoveIntentPersistence.js +29 -5
  17. package/data/persistence/container-contents/documentMoveIntentPersistence.js.map +1 -1
  18. package/data/persistence/container-contents/documentPlacement.js +24 -5
  19. package/data/persistence/container-contents/documentPlacement.js.map +1 -1
  20. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js +1 -1
  21. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js.map +1 -1
  22. package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js +1 -1
  23. package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js.map +1 -1
  24. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +43 -35
  25. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
  26. package/data/persistence/documents/documentsPersistence.js +4 -58
  27. package/data/persistence/documents/documentsPersistence.js.map +1 -1
  28. package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js +15 -11
  29. package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js.map +1 -1
  30. package/data/persistence/documents/internal/containerDocumentTombstones.js +87 -35
  31. package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
  32. package/data/persistence/documents/internal/discoveredDocumentPlacement.js +5 -2
  33. package/data/persistence/documents/internal/discoveredDocumentPlacement.js.map +1 -1
  34. package/data/persistence/documents/internal/discoveredDocumentUpsert.js +174 -0
  35. package/data/persistence/documents/internal/discoveredDocumentUpsert.js.map +1 -0
  36. package/data/persistence/documents/internal/documentMutationPersistence.js +15 -15
  37. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  38. package/data/persistence/documents/internal/documentRows.js +122 -11
  39. package/data/persistence/documents/internal/documentRows.js.map +1 -1
  40. package/data/persistence/documents/internal/rowQueryPersistence.js +70 -27
  41. package/data/persistence/documents/internal/rowQueryPersistence.js.map +1 -1
  42. package/data/persistence/documents/records/documentHistoryPersistence.js +17 -11
  43. package/data/persistence/documents/records/documentHistoryPersistence.js.map +1 -1
  44. package/data/persistence/documents/records/documentRecordPersistence.d.ts +5 -0
  45. package/data/persistence/documents/records/documentRecordPersistence.js +41 -6
  46. package/data/persistence/documents/records/documentRecordPersistence.js.map +1 -1
  47. package/data/persistence/documents/records/index.d.ts +1 -1
  48. package/data/persistence/documents/records/index.js +1 -1
  49. package/data/persistence/documents/records/index.js.map +1 -1
  50. package/data/persistence/keyingCheckpoints/documentPurgeCheckpointPersistence.d.ts +2 -0
  51. package/data/persistence/keyingCheckpoints/documentPurgeCheckpointPersistence.js +17 -1
  52. package/data/persistence/keyingCheckpoints/documentPurgeCheckpointPersistence.js.map +1 -1
  53. package/package.json +1 -1
  54. package/workflows/container-contents/documentQueries/index.js +21 -6
  55. package/workflows/container-contents/documentQueries/index.js.map +1 -1
  56. package/workflows/container-contents/remoteReset/containerRemoteReset.js +12 -7
  57. package/workflows/container-contents/remoteReset/containerRemoteReset.js.map +1 -1
  58. package/workflows/documents/documentMutationCommit.js +11 -12
  59. package/workflows/documents/documentMutationCommit.js.map +1 -1
  60. package/workflows/documents/documentMutationPreparation.d.ts +1 -0
  61. package/workflows/documents/documentMutationPreparation.js +1 -0
  62. package/workflows/documents/documentMutationPreparation.js.map +1 -1
  63. package/workflows/documents/documentPersistGuards.js +24 -0
  64. package/workflows/documents/documentPersistGuards.js.map +1 -1
  65. package/workflows/documents/remoteReset/documentRemoteReset.js +31 -18
  66. package/workflows/documents/remoteReset/documentRemoteReset.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mEAAmE,CAAC;AAC1G,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,2EAA2E,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,oCAAoC,GACrC,MAAM,gFAAgF,CAAC;AACxF,OAAO,EAAE,yCAAyC,EAAE,MAAM,qFAAqF,CAAC;AAChJ,OAAO,EACL,gCAAgC,IAAI,yCAAyC,EAC7E,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAgB,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EACL,iBAAiB,EAEjB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,2BAA2B,GAE5B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,GAErB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sCAAsC,EACtC,wCAAwC,EACxC,8BAA8B,EAC9B,mBAAmB,EACnB,uCAAuC,GACxC,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,6BAA6B,EAC7B,mDAAmD,EACnD,wCAAwC,EACxC,yCAAyC,EACzC,4CAA4C,EAC5C,uCAAuC,EACvC,sCAAsC,EACtC,2BAA2B,EAC3B,4BAA4B,EAC5B,+BAA+B,EAC/B,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,OAAO,CAAC;AA8Ff,KAAK,UAAU,uBAAuB,CACpC,OAAgB,EAChB,KAAmC;IAEnC,MAAM,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,uBAAuB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,eAAe,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAElD,MAAM,KAAK,GAAG,2BAA2B,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,6BAA6B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3D,MAAM,kBAAkB,GAAG,KAAK,CAAC,IAAI,CACnC,IAAI,GAAG,CAAC,KAAK,CAAC,kBAAkB,IAAI,EAAE,CAAC,CACxC,CAAC;IACF,MAAM,qBAAqB,GAAG,KAAK,CAAC,qBAAqB,IAAI,IAAI,CAAC;IAClE,MAAM,kCAAkC,GAAG,qBAAqB;QAC9D,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAC;QACrE,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC;IAC5C,MAAM,IAAI,GAAG,QAAQ;QACnB,CAAC,CAAC,4BAA4B,CAAC,KAAK,CAAC,qBAAqB,CAAC;QAC3D,CAAC,CAAC;YACE,KAAK,CAAC,WAAW;YACjB,GAAG,kBAAkB;YACrB,GAAG,CAAC,kCAAkC,CAAC,MAAM,GAAG,CAAC;gBAC/C,CAAC,CAAC,CAAC,qBAAqB,EAAE,GAAG,kCAAkC,CAAC;gBAChE,CAAC,CAAC,EAAE,CAAC;YACP,KAAK,CAAC,WAAW;YACjB,KAAK,CAAC,WAAW;SAClB,CAAC;IACN,MAAM,OAAO,GAAG,QAAQ;QACtB,CAAC,CAAC,+BAA+B,EAAE;QACnC,CAAC,CAAC,yCAAyC,CACvC,kBAAkB,CAAC,MAAM,EACzB,kCAAkC,CAAC,MAAM,CAC1C,CAAC;IACN,MAAM,SAAS,GAAG,MAAM,OAAO,CAC7B,wCAAwC,OAAO,GAAG,EAClD,IAAI,CACL,CAAC;IACF,MAAM,UAAU,GAAG,uCAAuC,CACxD,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CACnB,CAAC;IAEF,IAAI,KAAK,KAAK,CAAC,IAAI,MAAM,IAAI,UAAU,EAAE,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,GAAG,OAAO,aAAa,wCAAwC,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAC9F,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CACzB,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QACpE,UAAU;KACX,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,OAAgB,EAChB,qBAAoC;IAEpC,MAAM,uBAAuB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,4BAA4B,EAAE,EAC9B,4BAA4B,CAAC,qBAAqB,CAAC,CACpD,CAAC;IACF,OAAO,CACL,IAAI,CAAC,MAAM,GAAG,CAAC;QACf,CAAC,MAAM,4BAA4B,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;QACpE,CAAC,MAAM,yBAAyB,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,kCAAkC,CAC/C,OAAgB,EAChB,KAKC;IAED,MAAM,uBAAuB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAEpD,MAAM,KAAK,GAAG,sCAAsC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,6BAA6B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC;IAC5C,MAAM,IAAI,GAAG,QAAQ;QACnB,CAAC,CAAC,4BAA4B,CAAC,KAAK,CAAC,qBAAqB,CAAC;QAC3D,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,QAAQ;QACtB,CAAC,CAAC,8BAA8B,EAAE;QAClC,CAAC,CAAC,uCAAuC,EAAE,CAAC;IAC9C,MAAM,SAAS,GAAG,MAAM,OAAO,CAC7B,wCAAwC,OAAO,GAAG,EAClD,IAAI,CACL,CAAC;IACF,MAAM,UAAU,GAAG,uCAAuC,CACxD,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CACnB,CAAC;IAEF,IAAI,KAAK,KAAK,CAAC,IAAI,MAAM,IAAI,UAAU,EAAE,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,GAAG,OAAO,aAAa,mDAAmD,EAAE,mBAAmB,EAC/F,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CACzB,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,8BAA8B,CAAC;QAC9C,UAAU;KACX,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,qCAAqC,CAClD,OAAgB,EAChB,OAAe,EACf,KAA+D;IAE/D,MAAM,uBAAuB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAEpD,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB;;;;;;;;;;;;;;;QAeI,KAAK,CAAC,QAAQ;;KAEjB,EACD,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CACzB,CAAC;IAEF,OAAO,sCAAsC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,oCAAoC,CAC3C,OAAgB,EAChB,OAAe,EACf,eAAwB;IAExB,OAAO,qCAAqC,CAAC,OAAO,EAAE,OAAO,EAAE;QAC7D,IAAI,EAAE,EAAE;QACR,QAAQ,EAAE,eAAe;YACvB,CAAC,CAAC,OAAO,qBAAqB,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE;YAC3D,CAAC,CAAC,EAAE;KACP,CAAC,CAAC;AACL,CAAC;AAED,SAAS,4CAA4C,CACnD,OAAgB,EAChB,OAAe,EACf,qBAAoC,EACpC,eAAwB;IAExB,OAAO,qCAAqC,CAAC,OAAO,EAAE,OAAO,EAAE;QAC7D,IAAI,EAAE,4BAA4B,CAAC,qBAAqB,CAAC;QACzD,QAAQ,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,OAAO,qBAAqB,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,2BAA2B,CAC9H;YACE,aAAa,EAAE,eAAe;YAC9B,eAAe,EAAE,GAAG;SACrB,CACF,EAAE;KACJ,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,sCAAsC,CACnD,OAAgB,EAChB,OAAe;IAEf,MAAM,uBAAuB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAEpD,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB;aACS,4CAA4C,EAAE;;;;;;;;;;;;;;KActD,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACnB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,wCAAwC,CAAC,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,KAAK,UAAU,oDAAoD,CACjE,OAAgB,EAChB,WAAkC;IAElC,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IAC3D,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;IAED,MAAM,8BAA8B,GAAG,IAAI,GAAG,EAAoB,CAAC;IACnE,KAAK,MAAM,UAAU,IAAI,iBAAiB,EAAE,CAAC;QAC3C,8BAA8B,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,MAAM,eAAe,IAAI,iCAAiC,CAC7D,iBAAiB,CAClB,EAAE,CAAC;QACF,MAAM,mCAAmC,GACvC,MAAM,yCAAyC,CAAC,mCAAmC,CACjF,OAAO,EACP,eAAe,CAChB,CAAC;QACJ,KAAK,MAAM,CACT,UAAU,EACV,kBAAkB,EACnB,IAAI,mCAAmC,CAAC,OAAO,EAAE,EAAE,CAAC;YACnD,8BAA8B,CAAC,GAAG,CAChC,UAAU,EACV,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAC/B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,8BAA8B,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,yCAAyC,CACvD,OAAwC;IAExC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;IACtC,OAAO;QACL,GAAG,2BAA2B,CAAC,OAAO,CAAC;QACvC,gCAAgC,CAAC,UAAU;YACzC,OAAO,yCAAyC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACxE,CAAC;QACD,oBAAoB,CAAC,EAAE,qBAAqB,EAAE;YAC5C,OAAO,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;QAC9D,CAAC;QACD,kCAAkC,CAAC,KAAK;YACtC,OAAO,kCAAkC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC5D,CAAC;QACD,uBAAuB,CAAC,KAAK;YAC3B,OAAO,uBAAuB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACjD,CAAC;QACD,qBAAqB,CAAC,OAAO;YAC3B,OAAO,sCAAsC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClE,CAAC;QACD,mBAAmB,CAAC,OAAO,EAAE,OAAO;YAClC,OAAO,oCAAoC,CACzC,OAAO,EACP,OAAO,EACP,OAAO,EAAE,eAAe,IAAI,KAAK,CAClC,CAAC;QACJ,CAAC;QACD,2BAA2B,CAAC,EAC1B,qBAAqB,EACrB,OAAO,EACP,eAAe,GAAG,KAAK,GACxB;YACC,OAAO,4CAA4C,CACjD,OAAO,EACP,OAAO,EACP,qBAAqB,EACrB,eAAe,CAChB,CAAC;QACJ,CAAC;QACD,8BAA8B,CAAC,WAAW;YACxC,OAAO,oCAAoC,CAAC,aAAa,CACvD,OAAO,EACP,yBAAyB,CAAC,WAAW,CAAC,CACvC,CAAC;QACJ,CAAC;QACD,mCAAmC,CAAC,WAAW;YAC7C,OAAO,oDAAoD,CACzD,OAAO,EACP,WAAW,CACZ,CAAC;QACJ,CAAC;QACD,oBAAoB;YAClB,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QACD,iBAAiB;YACf,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;QACD,qBAAqB,CAAC,KAAK;YACzB,OAAO,2BAA2B,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACrD,CAAC;QACD,yBAAyB,CAAC,MAAM;YAC9B,OAAO,yCAAyC,CAAC,yBAAyB,CACxE,OAAO,EACP,MAAM,CACP,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,8BAA8B,CAAC,WAAW,EAAE,SAAS;YACzD,MAAM,oCAAoC,CAAC,aAAa,CACtD,OAAO,EACP,yBAAyB,CAAC,WAAW,CAAC,EACtC,SAAS,CACV,CAAC;QACJ,CAAC;QACD,yBAAyB,CAAC,MAAM;YAC9B,OAAO,yBAAyB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { SyncWatermark } from \"@tearleads/validators/response\";\nimport type {\n DiscoveredDocumentInput,\n DocumentSummary,\n} from \"../../../data/documents/documentSummary\";\nimport { ensureContainerTables } from \"../../../data/persistence/container-contents/containerPersistence\";\nimport {\n hasRetainedContainerMetadata,\n listRecoveryFolderMoveIds,\n} from \"../../../data/persistence/container-contents/containerRecoveryPersistence\";\nimport {\n containerContentsSyncLane,\n sqlContainerSyncWatermarkPersistence,\n} from \"../../../data/persistence/container-contents/containerSyncWatermarkPersistence\";\nimport { sqlDocumentContainerProjectionPersistence } from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport {\n applyContainerDocumentTombstones as applyPersistedContainerDocumentTombstones,\n sqlDocumentsPersistence,\n upsertDiscoveredDocuments,\n} from \"../../../data/persistence/documents/documentsPersistence\";\nimport { localIntentTables } from \"../../../data/sqlite/schema\";\nimport { type ExecSql, ensureSqlTables } from \"../../../data/sqlite/sqlSchema\";\nimport {\n listPendingWrites,\n type PendingWriteQueueItem,\n resetPendingWriteRetryState,\n} from \"../pendingWrites\";\nimport {\n createFolderRecoveryQueries,\n type RecoveryFolder,\n} from \"../recovery/folderRecovery\";\nimport type { ContainerDocumentObjectSyncState } from \"../syncState\";\nimport { hydratedProjectionSql } from \"./hydrationSql\";\nimport {\n getOrphanedDocumentQueryBind,\n getOrphanedDocumentWhereSql,\n} from \"./orphanedDocumentSql\";\nimport {\n listPendingDownloads,\n type PendingDownloadQueueItem,\n} from \"./pendingDownloads\";\nimport {\n mapContainerContentsDocumentSummaryRow,\n mapContainerContentsDocumentSyncStateRow,\n mapContainerDocumentSidebarRow,\n mapContainerItemRow,\n readContainerContentsContainerItemCount,\n} from \"./rows\";\nimport {\n clampContainerItemWindowValue,\n getContainerContentsContainerDocumentSidebarOrderBy,\n getContainerContentsContainerItemOrderBy,\n getContainerContentsContainerItemsBaseSql,\n getContainerContentsDocumentPendingStateCtes,\n getContainerContentsDocumentRowsBaseSql,\n getContainerDocumentSidebarWindowLimit,\n getContainerItemWindowLimit,\n getOrphanedDocumentExistsSql,\n getOrphanedDocumentItemsBaseSql,\n getOrphanedDocumentRowsBaseSql,\n listContainerContentsSqlIdBatches,\n} from \"./sql\";\nimport type {\n ContainerDocumentLinkInput,\n ContainerDocumentQueriesRuntime,\n ContainerDocumentSidebarWindow,\n ContainerDocumentTombstone,\n ContainerItemSort,\n ContainerItemWindow,\n} from \"./types\";\n\nexport type {\n ContainerDocumentLinkInput,\n ContainerDocumentSidebarRow,\n ContainerDocumentTombstone,\n ContainerItemRow,\n ContainerItemSort,\n ContainerItemSortDirection,\n ContainerItemSortKey,\n} from \"./types\";\n\ninterface ListContainerItemWindowInput {\n /** Null selects the virtual orphaned-documents recovery collection. */\n containerId: string | null;\n currentOrganizationId?: string | null | undefined;\n limit: number;\n offset: number;\n sort: ContainerItemSort;\n visibleForeignSystemContainerNames?: ReadonlyArray<string> | undefined;\n visibleSystemSlots?: ReadonlyArray<ContainerSystemSlot> | undefined;\n}\n\nexport interface ContainerDocumentQueries {\n listRecoveryFolderMoveIds(input: {\n currentOrganizationId: string | null;\n }): Promise<string[]>;\n listRecoveryFolders(input: {\n currentOrganizationId: string | null;\n }): Promise<RecoveryFolder[]>;\n discardRecoveryFolder(\n input: Pick<RecoveryFolder, \"containerId\" | \"organizationId\" | \"revision\">,\n ): Promise<boolean>;\n applyContainerDocumentTombstones(\n tombstones: ReadonlyArray<ContainerDocumentTombstone>,\n ): Promise<ReadonlyArray<DocumentSummary>>;\n hasOrphanedDocuments(input: {\n currentOrganizationId: string | null;\n }): Promise<boolean>;\n listContainerDocumentSidebarWindow(input: {\n /** Null selects the virtual orphaned-documents recovery collection. */\n containerId: string | null;\n currentOrganizationId?: string | null | undefined;\n limit: number;\n offset: number;\n }): Promise<ContainerDocumentSidebarWindow>;\n listContainerItemWindow(\n input: ListContainerItemWindowInput,\n ): Promise<ContainerItemWindow>;\n loadDocumentSyncState(\n localId: string,\n ): Promise<ContainerDocumentObjectSyncState | null>;\n loadDocumentSummary(\n localId: string,\n options?: { requireHydrated?: boolean },\n ): Promise<DocumentSummary | null>;\n loadOrphanedDocumentSummary(input: {\n requireHydrated?: boolean;\n currentOrganizationId: string | null;\n localId: string;\n }): Promise<DocumentSummary | null>;\n loadContainerDocumentWatermark(\n containerId: string,\n ): Promise<SyncWatermark | null>;\n listLinkedContainerIdsByDocumentIds(\n documentIds: ReadonlyArray<string>,\n ): Promise<ReadonlyMap<string, ReadonlyArray<string>>>;\n listPendingDownloads(): Promise<ReadonlyArray<PendingDownloadQueueItem>>;\n listPendingWrites(): Promise<ReadonlyArray<PendingWriteQueueItem>>;\n retryPendingWriteItem(input: {\n localId: string;\n namespace: string | null;\n objectKind: PendingWriteQueueItem[\"objectKind\"];\n }): Promise<void>;\n replaceDocumentLinksBatch(\n inputs: ReadonlyArray<ContainerDocumentLinkInput>,\n ): Promise<void>;\n saveContainerDocumentWatermark(\n containerId: string,\n watermark: SyncWatermark,\n ): Promise<void>;\n upsertDiscoveredDocuments(\n inputs: ReadonlyArray<DiscoveredDocumentInput>,\n ): Promise<ReadonlyArray<DocumentSummary>>;\n}\n\nasync function listContainerItemWindow(\n execSql: ExecSql,\n input: ListContainerItemWindowInput,\n): Promise<ContainerItemWindow> {\n await ensureContainerTables(execSql);\n await sqlDocumentsPersistence.ensureSchema(execSql);\n await ensureSqlTables(execSql, localIntentTables);\n\n const limit = getContainerItemWindowLimit(input.limit);\n const offset = clampContainerItemWindowValue(input.offset);\n const visibleSystemSlots = Array.from(\n new Set(input.visibleSystemSlots ?? []),\n );\n const currentOrganizationId = input.currentOrganizationId || null;\n const visibleForeignSystemContainerNames = currentOrganizationId\n ? Array.from(new Set(input.visibleForeignSystemContainerNames ?? []))\n : [];\n const orphaned = input.containerId === null;\n const bind = orphaned\n ? getOrphanedDocumentQueryBind(input.currentOrganizationId)\n : [\n input.containerId,\n ...visibleSystemSlots,\n ...(visibleForeignSystemContainerNames.length > 0\n ? [currentOrganizationId, ...visibleForeignSystemContainerNames]\n : []),\n input.containerId,\n input.containerId,\n ];\n const baseSql = orphaned\n ? getOrphanedDocumentItemsBaseSql()\n : getContainerContentsContainerItemsBaseSql(\n visibleSystemSlots.length,\n visibleForeignSystemContainerNames.length,\n );\n const countRows = await execSql(\n `SELECT COUNT(*) AS total_count FROM (${baseSql})`,\n bind,\n );\n const totalCount = readContainerContentsContainerItemCount(\n countRows[0] ?? {},\n );\n\n if (limit === 0 || offset >= totalCount) {\n return { rows: [], totalCount };\n }\n\n const rows = await execSql(\n `${baseSql} ORDER BY ${getContainerContentsContainerItemOrderBy(input.sort)} LIMIT ? OFFSET ?`,\n [...bind, limit, offset],\n );\n\n return {\n rows: rows.map((row) => mapContainerItemRow(input.containerId, row)),\n totalCount,\n };\n}\n\nasync function hasOrphanedDocuments(\n execSql: ExecSql,\n currentOrganizationId: string | null,\n): Promise<boolean> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n const rows = await execSql(\n getOrphanedDocumentExistsSql(),\n getOrphanedDocumentQueryBind(currentOrganizationId),\n );\n return (\n rows.length > 0 ||\n (await hasRetainedContainerMetadata(execSql, currentOrganizationId)) ||\n (await listRecoveryFolderMoveIds(execSql, currentOrganizationId)).length > 0\n );\n}\n\nasync function listContainerDocumentSidebarWindow(\n execSql: ExecSql,\n input: {\n containerId: string | null;\n currentOrganizationId?: string | null | undefined;\n limit: number;\n offset: number;\n },\n): Promise<ContainerDocumentSidebarWindow> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n\n const limit = getContainerDocumentSidebarWindowLimit(input.limit);\n const offset = clampContainerItemWindowValue(input.offset);\n const orphaned = input.containerId === null;\n const bind = orphaned\n ? getOrphanedDocumentQueryBind(input.currentOrganizationId)\n : [input.containerId, input.containerId];\n const baseSql = orphaned\n ? getOrphanedDocumentRowsBaseSql()\n : getContainerContentsDocumentRowsBaseSql();\n const countRows = await execSql(\n `SELECT COUNT(*) AS total_count FROM (${baseSql})`,\n bind,\n );\n const totalCount = readContainerContentsContainerItemCount(\n countRows[0] ?? {},\n );\n\n if (limit === 0 || offset >= totalCount) {\n return { rows: [], totalCount };\n }\n\n const rows = await execSql(\n `${baseSql} ORDER BY ${getContainerContentsContainerDocumentSidebarOrderBy()} LIMIT ? OFFSET ?`,\n [...bind, limit, offset],\n );\n\n return {\n rows: rows.map(mapContainerDocumentSidebarRow),\n totalCount,\n };\n}\n\nasync function queryContainerContentsDocumentSummary(\n execSql: ExecSql,\n localId: string,\n scope: { bind: ReadonlyArray<string | null>; whereSql: string },\n): Promise<DocumentSummary | null> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n\n const rows = await execSql(\n `\n SELECT\n d.local_id AS local_id,\n d.document_id AS document_id,\n d.container_id AS container_id,\n d.document_kind AS document_kind,\n d.title AS title,\n d.updated_at AS updated_at,\n stored.access_state_hash AS access_state_hash,\n stored.effective_access_level AS effective_access_level\n FROM document_projection d\n LEFT JOIN documents stored\n ON stored.app_kind = 'documents'\n AND stored.local_id = d.local_id\n WHERE d.local_id = ?\n ${scope.whereSql}\n LIMIT 1\n `,\n [localId, ...scope.bind],\n );\n\n return mapContainerContentsDocumentSummaryRow(rows[0] ?? {});\n}\n\nfunction loadContainerContentsDocumentSummary(\n execSql: ExecSql,\n localId: string,\n requireHydrated: boolean,\n): Promise<DocumentSummary | null> {\n return queryContainerContentsDocumentSummary(execSql, localId, {\n bind: [],\n whereSql: requireHydrated\n ? `AND ${hydratedProjectionSql(\"d.local_id\", \"documents\")}`\n : \"\",\n });\n}\n\nfunction loadContainerContentsOrphanedDocumentSummary(\n execSql: ExecSql,\n localId: string,\n currentOrganizationId: string | null,\n requireHydrated: boolean,\n): Promise<DocumentSummary | null> {\n return queryContainerContentsDocumentSummary(execSql, localId, {\n bind: getOrphanedDocumentQueryBind(currentOrganizationId),\n whereSql: `${requireHydrated ? `AND ${hydratedProjectionSql(\"d.local_id\", \"documents\")}` : \"\"} AND ${getOrphanedDocumentWhereSql(\n {\n documentIdSql: \"d.document_id\",\n projectionAlias: \"d\",\n },\n )}`,\n });\n}\n\nasync function loadContainerContentsDocumentSyncState(\n execSql: ExecSql,\n localId: string,\n): Promise<ContainerDocumentObjectSyncState | null> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n\n const rows = await execSql(\n `\n WITH ${getContainerContentsDocumentPendingStateCtes()}\n SELECT\n d.document_id AS document_id,\n COALESCE(document_updates.pending_update_count, 0) AS pending_update_count,\n COALESCE(document_attachments.pending_attachment_count, 0) AS pending_attachment_count,\n COALESCE(document_attachments.pending_attachment_bytes, 0) AS pending_attachment_bytes,\n NULL AS sync_last_error\n FROM document_projection d\n LEFT JOIN document_pending_update_counts document_updates\n ON document_updates.local_id = d.local_id\n LEFT JOIN document_pending_attachment_counts document_attachments\n ON document_attachments.local_id = d.local_id\n WHERE d.local_id = ?\n LIMIT 1\n `,\n [localId],\n );\n const [row] = rows;\n if (!row) {\n return null;\n }\n\n return mapContainerContentsDocumentSyncStateRow(row);\n}\n\nasync function listContainerContentsLinkedContainerIdsByDocumentIds(\n execSql: ExecSql,\n documentIds: ReadonlyArray<string>,\n): Promise<ReadonlyMap<string, ReadonlyArray<string>>> {\n const uniqueDocumentIds = Array.from(new Set(documentIds));\n if (uniqueDocumentIds.length === 0) {\n return new Map();\n }\n\n const linkedContainerIdsByDocumentId = new Map<string, string[]>();\n for (const documentId of uniqueDocumentIds) {\n linkedContainerIdsByDocumentId.set(documentId, []);\n }\n\n for (const documentIdBatch of listContainerContentsSqlIdBatches(\n uniqueDocumentIds,\n )) {\n const batchLinkedContainerIdsByDocumentId =\n await sqlDocumentContainerProjectionPersistence.listLinkedContainerIdsByDocumentIds(\n execSql,\n documentIdBatch,\n );\n for (const [\n documentId,\n linkedContainerIds,\n ] of batchLinkedContainerIdsByDocumentId.entries()) {\n linkedContainerIdsByDocumentId.set(\n documentId,\n Array.from(linkedContainerIds),\n );\n }\n }\n\n return linkedContainerIdsByDocumentId;\n}\n\nexport function createContainerDocumentQueriesFromRuntime(\n runtime: ContainerDocumentQueriesRuntime,\n): ContainerDocumentQueries {\n const execSql = runtime.infra.execSql;\n return {\n ...createFolderRecoveryQueries(execSql),\n applyContainerDocumentTombstones(tombstones) {\n return applyPersistedContainerDocumentTombstones(execSql, tombstones);\n },\n hasOrphanedDocuments({ currentOrganizationId }) {\n return hasOrphanedDocuments(execSql, currentOrganizationId);\n },\n listContainerDocumentSidebarWindow(input) {\n return listContainerDocumentSidebarWindow(execSql, input);\n },\n listContainerItemWindow(input) {\n return listContainerItemWindow(execSql, input);\n },\n loadDocumentSyncState(localId) {\n return loadContainerContentsDocumentSyncState(execSql, localId);\n },\n loadDocumentSummary(localId, options) {\n return loadContainerContentsDocumentSummary(\n execSql,\n localId,\n options?.requireHydrated ?? false,\n );\n },\n loadOrphanedDocumentSummary({\n currentOrganizationId,\n localId,\n requireHydrated = false,\n }) {\n return loadContainerContentsOrphanedDocumentSummary(\n execSql,\n localId,\n currentOrganizationId,\n requireHydrated,\n );\n },\n loadContainerDocumentWatermark(containerId) {\n return sqlContainerSyncWatermarkPersistence.loadWatermark(\n execSql,\n containerContentsSyncLane(containerId),\n );\n },\n listLinkedContainerIdsByDocumentIds(documentIds) {\n return listContainerContentsLinkedContainerIdsByDocumentIds(\n execSql,\n documentIds,\n );\n },\n listPendingDownloads() {\n return listPendingDownloads(execSql);\n },\n listPendingWrites() {\n return listPendingWrites(execSql);\n },\n retryPendingWriteItem(input) {\n return resetPendingWriteRetryState(execSql, input);\n },\n replaceDocumentLinksBatch(inputs) {\n return sqlDocumentContainerProjectionPersistence.replaceDocumentLinksBatch(\n execSql,\n inputs,\n );\n },\n async saveContainerDocumentWatermark(containerId, watermark) {\n await sqlContainerSyncWatermarkPersistence.saveWatermark(\n execSql,\n containerContentsSyncLane(containerId),\n watermark,\n );\n },\n upsertDiscoveredDocuments(inputs) {\n return upsertDiscoveredDocuments(execSql, inputs);\n },\n };\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { SyncWatermark } from \"@tearleads/validators/response\";\nimport type {\n DiscoveredDocumentInput,\n DocumentSummary,\n} from \"../../../data/documents/documentSummary\";\nimport { sqlContainerContentsPersistence } from \"../../../data/persistence/container-contents/containerContentsPersistence\";\nimport { ensureContainerTables } from \"../../../data/persistence/container-contents/containerPersistence\";\nimport {\n RECOVERY_FOLDER_MOVES_SQL,\n RETAINED_CONTAINER_METADATA_SQL,\n} from \"../../../data/persistence/container-contents/containerRecoveryPersistence\";\nimport {\n containerContentsSyncLane,\n sqlContainerSyncWatermarkPersistence,\n} from \"../../../data/persistence/container-contents/containerSyncWatermarkPersistence\";\nimport { sqlDocumentContainerProjectionPersistence } from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport {\n applyContainerDocumentTombstones as applyPersistedContainerDocumentTombstones,\n sqlDocumentsPersistence,\n upsertDiscoveredDocuments,\n} from \"../../../data/persistence/documents/documentsPersistence\";\nimport {\n LOCAL_INTENT_LANES,\n localIntentTables,\n} from \"../../../data/sqlite/schema\";\nimport { type ExecSql, ensureSqlTables } from \"../../../data/sqlite/sqlSchema\";\nimport {\n listPendingWrites,\n type PendingWriteQueueItem,\n resetPendingWriteRetryState,\n} from \"../pendingWrites\";\nimport {\n createFolderRecoveryQueries,\n type RecoveryFolder,\n} from \"../recovery/folderRecovery\";\nimport type { ContainerDocumentObjectSyncState } from \"../syncState\";\nimport { hydratedProjectionSql } from \"./hydrationSql\";\nimport {\n getOrphanedDocumentQueryBind,\n getOrphanedDocumentWhereSql,\n} from \"./orphanedDocumentSql\";\nimport {\n listPendingDownloads,\n type PendingDownloadQueueItem,\n} from \"./pendingDownloads\";\nimport {\n mapContainerContentsDocumentSummaryRow,\n mapContainerContentsDocumentSyncStateRow,\n mapContainerDocumentSidebarRow,\n mapContainerItemRow,\n readContainerContentsContainerItemCount,\n} from \"./rows\";\nimport {\n clampContainerItemWindowValue,\n getContainerContentsContainerDocumentSidebarOrderBy,\n getContainerContentsContainerItemOrderBy,\n getContainerContentsContainerItemsBaseSql,\n getContainerContentsDocumentPendingStateCtes,\n getContainerContentsDocumentRowsBaseSql,\n getContainerDocumentSidebarWindowLimit,\n getContainerItemWindowLimit,\n getOrphanedDocumentExistsSql,\n getOrphanedDocumentItemsBaseSql,\n getOrphanedDocumentRowsBaseSql,\n listContainerContentsSqlIdBatches,\n} from \"./sql\";\nimport type {\n ContainerDocumentLinkInput,\n ContainerDocumentQueriesRuntime,\n ContainerDocumentSidebarWindow,\n ContainerDocumentTombstone,\n ContainerItemSort,\n ContainerItemWindow,\n} from \"./types\";\n\nexport type {\n ContainerDocumentLinkInput,\n ContainerDocumentSidebarRow,\n ContainerDocumentTombstone,\n ContainerItemRow,\n ContainerItemSort,\n ContainerItemSortDirection,\n ContainerItemSortKey,\n} from \"./types\";\n\ninterface ListContainerItemWindowInput {\n /** Null selects the virtual orphaned-documents recovery collection. */\n containerId: string | null;\n currentOrganizationId?: string | null | undefined;\n limit: number;\n offset: number;\n sort: ContainerItemSort;\n visibleForeignSystemContainerNames?: ReadonlyArray<string> | undefined;\n visibleSystemSlots?: ReadonlyArray<ContainerSystemSlot> | undefined;\n}\n\nexport interface ContainerDocumentQueries {\n listRecoveryFolderMoveIds(input: {\n currentOrganizationId: string | null;\n }): Promise<string[]>;\n listRecoveryFolders(input: {\n currentOrganizationId: string | null;\n }): Promise<RecoveryFolder[]>;\n discardRecoveryFolder(\n input: Pick<RecoveryFolder, \"containerId\" | \"organizationId\" | \"revision\">,\n ): Promise<boolean>;\n applyContainerDocumentTombstones(\n tombstones: ReadonlyArray<ContainerDocumentTombstone>,\n ): Promise<ReadonlyArray<DocumentSummary>>;\n hasOrphanedDocuments(input: {\n currentOrganizationId: string | null;\n }): Promise<boolean>;\n listContainerDocumentSidebarWindow(input: {\n /** Null selects the virtual orphaned-documents recovery collection. */\n containerId: string | null;\n currentOrganizationId?: string | null | undefined;\n limit: number;\n offset: number;\n }): Promise<ContainerDocumentSidebarWindow>;\n listContainerItemWindow(\n input: ListContainerItemWindowInput,\n ): Promise<ContainerItemWindow>;\n loadDocumentSyncState(\n localId: string,\n ): Promise<ContainerDocumentObjectSyncState | null>;\n loadDocumentSummary(\n localId: string,\n options?: { requireHydrated?: boolean },\n ): Promise<DocumentSummary | null>;\n loadOrphanedDocumentSummary(input: {\n requireHydrated?: boolean;\n currentOrganizationId: string | null;\n localId: string;\n }): Promise<DocumentSummary | null>;\n loadContainerDocumentWatermark(\n containerId: string,\n ): Promise<SyncWatermark | null>;\n listLinkedContainerIdsByDocumentIds(\n documentIds: ReadonlyArray<string>,\n ): Promise<ReadonlyMap<string, ReadonlyArray<string>>>;\n listPendingDownloads(): Promise<ReadonlyArray<PendingDownloadQueueItem>>;\n listPendingWrites(): Promise<ReadonlyArray<PendingWriteQueueItem>>;\n retryPendingWriteItem(input: {\n localId: string;\n namespace: string | null;\n objectKind: PendingWriteQueueItem[\"objectKind\"];\n }): Promise<void>;\n replaceDocumentLinksBatch(\n inputs: ReadonlyArray<ContainerDocumentLinkInput>,\n ): Promise<void>;\n saveContainerDocumentWatermark(\n containerId: string,\n watermark: SyncWatermark,\n ): Promise<void>;\n upsertDiscoveredDocuments(\n inputs: ReadonlyArray<DiscoveredDocumentInput>,\n ): Promise<ReadonlyArray<DocumentSummary>>;\n}\n\nasync function listContainerItemWindow(\n execSql: ExecSql,\n input: ListContainerItemWindowInput,\n): Promise<ContainerItemWindow> {\n await ensureContainerTables(execSql);\n await sqlDocumentsPersistence.ensureSchema(execSql);\n await ensureSqlTables(execSql, localIntentTables);\n\n const limit = getContainerItemWindowLimit(input.limit);\n const offset = clampContainerItemWindowValue(input.offset);\n const visibleSystemSlots = Array.from(\n new Set(input.visibleSystemSlots ?? []),\n );\n const currentOrganizationId = input.currentOrganizationId || null;\n const visibleForeignSystemContainerNames = currentOrganizationId\n ? Array.from(new Set(input.visibleForeignSystemContainerNames ?? []))\n : [];\n const orphaned = input.containerId === null;\n const bind = orphaned\n ? getOrphanedDocumentQueryBind(input.currentOrganizationId)\n : [\n input.containerId,\n ...visibleSystemSlots,\n ...(visibleForeignSystemContainerNames.length > 0\n ? [currentOrganizationId, ...visibleForeignSystemContainerNames]\n : []),\n input.containerId,\n input.containerId,\n ];\n const baseSql = orphaned\n ? getOrphanedDocumentItemsBaseSql()\n : getContainerContentsContainerItemsBaseSql(\n visibleSystemSlots.length,\n visibleForeignSystemContainerNames.length,\n );\n const countRows = await execSql(\n `SELECT COUNT(*) AS total_count FROM (${baseSql})`,\n bind,\n );\n const totalCount = readContainerContentsContainerItemCount(\n countRows[0] ?? {},\n );\n\n if (limit === 0 || offset >= totalCount) {\n return { rows: [], totalCount };\n }\n\n const rows = await execSql(\n `${baseSql} ORDER BY ${getContainerContentsContainerItemOrderBy(input.sort)} LIMIT ? OFFSET ?`,\n [...bind, limit, offset],\n );\n\n return {\n rows: rows.map((row) => mapContainerItemRow(input.containerId, row)),\n totalCount,\n };\n}\n\nasync function hasOrphanedDocuments(\n execSql: ExecSql,\n currentOrganizationId: string | null,\n): Promise<boolean> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n // One statement for all three probes; the folder probes need an\n // organization, as their standalone readers do.\n const folderProbes = currentOrganizationId\n ? `OR EXISTS(${RETAINED_CONTAINER_METADATA_SQL}) OR EXISTS(${RECOVERY_FOLDER_MOVES_SQL})`\n : \"\";\n if (currentOrganizationId)\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const rows = await execSql(\n `SELECT (EXISTS(${getOrphanedDocumentExistsSql()}) ${folderProbes}) AS found`,\n [\n ...getOrphanedDocumentQueryBind(currentOrganizationId),\n ...(currentOrganizationId\n ? [\n currentOrganizationId,\n LOCAL_INTENT_LANES.containerMove,\n currentOrganizationId,\n ]\n : []),\n ],\n );\n return Number(Object.values(rows[0] ?? {})[0] ?? 0) !== 0;\n}\n\nasync function listContainerDocumentSidebarWindow(\n execSql: ExecSql,\n input: {\n containerId: string | null;\n currentOrganizationId?: string | null | undefined;\n limit: number;\n offset: number;\n },\n): Promise<ContainerDocumentSidebarWindow> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n\n const limit = getContainerDocumentSidebarWindowLimit(input.limit);\n const offset = clampContainerItemWindowValue(input.offset);\n const orphaned = input.containerId === null;\n const bind = orphaned\n ? getOrphanedDocumentQueryBind(input.currentOrganizationId)\n : [input.containerId, input.containerId];\n const baseSql = orphaned\n ? getOrphanedDocumentRowsBaseSql()\n : getContainerContentsDocumentRowsBaseSql();\n const countRows = await execSql(\n `SELECT COUNT(*) AS total_count FROM (${baseSql})`,\n bind,\n );\n const totalCount = readContainerContentsContainerItemCount(\n countRows[0] ?? {},\n );\n\n if (limit === 0 || offset >= totalCount) {\n return { rows: [], totalCount };\n }\n\n const rows = await execSql(\n `${baseSql} ORDER BY ${getContainerContentsContainerDocumentSidebarOrderBy()} LIMIT ? OFFSET ?`,\n [...bind, limit, offset],\n );\n\n return {\n rows: rows.map(mapContainerDocumentSidebarRow),\n totalCount,\n };\n}\n\nasync function queryContainerContentsDocumentSummary(\n execSql: ExecSql,\n localId: string,\n scope: { bind: ReadonlyArray<string | null>; whereSql: string },\n): Promise<DocumentSummary | null> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n\n const rows = await execSql(\n `\n SELECT\n d.local_id AS local_id,\n d.document_id AS document_id,\n d.container_id AS container_id,\n d.document_kind AS document_kind,\n d.title AS title,\n d.updated_at AS updated_at,\n stored.access_state_hash AS access_state_hash,\n stored.effective_access_level AS effective_access_level\n FROM document_projection d\n LEFT JOIN documents stored\n ON stored.app_kind = 'documents'\n AND stored.local_id = d.local_id\n WHERE d.local_id = ?\n ${scope.whereSql}\n LIMIT 1\n `,\n [localId, ...scope.bind],\n );\n\n return mapContainerContentsDocumentSummaryRow(rows[0] ?? {});\n}\n\nfunction loadContainerContentsDocumentSummary(\n execSql: ExecSql,\n localId: string,\n requireHydrated: boolean,\n): Promise<DocumentSummary | null> {\n return queryContainerContentsDocumentSummary(execSql, localId, {\n bind: [],\n whereSql: requireHydrated\n ? `AND ${hydratedProjectionSql(\"d.local_id\", \"documents\")}`\n : \"\",\n });\n}\n\nfunction loadContainerContentsOrphanedDocumentSummary(\n execSql: ExecSql,\n localId: string,\n currentOrganizationId: string | null,\n requireHydrated: boolean,\n): Promise<DocumentSummary | null> {\n return queryContainerContentsDocumentSummary(execSql, localId, {\n bind: getOrphanedDocumentQueryBind(currentOrganizationId),\n whereSql: `${requireHydrated ? `AND ${hydratedProjectionSql(\"d.local_id\", \"documents\")}` : \"\"} AND ${getOrphanedDocumentWhereSql(\n {\n documentIdSql: \"d.document_id\",\n projectionAlias: \"d\",\n },\n )}`,\n });\n}\n\nasync function loadContainerContentsDocumentSyncState(\n execSql: ExecSql,\n localId: string,\n): Promise<ContainerDocumentObjectSyncState | null> {\n await sqlDocumentsPersistence.ensureSchema(execSql);\n\n const rows = await execSql(\n `\n WITH ${getContainerContentsDocumentPendingStateCtes()}\n SELECT\n d.document_id AS document_id,\n COALESCE(document_updates.pending_update_count, 0) AS pending_update_count,\n COALESCE(document_attachments.pending_attachment_count, 0) AS pending_attachment_count,\n COALESCE(document_attachments.pending_attachment_bytes, 0) AS pending_attachment_bytes,\n NULL AS sync_last_error\n FROM document_projection d\n LEFT JOIN document_pending_update_counts document_updates\n ON document_updates.local_id = d.local_id\n LEFT JOIN document_pending_attachment_counts document_attachments\n ON document_attachments.local_id = d.local_id\n WHERE d.local_id = ?\n LIMIT 1\n `,\n [localId],\n );\n const [row] = rows;\n if (!row) {\n return null;\n }\n\n return mapContainerContentsDocumentSyncStateRow(row);\n}\n\nasync function listContainerContentsLinkedContainerIdsByDocumentIds(\n execSql: ExecSql,\n documentIds: ReadonlyArray<string>,\n): Promise<ReadonlyMap<string, ReadonlyArray<string>>> {\n const uniqueDocumentIds = Array.from(new Set(documentIds));\n if (uniqueDocumentIds.length === 0) {\n return new Map();\n }\n\n const linkedContainerIdsByDocumentId = new Map<string, string[]>();\n for (const documentId of uniqueDocumentIds) {\n linkedContainerIdsByDocumentId.set(documentId, []);\n }\n\n for (const documentIdBatch of listContainerContentsSqlIdBatches(\n uniqueDocumentIds,\n )) {\n const batchLinkedContainerIdsByDocumentId =\n await sqlDocumentContainerProjectionPersistence.listLinkedContainerIdsByDocumentIds(\n execSql,\n documentIdBatch,\n );\n for (const [\n documentId,\n linkedContainerIds,\n ] of batchLinkedContainerIdsByDocumentId.entries()) {\n linkedContainerIdsByDocumentId.set(\n documentId,\n Array.from(linkedContainerIds),\n );\n }\n }\n\n return linkedContainerIdsByDocumentId;\n}\n\nexport function createContainerDocumentQueriesFromRuntime(\n runtime: ContainerDocumentQueriesRuntime,\n): ContainerDocumentQueries {\n const execSql = runtime.infra.execSql;\n return {\n ...createFolderRecoveryQueries(execSql),\n applyContainerDocumentTombstones(tombstones) {\n return applyPersistedContainerDocumentTombstones(execSql, tombstones);\n },\n hasOrphanedDocuments({ currentOrganizationId }) {\n return hasOrphanedDocuments(execSql, currentOrganizationId);\n },\n listContainerDocumentSidebarWindow(input) {\n return listContainerDocumentSidebarWindow(execSql, input);\n },\n listContainerItemWindow(input) {\n return listContainerItemWindow(execSql, input);\n },\n loadDocumentSyncState(localId) {\n return loadContainerContentsDocumentSyncState(execSql, localId);\n },\n loadDocumentSummary(localId, options) {\n return loadContainerContentsDocumentSummary(\n execSql,\n localId,\n options?.requireHydrated ?? false,\n );\n },\n loadOrphanedDocumentSummary({\n currentOrganizationId,\n localId,\n requireHydrated = false,\n }) {\n return loadContainerContentsOrphanedDocumentSummary(\n execSql,\n localId,\n currentOrganizationId,\n requireHydrated,\n );\n },\n loadContainerDocumentWatermark(containerId) {\n return sqlContainerSyncWatermarkPersistence.loadWatermark(\n execSql,\n containerContentsSyncLane(containerId),\n );\n },\n listLinkedContainerIdsByDocumentIds(documentIds) {\n return listContainerContentsLinkedContainerIdsByDocumentIds(\n execSql,\n documentIds,\n );\n },\n listPendingDownloads() {\n return listPendingDownloads(execSql);\n },\n listPendingWrites() {\n return listPendingWrites(execSql);\n },\n retryPendingWriteItem(input) {\n return resetPendingWriteRetryState(execSql, input);\n },\n replaceDocumentLinksBatch(inputs) {\n return sqlDocumentContainerProjectionPersistence.replaceDocumentLinksBatch(\n execSql,\n inputs,\n );\n },\n async saveContainerDocumentWatermark(containerId, watermark) {\n await sqlContainerSyncWatermarkPersistence.saveWatermark(\n execSql,\n containerContentsSyncLane(containerId),\n watermark,\n );\n },\n upsertDiscoveredDocuments(inputs) {\n return upsertDiscoveredDocuments(execSql, inputs);\n },\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { and, eq, inArray } from "drizzle-orm";
1
+ import { and, eq, inArray, sql } from "drizzle-orm";
2
2
  import { deleteDocumentPlacementRowsByContainerIds, deleteDocumentPlacementRowsByDocumentIds, } from "../../../data/persistence/container-contents/documentContainerProjectionPersistence.js";
3
3
  import { recordSupersededContainerBindingsInTransaction } from "../../../data/persistence/container-contents/supersededContainerBindings.js";
4
4
  import { containerHydrationTombstones, containerSyncWatermarks, containers, documentContainerProjection, dormantContainerMetadata, dormantMetadataSweepRequests, inContainerIntentLanes, inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../../data/sqlite/schema/index.js";
@@ -124,21 +124,26 @@ export async function resetContainerServerIdentity(input) {
124
124
  supersededAt: now,
125
125
  });
126
126
  }
127
- for (const row of input.containerRows) {
127
+ // One update per batch: SQLite evaluates every SET value against the old
128
+ // row, and no earlier reset step writes `parent_id`, so COALESCE re-homes
129
+ // exactly the root folders the snapshot read with a null parent.
130
+ for (const rowBatch of remoteResetBatches(input.containerRows)) {
128
131
  await tx
129
132
  .update(containers)
130
133
  .set({
131
134
  metadataDocumentId: null,
132
135
  organizationId: reset.replacement?.organizationId ?? reset.organizationId,
133
- parentId: reset.replacement && row.parentId === null
134
- ? reset.replacement.rootContainerId
135
- : row.parentId,
136
+ ...(reset.replacement
137
+ ? {
138
+ parentId: sql `coalesce(${containers.parentId}, ${reset.replacement.rootContainerId})`,
139
+ systemSlot: null,
140
+ }
141
+ : {}),
136
142
  serverCreatedAt: null,
137
143
  serverUpdatedAt: null,
138
- ...(reset.replacement ? { systemSlot: null } : {}),
139
144
  localUpdatedAt: now,
140
145
  })
141
- .where(eq(containers.id, row.id))
146
+ .where(inArray(containers.id, rowBatch.map((row) => row.id)))
142
147
  .run();
143
148
  }
144
149
  }
@@ -1 +1 @@
1
- {"version":3,"file":"containerRemoteReset.js","sourceRoot":"","sources":["containerRemoteReset.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray } from \"drizzle-orm\";\nimport {\n deleteDocumentPlacementRowsByContainerIds,\n deleteDocumentPlacementRowsByDocumentIds,\n} from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { recordSupersededContainerBindingsInTransaction } from \"../../../data/persistence/container-contents/supersededContainerBindings\";\nimport {\n containerHydrationTombstones,\n containerSyncWatermarks,\n containers,\n documentContainerProjection,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../../data/sqlite/schema\";\nimport { documentIntentLinkTargets } from \"../../../data/sqlite/schema/documentPlacementIntentSchema\";\nimport { remoteResetBatches } from \"../../../data/sqlite/sqliteBindBudget\";\nimport type { ClientSQLiteTransactionScope } from \"../../../data/sqlite/sqlitePersistenceRuntime\";\nimport { isRemoteResetSyncCursor } from \"./remoteResetCursorScope\";\n\n// Container Contents' part of a remote reset. The sync remote reset calls these\n// in one transaction: it forgets the organization's server state, strips server\n// identity from the folders it keeps, and queues them to be created again.\nexport { clearRemoteResetSyncCursors } from \"./remoteResetCursorScope\";\n\nconst CONTAINER_CREATE_INTENT_TYPE = \"container.create\";\n\nexport interface ContainerRemoteReset {\n readonly organizationId: string;\n readonly replacement?:\n | {\n readonly organizationId: string;\n readonly rootContainerId: string;\n }\n | undefined;\n}\n\nexport interface ResetContainerRow {\n readonly id: string;\n readonly parentId: string | null;\n}\n\n/** The organization's live folders, plus the ids of its dormant ones. */\nexport async function loadContainerResetScope(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<{\n containerIds: string[];\n containerRows: ResetContainerRow[];\n}> {\n const liveContainerRows = (\n await tx\n .select({ id: containers.id, parentId: containers.parentId })\n .from(containers)\n .where(eq(containers.organizationId, organizationId))\n ).flatMap((row) => (row.id ? [{ id: row.id, parentId: row.parentId }] : []));\n const dormantContainerRows = await tx\n .select({ id: dormantContainerMetadata.containerId })\n .from(dormantContainerMetadata)\n .where(eq(dormantContainerMetadata.organizationId, organizationId));\n const containerRows = liveContainerRows;\n return {\n containerIds: [\n ...new Set([\n ...containerRows.map((row) => row.id),\n ...dormantContainerRows.map((row) => row.id),\n ]),\n ],\n containerRows,\n };\n}\n\n/** Every document placement, which decides the documents a reset covers. */\nexport function listDocumentPlacementRows(tx: ClientSQLiteTransactionScope) {\n return tx.select().from(documentContainerProjection);\n}\n\n/** Counts the queued folder and document move intents a reset clears. */\nexport async function countContainerResetIntents(input: {\n containerIds: readonly string[];\n documentLocalIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<{\n clearedContainerCreateIntentCount: number;\n clearedContainerMoveIntentCount: number;\n clearedDocumentMoveIntentCount: number;\n}> {\n const containerIdSet = new Set(input.containerIds);\n const documentLocalIdSet = new Set(input.documentLocalIds);\n const intents = await input.tx\n .select({\n lane: localIntents.lane,\n localId: localIntents.localId,\n subjectId: localIntents.subjectId,\n })\n .from(localIntents);\n const containerIntentCount = (lane: string) =>\n intents.filter(\n (row) => row.lane === lane && containerIdSet.has(row.subjectId),\n ).length;\n return {\n clearedContainerCreateIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerCreate,\n ),\n clearedContainerMoveIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerMove,\n ),\n clearedDocumentMoveIntentCount: intents.filter(\n (row) =>\n row.lane === LOCAL_INTENT_LANES.documentPlacement &&\n row.localId !== null &&\n documentLocalIdSet.has(row.localId),\n ).length,\n };\n}\n\n/** Counts the sync cursors `clearRemoteResetSyncCursors` deletes. */\nexport async function countRemoteResetSyncCursors(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<number> {\n const scopedContainerIds = new Set(input.containerIds);\n const syncLanes = await input.tx.select().from(containerSyncWatermarks);\n return syncLanes.filter((row) =>\n isRemoteResetSyncCursor({\n containerIds: scopedContainerIds,\n row,\n }),\n ).length;\n}\n\nexport async function clearDormantContainerMetadataForRemoteReset(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<void> {\n for (const table of [\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n ] as const) {\n await tx\n .delete(table)\n .where(eq(table.organizationId, organizationId))\n .run();\n }\n}\n\n/** Clears the folders' placements, queued intents, and hydration tombstones. */\nexport async function clearContainerRowsForRemoteReset(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n for (const containerBatch of remoteResetBatches(input.containerIds)) {\n await deleteDocumentPlacementRowsByContainerIds(input.tx, containerBatch);\n await input.tx\n .delete(localIntents)\n .where(\n and(\n inContainerIntentLanes(),\n inArray(localIntents.subjectId, containerBatch),\n ),\n )\n .run();\n await input.tx\n .delete(containerHydrationTombstones)\n .where(inArray(containerHydrationTombstones.containerId, containerBatch))\n .run();\n }\n}\n\n/** Clears the documents' placements and their queued placement intents. */\nexport async function clearDocumentPlacementsForRemoteReset(input: {\n documentLocalIds: readonly string[];\n oldDocumentIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { tx } = input;\n for (const documentIdBatch of remoteResetBatches(input.oldDocumentIds)) {\n await deleteDocumentPlacementRowsByDocumentIds(tx, documentIdBatch);\n }\n for (const localIdBatch of remoteResetBatches(input.documentLocalIds)) {\n const placementIntents = and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n inArray(localIntents.localId, localIdBatch),\n );\n await tx\n .delete(documentIntentLinkTargets)\n .where(\n inArray(\n documentIntentLinkTargets.intentId,\n tx\n .select({ id: localIntents.id })\n .from(localIntents)\n .where(placementIntents),\n ),\n )\n .run();\n await tx.delete(localIntents).where(placementIntents).run();\n }\n}\n\n/**\n * Drops the folders' server timestamps and metadata document, and moves them\n * to the replacement organization when there is one.\n */\nexport async function resetContainerServerIdentity(input: {\n containerIds: readonly string[];\n containerRows: readonly ResetContainerRow[];\n now: string;\n reset: ContainerRemoteReset;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { now, reset, tx } = input;\n // Replacement re-homes folders under their ids; the purged organization\n // can never bind them again on this device.\n for (const containerIds of reset.replacement\n ? remoteResetBatches(input.containerIds)\n : []) {\n await recordSupersededContainerBindingsInTransaction(tx, {\n containerIds,\n organizationId: reset.organizationId,\n supersededAt: now,\n });\n }\n for (const row of input.containerRows) {\n await tx\n .update(containers)\n .set({\n metadataDocumentId: null,\n organizationId:\n reset.replacement?.organizationId ?? reset.organizationId,\n parentId:\n reset.replacement && row.parentId === null\n ? reset.replacement.rootContainerId\n : row.parentId,\n serverCreatedAt: null,\n serverUpdatedAt: null,\n ...(reset.replacement ? { systemSlot: null } : {}),\n localUpdatedAt: now,\n })\n .where(eq(containers.id, row.id))\n .run();\n }\n}\n\n/** Queues a create for every kept folder that has a parent to create it in. */\nexport async function queueContainerCreatesForRemoteReset(input: {\n containerRows: readonly ResetContainerRow[];\n now: string;\n reset: ContainerRemoteReset;\n tx: ClientSQLiteTransactionScope;\n}): Promise<number> {\n const rows = input.containerRows.flatMap((row) => {\n const parentId =\n row.parentId ?? input.reset.replacement?.rootContainerId ?? null;\n return parentId ? [{ id: row.id, parentId }] : [];\n });\n if (rows.length === 0) return 0;\n for (const rowBatch of remoteResetBatches(rows)) {\n await input.tx\n .insert(localIntents)\n .values(\n rowBatch.map((row) => ({\n id: crypto.randomUUID(),\n lane: LOCAL_INTENT_LANES.containerCreate,\n subjectId: row.id,\n targetContainerId: row.parentId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\" as const,\n remoteContainerId: null,\n remoteMetadataAccessStateHash: null,\n remoteMetadataDocumentId: null,\n lastError: null,\n createdAt: input.now,\n updatedAt: input.now,\n })),\n )\n .run();\n }\n return rows.length;\n}\n"]}
1
+ {"version":3,"file":"containerRemoteReset.js","sourceRoot":"","sources":["containerRemoteReset.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray, sql } from \"drizzle-orm\";\nimport {\n deleteDocumentPlacementRowsByContainerIds,\n deleteDocumentPlacementRowsByDocumentIds,\n} from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { recordSupersededContainerBindingsInTransaction } from \"../../../data/persistence/container-contents/supersededContainerBindings\";\nimport {\n containerHydrationTombstones,\n containerSyncWatermarks,\n containers,\n documentContainerProjection,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../../data/sqlite/schema\";\nimport { documentIntentLinkTargets } from \"../../../data/sqlite/schema/documentPlacementIntentSchema\";\nimport { remoteResetBatches } from \"../../../data/sqlite/sqliteBindBudget\";\nimport type { ClientSQLiteTransactionScope } from \"../../../data/sqlite/sqlitePersistenceRuntime\";\nimport { isRemoteResetSyncCursor } from \"./remoteResetCursorScope\";\n\n// Container Contents' part of a remote reset. The sync remote reset calls these\n// in one transaction: it forgets the organization's server state, strips server\n// identity from the folders it keeps, and queues them to be created again.\nexport { clearRemoteResetSyncCursors } from \"./remoteResetCursorScope\";\n\nconst CONTAINER_CREATE_INTENT_TYPE = \"container.create\";\n\nexport interface ContainerRemoteReset {\n readonly organizationId: string;\n readonly replacement?:\n | {\n readonly organizationId: string;\n readonly rootContainerId: string;\n }\n | undefined;\n}\n\nexport interface ResetContainerRow {\n readonly id: string;\n readonly parentId: string | null;\n}\n\n/** The organization's live folders, plus the ids of its dormant ones. */\nexport async function loadContainerResetScope(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<{\n containerIds: string[];\n containerRows: ResetContainerRow[];\n}> {\n const liveContainerRows = (\n await tx\n .select({ id: containers.id, parentId: containers.parentId })\n .from(containers)\n .where(eq(containers.organizationId, organizationId))\n ).flatMap((row) => (row.id ? [{ id: row.id, parentId: row.parentId }] : []));\n const dormantContainerRows = await tx\n .select({ id: dormantContainerMetadata.containerId })\n .from(dormantContainerMetadata)\n .where(eq(dormantContainerMetadata.organizationId, organizationId));\n const containerRows = liveContainerRows;\n return {\n containerIds: [\n ...new Set([\n ...containerRows.map((row) => row.id),\n ...dormantContainerRows.map((row) => row.id),\n ]),\n ],\n containerRows,\n };\n}\n\n/** Every document placement, which decides the documents a reset covers. */\nexport function listDocumentPlacementRows(tx: ClientSQLiteTransactionScope) {\n return tx.select().from(documentContainerProjection);\n}\n\n/** Counts the queued folder and document move intents a reset clears. */\nexport async function countContainerResetIntents(input: {\n containerIds: readonly string[];\n documentLocalIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<{\n clearedContainerCreateIntentCount: number;\n clearedContainerMoveIntentCount: number;\n clearedDocumentMoveIntentCount: number;\n}> {\n const containerIdSet = new Set(input.containerIds);\n const documentLocalIdSet = new Set(input.documentLocalIds);\n const intents = await input.tx\n .select({\n lane: localIntents.lane,\n localId: localIntents.localId,\n subjectId: localIntents.subjectId,\n })\n .from(localIntents);\n const containerIntentCount = (lane: string) =>\n intents.filter(\n (row) => row.lane === lane && containerIdSet.has(row.subjectId),\n ).length;\n return {\n clearedContainerCreateIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerCreate,\n ),\n clearedContainerMoveIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerMove,\n ),\n clearedDocumentMoveIntentCount: intents.filter(\n (row) =>\n row.lane === LOCAL_INTENT_LANES.documentPlacement &&\n row.localId !== null &&\n documentLocalIdSet.has(row.localId),\n ).length,\n };\n}\n\n/** Counts the sync cursors `clearRemoteResetSyncCursors` deletes. */\nexport async function countRemoteResetSyncCursors(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<number> {\n const scopedContainerIds = new Set(input.containerIds);\n const syncLanes = await input.tx.select().from(containerSyncWatermarks);\n return syncLanes.filter((row) =>\n isRemoteResetSyncCursor({\n containerIds: scopedContainerIds,\n row,\n }),\n ).length;\n}\n\nexport async function clearDormantContainerMetadataForRemoteReset(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<void> {\n for (const table of [\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n ] as const) {\n await tx\n .delete(table)\n .where(eq(table.organizationId, organizationId))\n .run();\n }\n}\n\n/** Clears the folders' placements, queued intents, and hydration tombstones. */\nexport async function clearContainerRowsForRemoteReset(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n for (const containerBatch of remoteResetBatches(input.containerIds)) {\n await deleteDocumentPlacementRowsByContainerIds(input.tx, containerBatch);\n await input.tx\n .delete(localIntents)\n .where(\n and(\n inContainerIntentLanes(),\n inArray(localIntents.subjectId, containerBatch),\n ),\n )\n .run();\n await input.tx\n .delete(containerHydrationTombstones)\n .where(inArray(containerHydrationTombstones.containerId, containerBatch))\n .run();\n }\n}\n\n/** Clears the documents' placements and their queued placement intents. */\nexport async function clearDocumentPlacementsForRemoteReset(input: {\n documentLocalIds: readonly string[];\n oldDocumentIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { tx } = input;\n for (const documentIdBatch of remoteResetBatches(input.oldDocumentIds)) {\n await deleteDocumentPlacementRowsByDocumentIds(tx, documentIdBatch);\n }\n for (const localIdBatch of remoteResetBatches(input.documentLocalIds)) {\n const placementIntents = and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n inArray(localIntents.localId, localIdBatch),\n );\n await tx\n .delete(documentIntentLinkTargets)\n .where(\n inArray(\n documentIntentLinkTargets.intentId,\n tx\n .select({ id: localIntents.id })\n .from(localIntents)\n .where(placementIntents),\n ),\n )\n .run();\n await tx.delete(localIntents).where(placementIntents).run();\n }\n}\n\n/**\n * Drops the folders' server timestamps and metadata document, and moves them\n * to the replacement organization when there is one.\n */\nexport async function resetContainerServerIdentity(input: {\n containerIds: readonly string[];\n containerRows: readonly ResetContainerRow[];\n now: string;\n reset: ContainerRemoteReset;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { now, reset, tx } = input;\n // Replacement re-homes folders under their ids; the purged organization\n // can never bind them again on this device.\n for (const containerIds of reset.replacement\n ? remoteResetBatches(input.containerIds)\n : []) {\n await recordSupersededContainerBindingsInTransaction(tx, {\n containerIds,\n organizationId: reset.organizationId,\n supersededAt: now,\n });\n }\n // One update per batch: SQLite evaluates every SET value against the old\n // row, and no earlier reset step writes `parent_id`, so COALESCE re-homes\n // exactly the root folders the snapshot read with a null parent.\n for (const rowBatch of remoteResetBatches(input.containerRows)) {\n await tx\n .update(containers)\n .set({\n metadataDocumentId: null,\n organizationId:\n reset.replacement?.organizationId ?? reset.organizationId,\n ...(reset.replacement\n ? {\n parentId: sql`coalesce(${containers.parentId}, ${reset.replacement.rootContainerId})`,\n systemSlot: null,\n }\n : {}),\n serverCreatedAt: null,\n serverUpdatedAt: null,\n localUpdatedAt: now,\n })\n .where(\n inArray(\n containers.id,\n rowBatch.map((row) => row.id),\n ),\n )\n .run();\n }\n}\n\n/** Queues a create for every kept folder that has a parent to create it in. */\nexport async function queueContainerCreatesForRemoteReset(input: {\n containerRows: readonly ResetContainerRow[];\n now: string;\n reset: ContainerRemoteReset;\n tx: ClientSQLiteTransactionScope;\n}): Promise<number> {\n const rows = input.containerRows.flatMap((row) => {\n const parentId =\n row.parentId ?? input.reset.replacement?.rootContainerId ?? null;\n return parentId ? [{ id: row.id, parentId }] : [];\n });\n if (rows.length === 0) return 0;\n for (const rowBatch of remoteResetBatches(rows)) {\n await input.tx\n .insert(localIntents)\n .values(\n rowBatch.map((row) => ({\n id: crypto.randomUUID(),\n lane: LOCAL_INTENT_LANES.containerCreate,\n subjectId: row.id,\n targetContainerId: row.parentId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\" as const,\n remoteContainerId: null,\n remoteMetadataAccessStateHash: null,\n remoteMetadataDocumentId: null,\n lastError: null,\n createdAt: input.now,\n updatedAt: input.now,\n })),\n )\n .run();\n }\n return rows.length;\n}\n"]}
@@ -2,8 +2,8 @@ import { getTextValue } from "../../internal/loro/index.js";
2
2
  import { DEFAULT_DOCUMENT_ACCESS_EPOCH, DEFAULT_DOCUMENT_KIND, } from "../../data/documents/documentConstants.js";
3
3
  import { readStoredDocumentState, } from "../../data/documents/documentKinds.js";
4
4
  import { createInitialDocumentRows } from "./create/documentCreationPersistence.js";
5
- import { documentSyncSecurityContextMatches, prepareDocumentMutation, } from "./documentMutationPreparation.js";
6
- import { refuseDeletedDocumentPersist } from "./documentPersistGuards.js";
5
+ import { documentSyncSecurityContextMatches, } from "./documentMutationPreparation.js";
6
+ import { prepareDocumentMutationUnlessDeleted } from "./documentPersistGuards.js";
7
7
  const MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS = 8;
8
8
  async function loadSupersededPersistedDocumentState(input) {
9
9
  const { document, historyRestoreState } = await input.persistence.loadDocumentWithHistoryRestoreState(input.execSql, input.localId);
@@ -261,18 +261,17 @@ async function commitOnePreparedDocumentMutation(input) {
261
261
  }
262
262
  export async function commitPreparedDocumentState(input) {
263
263
  const { lockedExecSql, persistInput } = input;
264
- if (await refuseDeletedDocumentPersist({
265
- currentRecord: persistInput.currentRecord,
266
- documentProjectors: input.documentProjectors,
267
- execSql: lockedExecSql,
268
- localId: persistInput.localId,
269
- persistence: persistInput.persistence,
270
- })) {
271
- return null;
272
- }
273
264
  const acceptedPendingUpdateIds = persistInput.acceptedPendingUpdateIds ?? [];
274
265
  for (let attempt = 0; attempt < MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS; attempt += 1) {
275
- const mutation = await prepareDocumentMutation(persistInput, lockedExecSql, input.patch);
266
+ const mutation = await prepareDocumentMutationUnlessDeleted({
267
+ documentProjectors: input.documentProjectors,
268
+ guard: attempt === 0,
269
+ lockedExecSql,
270
+ patch: input.patch,
271
+ persistInput,
272
+ });
273
+ if (!mutation)
274
+ return null;
276
275
  if (mutation.pullContinuationSuperseded) {
277
276
  return settleSupersededDocumentMutation({
278
277
  acceptedPendingUpdateIds,
@@ -1 +1 @@
1
- {"version":3,"file":"documentMutationCommit.js","sourceRoot":"","sources":["documentMutationCommit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type encodeVersionVector, getTextValue } from \"@tearleads/loro\";\nimport {\n DEFAULT_DOCUMENT_ACCESS_EPOCH,\n DEFAULT_DOCUMENT_KIND,\n} from \"../../data/documents/documentConstants\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n readStoredDocumentState,\n} from \"../../data/documents/documentKinds\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { PendingUpdateFields } from \"../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { createInitialDocumentRows } from \"./create/documentCreationPersistence\";\nimport {\n documentSyncSecurityContextMatches,\n type PrepareDocumentMutationInput,\n prepareDocumentMutation,\n} from \"./documentMutationPreparation\";\nimport { refuseDeletedDocumentPersist } from \"./documentPersistGuards\";\n\ntype DocumentContentState = Parameters<typeof encodeVersionVector>[0];\ntype NullableDocumentRuntimeField =\n | \"accessStateHash\"\n | \"lastCommitLsn\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\";\n\nconst MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS = 8;\n\nexport interface PersistedDocumentState {\n creationSuperseded?: true;\n historyRestoreState?:\n | Awaited<ReturnType<DocumentsPersistence[\"loadHistoryRestoreState\"]>>\n | undefined;\n pullContinuationSuperseded?: true;\n record: StoredDocumentRecord;\n syncIdentitySuperseded?: true;\n updatedAt?: string | undefined;\n}\n\nexport interface PersistDocumentStateInput\n extends PrepareDocumentMutationInput {\n acceptedPendingUpdateIds?: readonly string[] | undefined;\n attachmentRemoval?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentRemoval\"]\n | undefined;\n attachmentStaging?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentStaging\"]\n | undefined;\n canStartDurableMutation?: (() => boolean) | undefined;\n clearSyncFailure?: boolean | undefined;\n commitSideEffect?: (transactionExecSql: ExecSql) => Promise<void>;\n containerId?: string | null | undefined;\n documentProjectors: DocumentProjectorRegistryInput;\n execSql: ExecSql;\n patch?: Partial<StoredDocumentRecord> | undefined;\n pendingUpdate?: PendingUpdateFields | undefined;\n}\n\nasync function loadSupersededPersistedDocumentState(input: {\n creationSuperseded: boolean;\n execSql: ExecSql;\n localId: string;\n persistence: DocumentsPersistence;\n record: StoredDocumentRecord;\n syncIdentitySuperseded: boolean;\n}): Promise<PersistedDocumentState | null> {\n const { document, historyRestoreState } =\n await input.persistence.loadDocumentWithHistoryRestoreState(\n input.execSql,\n input.localId,\n );\n if (!document) return null;\n const syncIdentitySuperseded =\n input.syncIdentitySuperseded ||\n !documentSyncSecurityContextMatches(document, input.record);\n return {\n ...(input.creationSuperseded ? { creationSuperseded: true as const } : {}),\n historyRestoreState,\n pullContinuationSuperseded: true,\n record: document,\n ...(syncIdentitySuperseded\n ? { syncIdentitySuperseded: true as const }\n : {}),\n };\n}\n\nfunction resolveNullableDocumentRuntimeField(\n patch: Partial<StoredDocumentRecord>,\n key: NullableDocumentRuntimeField,\n currentValue: string | null | undefined,\n resetWhenUnpatched = false,\n): string | null {\n if (Object.hasOwn(patch, key)) return patch[key] ?? null;\n return resetWhenUnpatched ? null : (currentValue ?? null);\n}\n\nfunction resolveStoredDocumentContainerId(input: {\n containerId?: string | null | undefined;\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n}): string | null {\n if (Object.hasOwn(input.patch, \"containerId\")) {\n return input.patch.containerId ?? null;\n }\n return input.currentRecord?.containerId ?? input.containerId ?? null;\n}\n\nfunction resolveStoredDocumentPullState(input: {\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n securityContextChanged: boolean;\n}): Pick<\n StoredDocumentRecord,\n \"pullContinuation\" | \"pullContinuationRecoveryRequired\"\n> {\n if (Object.hasOwn(input.patch, \"pullContinuation\")) {\n return { pullContinuation: input.patch.pullContinuation ?? null };\n }\n if (input.securityContextChanged) return { pullContinuation: null };\n if (input.currentRecord?.pullContinuationRecoveryRequired) {\n return { pullContinuationRecoveryRequired: true };\n }\n return { pullContinuation: input.currentRecord?.pullContinuation ?? null };\n}\n\nfunction buildStoredDocumentRecord(input: {\n containerId?: string | null | undefined;\n currentDoc: DocumentContentState;\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n localId: string;\n patch: Partial<StoredDocumentRecord>;\n}) {\n const { currentDoc, currentRecord, documentProjectors, localId, patch } =\n input;\n const currentDocumentId = currentRecord?.documentId ?? null;\n const nextDocumentId = patch.documentId ?? currentDocumentId;\n const documentIdChanged = nextDocumentId !== currentDocumentId;\n const currentAccessEpoch =\n currentRecord?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH;\n const nextAccessEpoch = patch.accessEpoch ?? currentAccessEpoch;\n const securityContextChanged =\n documentIdChanged || nextAccessEpoch !== currentAccessEpoch;\n const documentState = readStoredDocumentState(currentDoc, documentProjectors);\n const record: StoredDocumentRecord = {\n id: currentRecord?.id ?? localId,\n accessEpoch: nextAccessEpoch,\n accessStateHash: resolveNullableDocumentRuntimeField(\n patch,\n \"accessStateHash\",\n currentRecord?.accessStateHash,\n securityContextChanged,\n ),\n containerId: resolveStoredDocumentContainerId({\n containerId: input.containerId,\n currentRecord,\n patch,\n }),\n contentKeyBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"contentKeyBundle\",\n currentRecord?.contentKeyBundle,\n securityContextChanged,\n ),\n documentId: nextDocumentId,\n effectiveAccessLevel:\n patch.effectiveAccessLevel ?? currentRecord?.effectiveAccessLevel ?? null,\n documentKekTargets: resolveNullableDocumentRuntimeField(\n patch,\n \"documentKekTargets\",\n currentRecord?.documentKekTargets,\n securityContextChanged,\n ),\n documentKind: patch.documentKind ?? documentState.documentKind,\n documentManifestBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"documentManifestBundle\",\n currentRecord?.documentManifestBundle,\n securityContextChanged,\n ),\n lastCommitLsn: resolveNullableDocumentRuntimeField(\n patch,\n \"lastCommitLsn\",\n currentRecord?.lastCommitLsn,\n documentIdChanged,\n ),\n snapshotEndVersion:\n patch.snapshotEndVersion ?? currentRecord?.snapshotEndVersion ?? \"\",\n pendingBaseVersion:\n patch.pendingBaseVersion !== undefined\n ? patch.pendingBaseVersion\n : (currentRecord?.pendingBaseVersion ?? null),\n recoveryGeneration:\n patch.recoveryGeneration ?? currentRecord?.recoveryGeneration ?? 0,\n ...resolveStoredDocumentPullState({\n currentRecord,\n patch,\n securityContextChanged,\n }),\n text: patch.text ?? getTextValue(currentDoc),\n title: patch.title ?? documentState.title,\n };\n return { documentState, record };\n}\n\nasync function saveDocumentClientProjection(input: {\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n documentState: ReturnType<typeof readStoredDocumentState>;\n execSql: ExecSql;\n localId: string;\n record: StoredDocumentRecord;\n updatedAt: string;\n}): Promise<void> {\n const previousKind =\n input.currentRecord?.documentKind ?? DEFAULT_DOCUMENT_KIND;\n const nextKind = input.record.documentKind ?? DEFAULT_DOCUMENT_KIND;\n if (previousKind !== nextKind) {\n await input.documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: previousKind,\n execSql: input.execSql,\n localId: input.localId,\n });\n }\n await input.documentProjectors.saveStoredDocumentClientProjection({\n containerId: input.record.containerId,\n documentId: input.record.documentId,\n documentKind: nextKind,\n execSql: input.execSql,\n localId: input.record.id,\n structuredFields: input.documentState.structuredFields,\n text: input.record.text,\n title: input.record.title ?? input.documentState.title,\n updatedAt: input.updatedAt,\n });\n}\n\nasync function settleSupersededDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n lockedExecSql: ExecSql;\n mutation: Awaited<ReturnType<typeof prepareDocumentMutation>>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { mutation, persistInput } = input;\n if (!mutation.mutationCurrentRecord) return null;\n const authoritativeRecord = persistInput.expectedSyncState\n ? await persistInput.persistence.settleAcceptedPendingUpdates(\n input.lockedExecSql,\n {\n expectedRecord: persistInput.expectedSyncState.record,\n pendingUpdateIds: input.acceptedPendingUpdateIds,\n },\n )\n : mutation.mutationCurrentRecord;\n if (!authoritativeRecord) return null;\n return loadSupersededPersistedDocumentState({\n creationSuperseded: mutation.creationSuperseded,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: authoritativeRecord,\n syncIdentitySuperseded: !mutation.securityContextMatches,\n });\n}\n\nasync function loadConcurrentCreationWinner(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState> {\n const winningRecord = await input.persistInput.persistence.loadDocument(\n input.execSql,\n input.persistInput.localId,\n );\n if (!winningRecord) {\n throw new Error(\"Concurrent document creation lost without a winner\");\n }\n const winner = await loadSupersededPersistedDocumentState({\n creationSuperseded: true,\n execSql: input.execSql,\n localId: input.persistInput.localId,\n persistence: input.persistInput.persistence,\n record: winningRecord,\n syncIdentitySuperseded: true,\n });\n if (!winner) {\n throw new Error(\"Concurrent document creation winner disappeared\");\n }\n return winner;\n}\n\nasync function resolveInitialDocumentCreation(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n savedAt: string | null;\n}): Promise<PersistedDocumentState | null> {\n if (input.savedAt !== null) {\n return { record: input.record, updatedAt: input.savedAt };\n }\n if (\n input.persistInput.canStartDurableMutation &&\n !input.persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n return loadConcurrentCreationWinner({\n execSql: input.execSql,\n persistInput: input.persistInput,\n });\n}\n\nasync function resolveDocumentMutationCommit(input: {\n committed: Awaited<\n ReturnType<DocumentsPersistence[\"commitDocumentMutation\"]>\n >;\n lockedExecSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { committed, persistInput, record } = input;\n if (\n persistInput.canStartDurableMutation &&\n !persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n if (committed.committed) return { record, updatedAt: committed.updatedAt };\n if (!committed.currentRecord) return null;\n if (persistInput.expectedSyncState === undefined) return \"retry\";\n return loadSupersededPersistedDocumentState({\n creationSuperseded: false,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: committed.currentRecord,\n syncIdentitySuperseded: !documentSyncSecurityContextMatches(\n committed.currentRecord,\n persistInput.expectedSyncState.record,\n ),\n });\n}\n\nasync function commitOnePreparedDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n mutation: Exclude<\n Awaited<ReturnType<typeof prepareDocumentMutation>>,\n { pullContinuationSuperseded: true }\n >;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { mutation, persistInput } = input;\n const { documentState, record } = buildStoredDocumentRecord({\n containerId: persistInput.containerId,\n currentDoc: persistInput.currentDoc,\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n localId: persistInput.localId,\n patch: mutation.resolvedPatch,\n });\n if (!mutation.mutationCurrentRecord) {\n const savedAt = await createInitialDocumentRows({\n currentDoc: persistInput.currentDoc,\n execSql: input.lockedExecSql,\n pendingUpdate: persistInput.pendingUpdate,\n persistence: persistInput.persistence,\n record,\n stillCurrent: persistInput.canStartDurableMutation,\n saveClientProjection: (transactionExecSql, updatedAt) =>\n saveDocumentClientProjection({\n currentRecord: null,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n }),\n });\n return resolveInitialDocumentCreation({\n execSql: input.lockedExecSql,\n persistInput,\n record,\n savedAt,\n });\n }\n\n const committed = await persistInput.persistence.commitDocumentMutation(\n input.lockedExecSql,\n {\n acceptedPendingUpdateIds: input.acceptedPendingUpdateIds,\n clearSyncFailure: persistInput.clearSyncFailure,\n ...(persistInput.attachmentRemoval\n ? { attachmentRemoval: persistInput.attachmentRemoval }\n : {}),\n ...(persistInput.attachmentStaging\n ? { attachmentStaging: persistInput.attachmentStaging }\n : {}),\n document: record,\n expectedRecord: mutation.mutationCurrentRecord,\n ...(persistInput.historyCheckpoint\n ? { historyCheckpoint: persistInput.historyCheckpoint }\n : {}),\n ...(persistInput.historyUpdateOrigin\n ? { historyUpdateOrigin: persistInput.historyUpdateOrigin }\n : {}),\n ...(persistInput.historyUpdates\n ? { historyUpdates: persistInput.historyUpdates }\n : {}),\n ...(persistInput.pendingUpdate\n ? { pendingUpdate: persistInput.pendingUpdate }\n : {}),\n settleAcceptedPendingOnConflict:\n persistInput.expectedSyncState !== undefined,\n ...(persistInput.canStartDurableMutation\n ? { stillCurrent: persistInput.canStartDurableMutation }\n : {}),\n },\n async (transactionExecSql, updatedAt) => {\n await saveDocumentClientProjection({\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n });\n await persistInput.commitSideEffect?.(transactionExecSql);\n },\n );\n return resolveDocumentMutationCommit({\n committed,\n lockedExecSql: input.lockedExecSql,\n persistInput,\n record,\n });\n}\n\nexport async function commitPreparedDocumentState(input: {\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n patch: Partial<StoredDocumentRecord>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { lockedExecSql, persistInput } = input;\n if (\n await refuseDeletedDocumentPersist({\n currentRecord: persistInput.currentRecord,\n documentProjectors: input.documentProjectors,\n execSql: lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n })\n ) {\n return null;\n }\n const acceptedPendingUpdateIds = persistInput.acceptedPendingUpdateIds ?? [];\n for (\n let attempt = 0;\n attempt < MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS;\n attempt += 1\n ) {\n const mutation = await prepareDocumentMutation(\n persistInput,\n lockedExecSql,\n input.patch,\n );\n if (mutation.pullContinuationSuperseded) {\n return settleSupersededDocumentMutation({\n acceptedPendingUpdateIds,\n lockedExecSql,\n mutation,\n persistInput,\n });\n }\n const result = await commitOnePreparedDocumentMutation({\n acceptedPendingUpdateIds,\n documentProjectors: input.documentProjectors,\n lockedExecSql,\n mutation,\n persistInput,\n });\n if (result !== \"retry\") return result;\n }\n throw new Error(\n `Document mutation commit gave up after ${MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS} concurrent conflicts`,\n );\n}\n"]}
1
+ {"version":3,"file":"documentMutationCommit.js","sourceRoot":"","sources":["documentMutationCommit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type encodeVersionVector, getTextValue } from \"@tearleads/loro\";\nimport {\n DEFAULT_DOCUMENT_ACCESS_EPOCH,\n DEFAULT_DOCUMENT_KIND,\n} from \"../../data/documents/documentConstants\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n readStoredDocumentState,\n} from \"../../data/documents/documentKinds\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { PendingUpdateFields } from \"../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { createInitialDocumentRows } from \"./create/documentCreationPersistence\";\nimport {\n documentSyncSecurityContextMatches,\n type PrepareDocumentMutationInput,\n type prepareDocumentMutation,\n} from \"./documentMutationPreparation\";\nimport { prepareDocumentMutationUnlessDeleted } from \"./documentPersistGuards\";\n\ntype DocumentContentState = Parameters<typeof encodeVersionVector>[0];\ntype NullableDocumentRuntimeField =\n | \"accessStateHash\"\n | \"lastCommitLsn\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\";\n\nconst MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS = 8;\n\nexport interface PersistedDocumentState {\n creationSuperseded?: true;\n historyRestoreState?:\n | Awaited<ReturnType<DocumentsPersistence[\"loadHistoryRestoreState\"]>>\n | undefined;\n pullContinuationSuperseded?: true;\n record: StoredDocumentRecord;\n syncIdentitySuperseded?: true;\n updatedAt?: string | undefined;\n}\n\nexport interface PersistDocumentStateInput\n extends PrepareDocumentMutationInput {\n acceptedPendingUpdateIds?: readonly string[] | undefined;\n attachmentRemoval?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentRemoval\"]\n | undefined;\n attachmentStaging?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentStaging\"]\n | undefined;\n canStartDurableMutation?: (() => boolean) | undefined;\n clearSyncFailure?: boolean | undefined;\n commitSideEffect?: (transactionExecSql: ExecSql) => Promise<void>;\n containerId?: string | null | undefined;\n documentProjectors: DocumentProjectorRegistryInput;\n execSql: ExecSql;\n patch?: Partial<StoredDocumentRecord> | undefined;\n pendingUpdate?: PendingUpdateFields | undefined;\n}\n\nasync function loadSupersededPersistedDocumentState(input: {\n creationSuperseded: boolean;\n execSql: ExecSql;\n localId: string;\n persistence: DocumentsPersistence;\n record: StoredDocumentRecord;\n syncIdentitySuperseded: boolean;\n}): Promise<PersistedDocumentState | null> {\n const { document, historyRestoreState } =\n await input.persistence.loadDocumentWithHistoryRestoreState(\n input.execSql,\n input.localId,\n );\n if (!document) return null;\n const syncIdentitySuperseded =\n input.syncIdentitySuperseded ||\n !documentSyncSecurityContextMatches(document, input.record);\n return {\n ...(input.creationSuperseded ? { creationSuperseded: true as const } : {}),\n historyRestoreState,\n pullContinuationSuperseded: true,\n record: document,\n ...(syncIdentitySuperseded\n ? { syncIdentitySuperseded: true as const }\n : {}),\n };\n}\n\nfunction resolveNullableDocumentRuntimeField(\n patch: Partial<StoredDocumentRecord>,\n key: NullableDocumentRuntimeField,\n currentValue: string | null | undefined,\n resetWhenUnpatched = false,\n): string | null {\n if (Object.hasOwn(patch, key)) return patch[key] ?? null;\n return resetWhenUnpatched ? null : (currentValue ?? null);\n}\n\nfunction resolveStoredDocumentContainerId(input: {\n containerId?: string | null | undefined;\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n}): string | null {\n if (Object.hasOwn(input.patch, \"containerId\")) {\n return input.patch.containerId ?? null;\n }\n return input.currentRecord?.containerId ?? input.containerId ?? null;\n}\n\nfunction resolveStoredDocumentPullState(input: {\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n securityContextChanged: boolean;\n}): Pick<\n StoredDocumentRecord,\n \"pullContinuation\" | \"pullContinuationRecoveryRequired\"\n> {\n if (Object.hasOwn(input.patch, \"pullContinuation\")) {\n return { pullContinuation: input.patch.pullContinuation ?? null };\n }\n if (input.securityContextChanged) return { pullContinuation: null };\n if (input.currentRecord?.pullContinuationRecoveryRequired) {\n return { pullContinuationRecoveryRequired: true };\n }\n return { pullContinuation: input.currentRecord?.pullContinuation ?? null };\n}\n\nfunction buildStoredDocumentRecord(input: {\n containerId?: string | null | undefined;\n currentDoc: DocumentContentState;\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n localId: string;\n patch: Partial<StoredDocumentRecord>;\n}) {\n const { currentDoc, currentRecord, documentProjectors, localId, patch } =\n input;\n const currentDocumentId = currentRecord?.documentId ?? null;\n const nextDocumentId = patch.documentId ?? currentDocumentId;\n const documentIdChanged = nextDocumentId !== currentDocumentId;\n const currentAccessEpoch =\n currentRecord?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH;\n const nextAccessEpoch = patch.accessEpoch ?? currentAccessEpoch;\n const securityContextChanged =\n documentIdChanged || nextAccessEpoch !== currentAccessEpoch;\n const documentState = readStoredDocumentState(currentDoc, documentProjectors);\n const record: StoredDocumentRecord = {\n id: currentRecord?.id ?? localId,\n accessEpoch: nextAccessEpoch,\n accessStateHash: resolveNullableDocumentRuntimeField(\n patch,\n \"accessStateHash\",\n currentRecord?.accessStateHash,\n securityContextChanged,\n ),\n containerId: resolveStoredDocumentContainerId({\n containerId: input.containerId,\n currentRecord,\n patch,\n }),\n contentKeyBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"contentKeyBundle\",\n currentRecord?.contentKeyBundle,\n securityContextChanged,\n ),\n documentId: nextDocumentId,\n effectiveAccessLevel:\n patch.effectiveAccessLevel ?? currentRecord?.effectiveAccessLevel ?? null,\n documentKekTargets: resolveNullableDocumentRuntimeField(\n patch,\n \"documentKekTargets\",\n currentRecord?.documentKekTargets,\n securityContextChanged,\n ),\n documentKind: patch.documentKind ?? documentState.documentKind,\n documentManifestBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"documentManifestBundle\",\n currentRecord?.documentManifestBundle,\n securityContextChanged,\n ),\n lastCommitLsn: resolveNullableDocumentRuntimeField(\n patch,\n \"lastCommitLsn\",\n currentRecord?.lastCommitLsn,\n documentIdChanged,\n ),\n snapshotEndVersion:\n patch.snapshotEndVersion ?? currentRecord?.snapshotEndVersion ?? \"\",\n pendingBaseVersion:\n patch.pendingBaseVersion !== undefined\n ? patch.pendingBaseVersion\n : (currentRecord?.pendingBaseVersion ?? null),\n recoveryGeneration:\n patch.recoveryGeneration ?? currentRecord?.recoveryGeneration ?? 0,\n ...resolveStoredDocumentPullState({\n currentRecord,\n patch,\n securityContextChanged,\n }),\n text: patch.text ?? getTextValue(currentDoc),\n title: patch.title ?? documentState.title,\n };\n return { documentState, record };\n}\n\nasync function saveDocumentClientProjection(input: {\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n documentState: ReturnType<typeof readStoredDocumentState>;\n execSql: ExecSql;\n localId: string;\n record: StoredDocumentRecord;\n updatedAt: string;\n}): Promise<void> {\n const previousKind =\n input.currentRecord?.documentKind ?? DEFAULT_DOCUMENT_KIND;\n const nextKind = input.record.documentKind ?? DEFAULT_DOCUMENT_KIND;\n if (previousKind !== nextKind) {\n await input.documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: previousKind,\n execSql: input.execSql,\n localId: input.localId,\n });\n }\n await input.documentProjectors.saveStoredDocumentClientProjection({\n containerId: input.record.containerId,\n documentId: input.record.documentId,\n documentKind: nextKind,\n execSql: input.execSql,\n localId: input.record.id,\n structuredFields: input.documentState.structuredFields,\n text: input.record.text,\n title: input.record.title ?? input.documentState.title,\n updatedAt: input.updatedAt,\n });\n}\n\nasync function settleSupersededDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n lockedExecSql: ExecSql;\n mutation: Awaited<ReturnType<typeof prepareDocumentMutation>>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { mutation, persistInput } = input;\n if (!mutation.mutationCurrentRecord) return null;\n const authoritativeRecord = persistInput.expectedSyncState\n ? await persistInput.persistence.settleAcceptedPendingUpdates(\n input.lockedExecSql,\n {\n expectedRecord: persistInput.expectedSyncState.record,\n pendingUpdateIds: input.acceptedPendingUpdateIds,\n },\n )\n : mutation.mutationCurrentRecord;\n if (!authoritativeRecord) return null;\n return loadSupersededPersistedDocumentState({\n creationSuperseded: mutation.creationSuperseded,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: authoritativeRecord,\n syncIdentitySuperseded: !mutation.securityContextMatches,\n });\n}\n\nasync function loadConcurrentCreationWinner(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState> {\n const winningRecord = await input.persistInput.persistence.loadDocument(\n input.execSql,\n input.persistInput.localId,\n );\n if (!winningRecord) {\n throw new Error(\"Concurrent document creation lost without a winner\");\n }\n const winner = await loadSupersededPersistedDocumentState({\n creationSuperseded: true,\n execSql: input.execSql,\n localId: input.persistInput.localId,\n persistence: input.persistInput.persistence,\n record: winningRecord,\n syncIdentitySuperseded: true,\n });\n if (!winner) {\n throw new Error(\"Concurrent document creation winner disappeared\");\n }\n return winner;\n}\n\nasync function resolveInitialDocumentCreation(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n savedAt: string | null;\n}): Promise<PersistedDocumentState | null> {\n if (input.savedAt !== null) {\n return { record: input.record, updatedAt: input.savedAt };\n }\n if (\n input.persistInput.canStartDurableMutation &&\n !input.persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n return loadConcurrentCreationWinner({\n execSql: input.execSql,\n persistInput: input.persistInput,\n });\n}\n\nasync function resolveDocumentMutationCommit(input: {\n committed: Awaited<\n ReturnType<DocumentsPersistence[\"commitDocumentMutation\"]>\n >;\n lockedExecSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { committed, persistInput, record } = input;\n if (\n persistInput.canStartDurableMutation &&\n !persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n if (committed.committed) return { record, updatedAt: committed.updatedAt };\n if (!committed.currentRecord) return null;\n if (persistInput.expectedSyncState === undefined) return \"retry\";\n return loadSupersededPersistedDocumentState({\n creationSuperseded: false,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: committed.currentRecord,\n syncIdentitySuperseded: !documentSyncSecurityContextMatches(\n committed.currentRecord,\n persistInput.expectedSyncState.record,\n ),\n });\n}\n\nasync function commitOnePreparedDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n mutation: Exclude<\n Awaited<ReturnType<typeof prepareDocumentMutation>>,\n { pullContinuationSuperseded: true }\n >;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { mutation, persistInput } = input;\n const { documentState, record } = buildStoredDocumentRecord({\n containerId: persistInput.containerId,\n currentDoc: persistInput.currentDoc,\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n localId: persistInput.localId,\n patch: mutation.resolvedPatch,\n });\n if (!mutation.mutationCurrentRecord) {\n const savedAt = await createInitialDocumentRows({\n currentDoc: persistInput.currentDoc,\n execSql: input.lockedExecSql,\n pendingUpdate: persistInput.pendingUpdate,\n persistence: persistInput.persistence,\n record,\n stillCurrent: persistInput.canStartDurableMutation,\n saveClientProjection: (transactionExecSql, updatedAt) =>\n saveDocumentClientProjection({\n currentRecord: null,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n }),\n });\n return resolveInitialDocumentCreation({\n execSql: input.lockedExecSql,\n persistInput,\n record,\n savedAt,\n });\n }\n\n const committed = await persistInput.persistence.commitDocumentMutation(\n input.lockedExecSql,\n {\n acceptedPendingUpdateIds: input.acceptedPendingUpdateIds,\n clearSyncFailure: persistInput.clearSyncFailure,\n ...(persistInput.attachmentRemoval\n ? { attachmentRemoval: persistInput.attachmentRemoval }\n : {}),\n ...(persistInput.attachmentStaging\n ? { attachmentStaging: persistInput.attachmentStaging }\n : {}),\n document: record,\n expectedRecord: mutation.mutationCurrentRecord,\n ...(persistInput.historyCheckpoint\n ? { historyCheckpoint: persistInput.historyCheckpoint }\n : {}),\n ...(persistInput.historyUpdateOrigin\n ? { historyUpdateOrigin: persistInput.historyUpdateOrigin }\n : {}),\n ...(persistInput.historyUpdates\n ? { historyUpdates: persistInput.historyUpdates }\n : {}),\n ...(persistInput.pendingUpdate\n ? { pendingUpdate: persistInput.pendingUpdate }\n : {}),\n settleAcceptedPendingOnConflict:\n persistInput.expectedSyncState !== undefined,\n ...(persistInput.canStartDurableMutation\n ? { stillCurrent: persistInput.canStartDurableMutation }\n : {}),\n },\n async (transactionExecSql, updatedAt) => {\n await saveDocumentClientProjection({\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n });\n await persistInput.commitSideEffect?.(transactionExecSql);\n },\n );\n return resolveDocumentMutationCommit({\n committed,\n lockedExecSql: input.lockedExecSql,\n persistInput,\n record,\n });\n}\n\nexport async function commitPreparedDocumentState(input: {\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n patch: Partial<StoredDocumentRecord>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { lockedExecSql, persistInput } = input;\n const acceptedPendingUpdateIds = persistInput.acceptedPendingUpdateIds ?? [];\n for (\n let attempt = 0;\n attempt < MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS;\n attempt += 1\n ) {\n const mutation = await prepareDocumentMutationUnlessDeleted({\n documentProjectors: input.documentProjectors,\n guard: attempt === 0,\n lockedExecSql,\n patch: input.patch,\n persistInput,\n });\n if (!mutation) return null;\n if (mutation.pullContinuationSuperseded) {\n return settleSupersededDocumentMutation({\n acceptedPendingUpdateIds,\n lockedExecSql,\n mutation,\n persistInput,\n });\n }\n const result = await commitOnePreparedDocumentMutation({\n acceptedPendingUpdateIds,\n documentProjectors: input.documentProjectors,\n lockedExecSql,\n mutation,\n persistInput,\n });\n if (result !== \"retry\") return result;\n }\n throw new Error(\n `Document mutation commit gave up after ${MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS} concurrent conflicts`,\n );\n}\n"]}
@@ -24,6 +24,7 @@ export interface PrepareDocumentMutationInput {
24
24
  export declare function documentSyncSecurityContextMatches(current: StoredDocumentRecord | null, expected: StoredDocumentRecord): boolean;
25
25
  export declare function prepareDocumentMutation(input: PrepareDocumentMutationInput, execSql: ExecSql, patch: Partial<StoredDocumentRecord>): Promise<{
26
26
  creationSuperseded: boolean;
27
+ durableCurrentRecord: StoredDocumentRecord | null;
27
28
  mutationCurrentRecord: StoredDocumentRecord | null;
28
29
  pullContinuationSuperseded: boolean;
29
30
  resolvedPatch: Partial<StoredDocumentRecord>;
@@ -135,6 +135,7 @@ export async function prepareDocumentMutation(input, execSql, patch) {
135
135
  : await input.persistence.loadDocumentContainer(execSql, input.localId);
136
136
  return {
137
137
  creationSuperseded,
138
+ durableCurrentRecord,
138
139
  mutationCurrentRecord,
139
140
  pullContinuationSuperseded,
140
141
  resolvedPatch: authoritativeContainer === undefined
@@ -1 +1 @@
1
- {"version":3,"file":"documentMutationPreparation.js","sourceRoot":"","sources":["documentMutationPreparation.ts"],"names":[],"mappings":"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","sourcesContent":["import { mergeVersionVectors, satisfiesVersionVector } from \"@tearleads/loro\";\nimport {\n type DocumentSyncPullContinuation,\n documentSyncPullContinuationsEqual,\n} from \"../../data/documents/shared/sync/syncPagination\";\nimport { canWriteEffectiveAccessLevel } from \"../../data/keying/accessLevel\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { mergePersistedDocumentHistory } from \"./historyContent\";\n\nexport interface ExpectedDocumentSyncState {\n pullContinuation: DocumentSyncPullContinuation | null;\n record: StoredDocumentRecord;\n}\n\nexport interface PrepareDocumentMutationInput {\n currentDoc: Parameters<typeof mergePersistedDocumentHistory>[0][\"doc\"];\n currentRecord: StoredDocumentRecord | null;\n expectedSyncState?: ExpectedDocumentSyncState | undefined;\n historyCheckpoint?:\n | {\n coveredTailIds: readonly string[];\n endVersionVector: string;\n pruneCoveredLocalState: boolean;\n snapshot: string;\n }\n | undefined;\n historyUpdateOrigin?: \"local\" | \"remote\" | undefined;\n historyUpdates?: readonly string[] | undefined;\n localId: string;\n persistence: DocumentsPersistence;\n}\n\nfunction sameNullableDocumentValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nexport function documentSyncSecurityContextMatches(\n current: StoredDocumentRecord | null,\n expected: StoredDocumentRecord,\n): boolean {\n return (\n current !== null &&\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.containerId === expected.containerId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableDocumentValue(\n current.accessStateHash,\n expected.accessStateHash,\n ) &&\n (current.effectiveAccessLevel ?? null) ===\n (expected.effectiveAccessLevel ?? null) &&\n sameNullableDocumentValue(\n current.contentKeyBundle,\n expected.contentKeyBundle,\n ) &&\n sameNullableDocumentValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableDocumentValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n )\n );\n}\n\nfunction patchSpecifiesContainer(\n patch: Partial<StoredDocumentRecord>,\n): boolean {\n return Object.hasOwn(patch, \"containerId\");\n}\n\nfunction documentSyncStateDiffers(\n current: StoredDocumentRecord,\n cached: StoredDocumentRecord,\n): boolean {\n return (\n !sameNullableDocumentValue(current.lastCommitLsn, cached.lastCommitLsn) ||\n current.snapshotEndVersion !== cached.snapshotEndVersion ||\n !sameNullableDocumentValue(\n current.pendingBaseVersion,\n cached.pendingBaseVersion,\n ) ||\n !documentSyncPullContinuationsEqual(\n current.pullContinuation,\n cached.pullContinuation,\n ) ||\n Boolean(current.pullContinuationRecoveryRequired) !==\n Boolean(cached.pullContinuationRecoveryRequired)\n );\n}\n\nfunction mergeMutationFrontiers(\n patch: Partial<StoredDocumentRecord>,\n durableRecord: StoredDocumentRecord,\n): Partial<StoredDocumentRecord> {\n const nextPatch = { ...patch };\n if (patch.snapshotEndVersion !== undefined) {\n nextPatch.snapshotEndVersion = mergeVersionVectors([\n durableRecord.snapshotEndVersion,\n patch.snapshotEndVersion,\n ]);\n }\n if (\n patch.pendingBaseVersion !== undefined &&\n patch.pendingBaseVersion !== null &&\n durableRecord.pendingBaseVersion\n ) {\n nextPatch.pendingBaseVersion = mergeVersionVectors([\n durableRecord.pendingBaseVersion,\n patch.pendingBaseVersion,\n ]);\n }\n return nextPatch;\n}\n\nfunction ordinarySaveNeedsHistoryRebase(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n if (\n input.expectedSyncState !== undefined ||\n durableRecord === null ||\n input.currentRecord === null\n ) {\n return false;\n }\n const cachedPendingBase = input.currentRecord.pendingBaseVersion;\n const durableCoversCachedPendingBase =\n !cachedPendingBase ||\n (durableRecord.pendingBaseVersion !== null &&\n durableRecord.pendingBaseVersion !== undefined &&\n satisfiesVersionVector(\n durableRecord.pendingBaseVersion,\n cachedPendingBase,\n ));\n return (\n durableRecord.id === input.currentRecord.id &&\n durableRecord.documentId === input.currentRecord.documentId &&\n satisfiesVersionVector(\n durableRecord.snapshotEndVersion,\n input.currentRecord.snapshotEndVersion,\n ) &&\n durableCoversCachedPendingBase &&\n documentSyncStateDiffers(durableRecord, input.currentRecord)\n );\n}\n\nfunction ordinarySaveIdentityWasReplaced(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n return (\n input.expectedSyncState === undefined &&\n input.currentRecord !== null &&\n durableRecord !== null &&\n (durableRecord.id !== input.currentRecord.id ||\n durableRecord.documentId !== input.currentRecord.documentId)\n );\n}\n\nfunction ordinarySaveWriteAccessWasRevoked(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n return (\n input.expectedSyncState === undefined &&\n input.currentRecord !== null &&\n durableRecord !== null &&\n canWriteEffectiveAccessLevel(input.currentRecord.effectiveAccessLevel) &&\n !canWriteEffectiveAccessLevel(durableRecord.effectiveAccessLevel)\n );\n}\n\nfunction recoveryGenerationWasSuperseded(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n return (\n input.currentRecord !== null &&\n durableRecord !== null &&\n (input.currentRecord.recoveryGeneration ?? 0) !==\n (durableRecord.recoveryGeneration ?? 0)\n );\n}\n\nfunction resolveSyncSettlementState(\n current: StoredDocumentRecord | null,\n expected: ExpectedDocumentSyncState | undefined,\n): { pullContinuationSuperseded: boolean; securityContextMatches: boolean } {\n if (!expected) {\n return { pullContinuationSuperseded: false, securityContextMatches: true };\n }\n const securityContextMatches = documentSyncSecurityContextMatches(\n current,\n expected.record,\n );\n const contentFrontiersMatch =\n sameNullableDocumentValue(\n current?.lastCommitLsn,\n expected.record.lastCommitLsn,\n ) &&\n current?.snapshotEndVersion === expected.record.snapshotEndVersion &&\n sameNullableDocumentValue(\n current?.pendingBaseVersion,\n expected.record.pendingBaseVersion,\n );\n const recoveryStateMatches =\n Boolean(current?.pullContinuationRecoveryRequired) ===\n Boolean(expected.record.pullContinuationRecoveryRequired) &&\n (current?.recoveryGeneration ?? 0) ===\n (expected.record.recoveryGeneration ?? 0);\n return {\n pullContinuationSuperseded:\n !securityContextMatches ||\n !contentFrontiersMatch ||\n !recoveryStateMatches ||\n !documentSyncPullContinuationsEqual(\n current?.pullContinuation,\n expected.pullContinuation,\n ),\n securityContextMatches,\n };\n}\n\nexport async function prepareDocumentMutation(\n input: PrepareDocumentMutationInput,\n execSql: ExecSql,\n patch: Partial<StoredDocumentRecord>,\n) {\n const durableCurrentRecord = await input.persistence.loadDocument(\n execSql,\n input.localId,\n );\n const creationSuperseded =\n input.currentRecord === null && durableCurrentRecord !== null;\n const mutationCurrentRecord = durableCurrentRecord ?? input.currentRecord;\n const identityWasReplaced = ordinarySaveIdentityWasReplaced(\n input,\n durableCurrentRecord,\n );\n const writeAccessWasRevoked = ordinarySaveWriteAccessWasRevoked(\n input,\n durableCurrentRecord,\n );\n const recoveryWasSuperseded = recoveryGenerationWasSuperseded(\n input,\n durableCurrentRecord,\n );\n const { pullContinuationSuperseded, securityContextMatches } =\n creationSuperseded || identityWasReplaced || writeAccessWasRevoked\n ? { pullContinuationSuperseded: true, securityContextMatches: false }\n : recoveryWasSuperseded\n ? { pullContinuationSuperseded: true, securityContextMatches: true }\n : resolveSyncSettlementState(\n mutationCurrentRecord,\n input.expectedSyncState,\n );\n const ordinarySaveNeedsRebase = ordinarySaveNeedsHistoryRebase(\n input,\n durableCurrentRecord,\n );\n\n if (ordinarySaveNeedsRebase && securityContextMatches) {\n await mergePersistedDocumentHistory({\n doc: input.currentDoc,\n execSql,\n localId: input.localId,\n persistence: input.persistence,\n });\n }\n const mutationPatch = pullContinuationSuperseded\n ? {}\n : ordinarySaveNeedsRebase && durableCurrentRecord\n ? mergeMutationFrontiers(patch, durableCurrentRecord)\n : patch;\n const authoritativeContainer = patchSpecifiesContainer(mutationPatch)\n ? undefined\n : await input.persistence.loadDocumentContainer(execSql, input.localId);\n return {\n creationSuperseded,\n mutationCurrentRecord,\n pullContinuationSuperseded,\n resolvedPatch:\n authoritativeContainer === undefined\n ? mutationPatch\n : { ...mutationPatch, containerId: authoritativeContainer.containerId },\n securityContextMatches,\n };\n}\n"]}
1
+ {"version":3,"file":"documentMutationPreparation.js","sourceRoot":"","sources":["documentMutationPreparation.ts"],"names":[],"mappings":"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","sourcesContent":["import { mergeVersionVectors, satisfiesVersionVector } from \"@tearleads/loro\";\nimport {\n type DocumentSyncPullContinuation,\n documentSyncPullContinuationsEqual,\n} from \"../../data/documents/shared/sync/syncPagination\";\nimport { canWriteEffectiveAccessLevel } from \"../../data/keying/accessLevel\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { mergePersistedDocumentHistory } from \"./historyContent\";\n\nexport interface ExpectedDocumentSyncState {\n pullContinuation: DocumentSyncPullContinuation | null;\n record: StoredDocumentRecord;\n}\n\nexport interface PrepareDocumentMutationInput {\n currentDoc: Parameters<typeof mergePersistedDocumentHistory>[0][\"doc\"];\n currentRecord: StoredDocumentRecord | null;\n expectedSyncState?: ExpectedDocumentSyncState | undefined;\n historyCheckpoint?:\n | {\n coveredTailIds: readonly string[];\n endVersionVector: string;\n pruneCoveredLocalState: boolean;\n snapshot: string;\n }\n | undefined;\n historyUpdateOrigin?: \"local\" | \"remote\" | undefined;\n historyUpdates?: readonly string[] | undefined;\n localId: string;\n persistence: DocumentsPersistence;\n}\n\nfunction sameNullableDocumentValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nexport function documentSyncSecurityContextMatches(\n current: StoredDocumentRecord | null,\n expected: StoredDocumentRecord,\n): boolean {\n return (\n current !== null &&\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.containerId === expected.containerId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableDocumentValue(\n current.accessStateHash,\n expected.accessStateHash,\n ) &&\n (current.effectiveAccessLevel ?? null) ===\n (expected.effectiveAccessLevel ?? null) &&\n sameNullableDocumentValue(\n current.contentKeyBundle,\n expected.contentKeyBundle,\n ) &&\n sameNullableDocumentValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableDocumentValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n )\n );\n}\n\nfunction patchSpecifiesContainer(\n patch: Partial<StoredDocumentRecord>,\n): boolean {\n return Object.hasOwn(patch, \"containerId\");\n}\n\nfunction documentSyncStateDiffers(\n current: StoredDocumentRecord,\n cached: StoredDocumentRecord,\n): boolean {\n return (\n !sameNullableDocumentValue(current.lastCommitLsn, cached.lastCommitLsn) ||\n current.snapshotEndVersion !== cached.snapshotEndVersion ||\n !sameNullableDocumentValue(\n current.pendingBaseVersion,\n cached.pendingBaseVersion,\n ) ||\n !documentSyncPullContinuationsEqual(\n current.pullContinuation,\n cached.pullContinuation,\n ) ||\n Boolean(current.pullContinuationRecoveryRequired) !==\n Boolean(cached.pullContinuationRecoveryRequired)\n );\n}\n\nfunction mergeMutationFrontiers(\n patch: Partial<StoredDocumentRecord>,\n durableRecord: StoredDocumentRecord,\n): Partial<StoredDocumentRecord> {\n const nextPatch = { ...patch };\n if (patch.snapshotEndVersion !== undefined) {\n nextPatch.snapshotEndVersion = mergeVersionVectors([\n durableRecord.snapshotEndVersion,\n patch.snapshotEndVersion,\n ]);\n }\n if (\n patch.pendingBaseVersion !== undefined &&\n patch.pendingBaseVersion !== null &&\n durableRecord.pendingBaseVersion\n ) {\n nextPatch.pendingBaseVersion = mergeVersionVectors([\n durableRecord.pendingBaseVersion,\n patch.pendingBaseVersion,\n ]);\n }\n return nextPatch;\n}\n\nfunction ordinarySaveNeedsHistoryRebase(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n if (\n input.expectedSyncState !== undefined ||\n durableRecord === null ||\n input.currentRecord === null\n ) {\n return false;\n }\n const cachedPendingBase = input.currentRecord.pendingBaseVersion;\n const durableCoversCachedPendingBase =\n !cachedPendingBase ||\n (durableRecord.pendingBaseVersion !== null &&\n durableRecord.pendingBaseVersion !== undefined &&\n satisfiesVersionVector(\n durableRecord.pendingBaseVersion,\n cachedPendingBase,\n ));\n return (\n durableRecord.id === input.currentRecord.id &&\n durableRecord.documentId === input.currentRecord.documentId &&\n satisfiesVersionVector(\n durableRecord.snapshotEndVersion,\n input.currentRecord.snapshotEndVersion,\n ) &&\n durableCoversCachedPendingBase &&\n documentSyncStateDiffers(durableRecord, input.currentRecord)\n );\n}\n\nfunction ordinarySaveIdentityWasReplaced(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n return (\n input.expectedSyncState === undefined &&\n input.currentRecord !== null &&\n durableRecord !== null &&\n (durableRecord.id !== input.currentRecord.id ||\n durableRecord.documentId !== input.currentRecord.documentId)\n );\n}\n\nfunction ordinarySaveWriteAccessWasRevoked(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n return (\n input.expectedSyncState === undefined &&\n input.currentRecord !== null &&\n durableRecord !== null &&\n canWriteEffectiveAccessLevel(input.currentRecord.effectiveAccessLevel) &&\n !canWriteEffectiveAccessLevel(durableRecord.effectiveAccessLevel)\n );\n}\n\nfunction recoveryGenerationWasSuperseded(\n input: PrepareDocumentMutationInput,\n durableRecord: StoredDocumentRecord | null,\n): boolean {\n return (\n input.currentRecord !== null &&\n durableRecord !== null &&\n (input.currentRecord.recoveryGeneration ?? 0) !==\n (durableRecord.recoveryGeneration ?? 0)\n );\n}\n\nfunction resolveSyncSettlementState(\n current: StoredDocumentRecord | null,\n expected: ExpectedDocumentSyncState | undefined,\n): { pullContinuationSuperseded: boolean; securityContextMatches: boolean } {\n if (!expected) {\n return { pullContinuationSuperseded: false, securityContextMatches: true };\n }\n const securityContextMatches = documentSyncSecurityContextMatches(\n current,\n expected.record,\n );\n const contentFrontiersMatch =\n sameNullableDocumentValue(\n current?.lastCommitLsn,\n expected.record.lastCommitLsn,\n ) &&\n current?.snapshotEndVersion === expected.record.snapshotEndVersion &&\n sameNullableDocumentValue(\n current?.pendingBaseVersion,\n expected.record.pendingBaseVersion,\n );\n const recoveryStateMatches =\n Boolean(current?.pullContinuationRecoveryRequired) ===\n Boolean(expected.record.pullContinuationRecoveryRequired) &&\n (current?.recoveryGeneration ?? 0) ===\n (expected.record.recoveryGeneration ?? 0);\n return {\n pullContinuationSuperseded:\n !securityContextMatches ||\n !contentFrontiersMatch ||\n !recoveryStateMatches ||\n !documentSyncPullContinuationsEqual(\n current?.pullContinuation,\n expected.pullContinuation,\n ),\n securityContextMatches,\n };\n}\n\nexport async function prepareDocumentMutation(\n input: PrepareDocumentMutationInput,\n execSql: ExecSql,\n patch: Partial<StoredDocumentRecord>,\n) {\n const durableCurrentRecord = await input.persistence.loadDocument(\n execSql,\n input.localId,\n );\n const creationSuperseded =\n input.currentRecord === null && durableCurrentRecord !== null;\n const mutationCurrentRecord = durableCurrentRecord ?? input.currentRecord;\n const identityWasReplaced = ordinarySaveIdentityWasReplaced(\n input,\n durableCurrentRecord,\n );\n const writeAccessWasRevoked = ordinarySaveWriteAccessWasRevoked(\n input,\n durableCurrentRecord,\n );\n const recoveryWasSuperseded = recoveryGenerationWasSuperseded(\n input,\n durableCurrentRecord,\n );\n const { pullContinuationSuperseded, securityContextMatches } =\n creationSuperseded || identityWasReplaced || writeAccessWasRevoked\n ? { pullContinuationSuperseded: true, securityContextMatches: false }\n : recoveryWasSuperseded\n ? { pullContinuationSuperseded: true, securityContextMatches: true }\n : resolveSyncSettlementState(\n mutationCurrentRecord,\n input.expectedSyncState,\n );\n const ordinarySaveNeedsRebase = ordinarySaveNeedsHistoryRebase(\n input,\n durableCurrentRecord,\n );\n\n if (ordinarySaveNeedsRebase && securityContextMatches) {\n await mergePersistedDocumentHistory({\n doc: input.currentDoc,\n execSql,\n localId: input.localId,\n persistence: input.persistence,\n });\n }\n const mutationPatch = pullContinuationSuperseded\n ? {}\n : ordinarySaveNeedsRebase && durableCurrentRecord\n ? mergeMutationFrontiers(patch, durableCurrentRecord)\n : patch;\n const authoritativeContainer = patchSpecifiesContainer(mutationPatch)\n ? undefined\n : await input.persistence.loadDocumentContainer(execSql, input.localId);\n return {\n creationSuperseded,\n durableCurrentRecord,\n mutationCurrentRecord,\n pullContinuationSuperseded,\n resolvedPatch:\n authoritativeContainer === undefined\n ? mutationPatch\n : { ...mutationPatch, containerId: authoritativeContainer.containerId },\n securityContextMatches,\n };\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_DOCUMENT_KIND } from "../../data/documents/documentConstants.js";
2
+ import { prepareDocumentMutation, } from "./documentMutationPreparation.js";
2
3
  /** Refuse a queued update after another subsystem deleted its canonical row. */
3
4
  export async function refuseDeletedDocumentPersist(input) {
4
5
  const { currentRecord } = input;
@@ -12,4 +13,27 @@ export async function refuseDeletedDocumentPersist(input) {
12
13
  });
13
14
  });
14
15
  }
16
+ /**
17
+ * The preparation read doubles as the first look for a deleted row: only when
18
+ * it finds none does the guard open its own transaction, which reads again
19
+ * under the write lock before it refuses. A row it then finds (or an alias it
20
+ * must keep) is prepared afresh, as before the guard moved.
21
+ */
22
+ export async function prepareDocumentMutationUnlessDeleted(input) {
23
+ const { lockedExecSql, persistInput } = input;
24
+ const prepare = () => prepareDocumentMutation(persistInput, lockedExecSql, input.patch);
25
+ const mutation = await prepare();
26
+ if (!input.guard ||
27
+ persistInput.currentRecord === null ||
28
+ mutation.durableCurrentRecord !== null)
29
+ return mutation;
30
+ const refused = await refuseDeletedDocumentPersist({
31
+ currentRecord: persistInput.currentRecord,
32
+ documentProjectors: input.documentProjectors,
33
+ execSql: lockedExecSql,
34
+ localId: persistInput.localId,
35
+ persistence: persistInput.persistence,
36
+ });
37
+ return refused ? null : prepare();
38
+ }
15
39
  //# sourceMappingURL=documentPersistGuards.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"documentPersistGuards.js","sourceRoot":"","sources":["documentPersistGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAQ/E,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,KAMlD;IACC,MAAM,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAChC,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IACjC,OAAO,KAAK,CAAC,WAAW,CAAC,8BAA8B,CACrD,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,OAAO,EACb,aAAa,CAAC,UAAU,EACxB,KAAK,EAAE,kBAAkB,EAAE,EAAE;QAC3B,MAAM,KAAK,CAAC,kBAAkB,CAAC,oCAAoC,CAAC;YAClE,YAAY,EAAE,aAAa,CAAC,YAAY,IAAI,qBAAqB;YACjE,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../../data/documents/documentConstants\";\nimport type { DocumentProjectorRegistry } from \"../../data/documents/documentKinds\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\n\n/** Refuse a queued update after another subsystem deleted its canonical row. */\nexport async function refuseDeletedDocumentPersist(input: {\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n execSql: ExecSql;\n localId: string;\n persistence: DocumentsPersistence;\n}): Promise<boolean> {\n const { currentRecord } = input;\n if (!currentRecord) return false;\n return input.persistence.deleteDocumentSideRowsIfAbsent(\n input.execSql,\n input.localId,\n currentRecord.documentId,\n async (transactionExecSql) => {\n await input.documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: currentRecord.documentKind ?? DEFAULT_DOCUMENT_KIND,\n execSql: transactionExecSql,\n localId: input.localId,\n });\n },\n );\n}\n"]}
1
+ {"version":3,"file":"documentPersistGuards.js","sourceRoot":"","sources":["documentPersistGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAO/E,OAAO,EAEL,uBAAuB,GACxB,MAAM,+BAA+B,CAAC;AAEvC,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,KAMlD;IACC,MAAM,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAChC,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IACjC,OAAO,KAAK,CAAC,WAAW,CAAC,8BAA8B,CACrD,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,OAAO,EACb,aAAa,CAAC,UAAU,EACxB,KAAK,EAAE,kBAAkB,EAAE,EAAE;QAC3B,MAAM,KAAK,CAAC,kBAAkB,CAAC,oCAAoC,CAAC;YAClE,YAAY,EAAE,aAAa,CAAC,YAAY,IAAI,qBAAqB;YACjE,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oCAAoC,CAAC,KAM1D;IACC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;IAC9C,MAAM,OAAO,GAAG,GAAG,EAAE,CACnB,uBAAuB,CAAC,YAAY,EAAE,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,MAAM,OAAO,EAAE,CAAC;IACjC,IACE,CAAC,KAAK,CAAC,KAAK;QACZ,YAAY,CAAC,aAAa,KAAK,IAAI;QACnC,QAAQ,CAAC,oBAAoB,KAAK,IAAI;QAEtC,OAAO,QAAQ,CAAC;IAClB,MAAM,OAAO,GAAG,MAAM,4BAA4B,CAAC;QACjD,aAAa,EAAE,YAAY,CAAC,aAAa;QACzC,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE,YAAY,CAAC,OAAO;QAC7B,WAAW,EAAE,YAAY,CAAC,WAAW;KACtC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AACpC,CAAC","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../../data/documents/documentConstants\";\nimport type { DocumentProjectorRegistry } from \"../../data/documents/documentKinds\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport {\n type PrepareDocumentMutationInput,\n prepareDocumentMutation,\n} from \"./documentMutationPreparation\";\n\n/** Refuse a queued update after another subsystem deleted its canonical row. */\nexport async function refuseDeletedDocumentPersist(input: {\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n execSql: ExecSql;\n localId: string;\n persistence: DocumentsPersistence;\n}): Promise<boolean> {\n const { currentRecord } = input;\n if (!currentRecord) return false;\n return input.persistence.deleteDocumentSideRowsIfAbsent(\n input.execSql,\n input.localId,\n currentRecord.documentId,\n async (transactionExecSql) => {\n await input.documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: currentRecord.documentKind ?? DEFAULT_DOCUMENT_KIND,\n execSql: transactionExecSql,\n localId: input.localId,\n });\n },\n );\n}\n\n/**\n * The preparation read doubles as the first look for a deleted row: only when\n * it finds none does the guard open its own transaction, which reads again\n * under the write lock before it refuses. A row it then finds (or an alias it\n * must keep) is prepared afresh, as before the guard moved.\n */\nexport async function prepareDocumentMutationUnlessDeleted(input: {\n documentProjectors: DocumentProjectorRegistry;\n guard: boolean;\n lockedExecSql: ExecSql;\n patch: Partial<StoredDocumentRecord>;\n persistInput: PrepareDocumentMutationInput & { localId: string };\n}) {\n const { lockedExecSql, persistInput } = input;\n const prepare = () =>\n prepareDocumentMutation(persistInput, lockedExecSql, input.patch);\n const mutation = await prepare();\n if (\n !input.guard ||\n persistInput.currentRecord === null ||\n mutation.durableCurrentRecord !== null\n )\n return mutation;\n const refused = await refuseDeletedDocumentPersist({\n currentRecord: persistInput.currentRecord,\n documentProjectors: input.documentProjectors,\n execSql: lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n });\n return refused ? null : prepare();\n}\n"]}