@tearleads/client-sdk 0.1.30 → 0.1.32

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 (37) hide show
  1. package/index.d.ts +1 -1
  2. package/index.js.map +1 -1
  3. package/internal/api-client/operationTransportFactory.js +1 -0
  4. package/internal/api-client/operationTransportFactory.js.map +1 -1
  5. package/internal/api-client/routes/blobs/get.d.ts +6 -1
  6. package/internal/api-client/routes/blobs/get.js +98 -2
  7. package/internal/api-client/routes/blobs/get.js.map +1 -1
  8. package/internal/validators/operation/blobDownloads.d.ts +163 -0
  9. package/internal/validators/operation/blobDownloads.js +43 -0
  10. package/internal/validators/operation/blobDownloads.js.map +1 -0
  11. package/internal/validators/operation/index.d.ts +1 -0
  12. package/internal/validators/operation/index.js +1 -0
  13. package/internal/validators/operation/index.js.map +1 -1
  14. package/internal/validators/operation/registry.d.ts +2 -0
  15. package/internal/validators/operation/registry.js +2 -0
  16. package/internal/validators/operation/registry.js.map +1 -1
  17. package/package.json +1 -1
  18. package/stores/container-contents/state.js +1 -0
  19. package/stores/container-contents/state.js.map +1 -1
  20. package/stores/container-contents/types.d.ts +2 -0
  21. package/stores/container-contents/types.js.map +1 -1
  22. package/stores/container-contents/utils.js +10 -0
  23. package/stores/container-contents/utils.js.map +1 -1
  24. package/stores/documents/documentStore/syncFinalize.js +7 -3
  25. package/stores/documents/documentStore/syncFinalize.js.map +1 -1
  26. package/workflows/container-contents/documentQueries/hydrationSql.js +16 -0
  27. package/workflows/container-contents/documentQueries/hydrationSql.js.map +1 -0
  28. package/workflows/container-contents/documentQueries/sql.js +16 -7
  29. package/workflows/container-contents/documentQueries/sql.js.map +1 -1
  30. package/workflows/container-contents/documentQueries.d.ts +6 -1
  31. package/workflows/container-contents/documentQueries.js +15 -8
  32. package/workflows/container-contents/documentQueries.js.map +1 -1
  33. package/workflows/container-contents/index.d.ts +1 -0
  34. package/workflows/container-contents/index.js.map +1 -1
  35. package/workflows/container-contents/pendingDownloads.d.ts +12 -0
  36. package/workflows/container-contents/pendingDownloads.js +45 -0
  37. package/workflows/container-contents/pendingDownloads.js.map +1 -0
@@ -2,6 +2,7 @@ import { bindBlobAttachmentOperation, detachBlobAttachmentOperation, listDocumen
2
2
  import { challengeOperation, destroySessionOperation, listSessionsOperation, logoutOperation, registerOperation, userIdentityOperation, verifyOperation, webSocketTicketOperation } from "./auth.js";
3
3
  import { receiveRevenueCatWebhookOperation, receiveStripeWebhookOperation } from "./billingWebhooks.js";
4
4
  import { getBlobBytesOperation, uploadMultipartBlobPartBytesOperation } from "./blobBytes.js";
5
+ import { getBlobDownloadOperation } from "./blobDownloads.js";
5
6
  import { createContainerOperation, createContainerWithMetadataDocumentOperation, deleteContainerOperation, moveContainerOperation, reciteContainerOperation, rekeyContainerOperation, revokeContainerOperation, shareContainerOperation } from "./containerMutations.js";
6
7
  import { getContainerKekLogOperation, listContainerDocumentsOperation, listContainerParentLanesOperation } from "./containerReads.js";
7
8
  import { getContainerReplacementAuthorizationsOperation } from "./containerReplacement.js";
@@ -31,6 +32,7 @@ export declare const protocolOperations: readonly [
31
32
  typeof verifyOperation,
32
33
  typeof webSocketTicketOperation,
33
34
  typeof getBlobBytesOperation,
35
+ typeof getBlobDownloadOperation,
34
36
  typeof receiveRevenueCatWebhookOperation,
35
37
  typeof receiveStripeWebhookOperation,
36
38
  typeof bindBlobAttachmentOperation,
@@ -2,6 +2,7 @@ import { bindBlobAttachmentOperation, detachBlobAttachmentOperation, listDocumen
2
2
  import { challengeOperation, destroySessionOperation, listSessionsOperation, logoutOperation, registerOperation, userIdentityOperation, verifyOperation, webSocketTicketOperation, } from "./auth.js";
3
3
  import { receiveRevenueCatWebhookOperation, receiveStripeWebhookOperation, } from "./billingWebhooks.js";
4
4
  import { getBlobBytesOperation, uploadMultipartBlobPartBytesOperation, } from "./blobBytes.js";
5
+ import { getBlobDownloadOperation } from "./blobDownloads.js";
5
6
  import { createContainerOperation, createContainerWithMetadataDocumentOperation, deleteContainerOperation, moveContainerOperation, reciteContainerOperation, rekeyContainerOperation, revokeContainerOperation, shareContainerOperation, } from "./containerMutations.js";
6
7
  import { getContainerKekLogOperation, listContainerDocumentsOperation, listContainerParentLanesOperation, } from "./containerReads.js";
7
8
  import { getContainerReplacementAuthorizationsOperation } from "./containerReplacement.js";
@@ -33,6 +34,7 @@ export const protocolOperations = [
33
34
  verifyOperation,
34
35
  webSocketTicketOperation,
35
36
  getBlobBytesOperation,
37
+ getBlobDownloadOperation,
36
38
  receiveRevenueCatWebhookOperation,
37
39
  receiveStripeWebhookOperation,
38
40
  bindBlobAttachmentOperation,
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["registry.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,EAC7B,gCAAgC,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,wBAAwB,GACzB,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,iCAAiC,EACjC,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,qBAAqB,EACrB,qCAAqC,GACtC,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,wBAAwB,EACxB,4CAA4C,EAC5C,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,2BAA2B,EAC3B,+BAA+B,EAC/B,iCAAiC,GAClC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,8CAA8C,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EACL,+BAA+B,EAC/B,sCAAsC,GACvC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,uBAAuB,EACvB,8BAA8B,EAC9B,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EACL,mCAAmC,EACnC,8BAA8B,EAC9B,mCAAmC,GACpC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,4CAA4C,EAC5C,sCAAsC,EACtC,4CAA4C,EAC5C,+BAA+B,EAC/B,iDAAiD,EACjD,+BAA+B,GAChC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,qCAAqC,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EACL,gCAAgC,EAChC,2BAA2B,EAC3B,gCAAgC,EAChC,iCAAiC,EACjC,iCAAiC,EACjC,qCAAqC,EACrC,kCAAkC,EAClC,sCAAsC,GACvC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sCAAsC,EACtC,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mCAAmC,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,sCAAsC,GACvC,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,qCAAqC,EACrC,4BAA4B,EAC5B,gCAAgC,EAChC,uCAAuC,EACvC,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,oCAAoC,EACpC,2BAA2B,EAC3B,iCAAiC,GAClC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,qCAAqC,EACrC,oCAAoC,GACrC,MAAM,qBAAqB,CAAC;AAE7B,6EAA6E;AAC7E,mFAAmF;AACnF,MAAM,CAAC,MAAM,kBAAkB,GA0E3B;IACF,8CAA8C;IAC9C,kBAAkB;IAClB,kBAAkB;IAClB,uBAAuB;IACvB,qBAAqB;IACrB,eAAe;IACf,iBAAiB;IACjB,qBAAqB;IACrB,eAAe;IACf,wBAAwB;IACxB,qBAAqB;IACrB,iCAAiC;IACjC,6BAA6B;IAC7B,2BAA2B;IAC3B,6BAA6B;IAC7B,mCAAmC;IACnC,8BAA8B;IAC9B,mCAAmC;IACnC,qCAAqC;IACrC,gCAAgC;IAChC,+BAA+B;IAC/B,sCAAsC;IACtC,uBAAuB;IACvB,8BAA8B;IAC9B,qBAAqB;IACrB,sBAAsB;IACtB,uBAAuB;IACvB,2BAA2B;IAC3B,+BAA+B;IAC/B,iCAAiC;IACjC,wBAAwB;IACxB,4CAA4C;IAC5C,wBAAwB;IACxB,sBAAsB;IACtB,wBAAwB;IACxB,uBAAuB;IACvB,wBAAwB;IACxB,uBAAuB;IACvB,qCAAqC;IACrC,oCAAoC;IACpC,2BAA2B;IAC3B,+BAA+B;IAC/B,sCAAsC;IACtC,4CAA4C;IAC5C,iDAAiD;IACjD,4CAA4C;IAC5C,+BAA+B;IAC/B,iCAAiC;IACjC,6BAA6B;IAC7B,oCAAoC;IACpC,2BAA2B;IAC3B,iCAAiC;IACjC,iCAAiC;IACjC,iCAAiC;IACjC,qCAAqC;IACrC,gCAAgC;IAChC,gCAAgC;IAChC,qCAAqC;IACrC,kCAAkC;IAClC,sCAAsC;IACtC,2BAA2B;IAC3B,mCAAmC;IACnC,sCAAsC;IACtC,2BAA2B;IAC3B,2BAA2B;IAC3B,8BAA8B;IAC9B,qCAAqC;IACrC,gCAAgC;IAChC,4BAA4B;IAC5B,uCAAuC;IACvC,wBAAwB;IACxB,sCAAsC;IACtC,qBAAqB;CACtB,CAAC","sourcesContent":["import {\n bindBlobAttachmentOperation,\n detachBlobAttachmentOperation,\n listDocumentAttachmentsOperation,\n} from \"./attachments\";\nimport {\n challengeOperation,\n destroySessionOperation,\n listSessionsOperation,\n logoutOperation,\n registerOperation,\n userIdentityOperation,\n verifyOperation,\n webSocketTicketOperation,\n} from \"./auth\";\nimport {\n receiveRevenueCatWebhookOperation,\n receiveStripeWebhookOperation,\n} from \"./billingWebhooks\";\nimport {\n getBlobBytesOperation,\n uploadMultipartBlobPartBytesOperation,\n} from \"./blobBytes\";\nimport {\n createContainerOperation,\n createContainerWithMetadataDocumentOperation,\n deleteContainerOperation,\n moveContainerOperation,\n reciteContainerOperation,\n rekeyContainerOperation,\n revokeContainerOperation,\n shareContainerOperation,\n} from \"./containerMutations\";\nimport {\n getContainerKekLogOperation,\n listContainerDocumentsOperation,\n listContainerParentLanesOperation,\n} from \"./containerReads\";\nimport { getContainerReplacementAuthorizationsOperation } from \"./containerReplacement\";\nimport {\n getDocumentAttributionOperation,\n listDocumentAttributionRangesOperation,\n} from \"./documentAttribution\";\nimport {\n createDocumentOperation,\n getDocumentPurgeProofOperation,\n linkDocumentOperation,\n purgeDocumentOperation,\n unlinkDocumentOperation,\n} from \"./documentMutations\";\nimport { documentSyncOperation } from \"./documentSync\";\nimport { getHealthOperation } from \"./health\";\nimport {\n completeMultipartBlobStageOperation,\n getMultipartBlobStageOperation,\n initiateMultipartBlobStageOperation,\n} from \"./multipartBlobs\";\nimport {\n claimNativeOrganizationSubscriptionOperation,\n getOrganizationBillingHistoryOperation,\n getOrganizationBillingManagementUrlOperation,\n getOrganizationBillingOperation,\n getOrganizationNativePurchaseEligibilityOperation,\n startOrganizationTrialOperation,\n} from \"./organizationBilling\";\nimport { getOrganizationPolicyHistoryOperation } from \"./organizationPolicyHistory\";\nimport {\n createOrganizationGroupOperation,\n createOrganizationOperation,\n deleteOrganizationGroupOperation,\n getOrganizationDataUsageOperation,\n getOrganizationReadModelOperation,\n listOrganizationGroupMembersOperation,\n updateOrganizationProfileOperation,\n updateOrganizationRosterEntryOperation,\n} from \"./organizations\";\nimport {\n commitOrganizationGroupPolicyOperation,\n getPrincipalPolicyOperation,\n putPrincipalPolicyOperation,\n} from \"./principals\";\nimport { getProjectionPolicyHistoryOperation } from \"./projectionPolicyHistory\";\nimport {\n getRootIdentityOperation,\n listRootIdentitiesOperation,\n listRootIdentityOrganizationsOperation,\n} from \"./root\";\nimport {\n getRootOrganizationDataUsageOperation,\n getRootOrganizationOperation,\n listRootDataUsageReportOperation,\n listRootOrganizationIdentitiesOperation,\n listRootOrganizationsOperation,\n} from \"./rootOrganizations\";\nimport {\n cancelStripeSubscriptionOperation,\n createStripeCheckoutOperation,\n createStripeCheckoutSessionOperation,\n createStripePortalOperation,\n getStripeCheckoutOptionsOperation,\n} from \"./stripeCheckout\";\nimport {\n getContainerWriterProjectionOperation,\n getDocumentWriterProjectionOperation,\n} from \"./writerProjections\";\n\n// Name each imported operation type instead of expanding every Zod schema in\n// the emitted declaration; the exact readonly tuple and runtime order stay intact.\nexport const protocolOperations: readonly [\n typeof getContainerReplacementAuthorizationsOperation,\n typeof getHealthOperation,\n typeof challengeOperation,\n typeof destroySessionOperation,\n typeof listSessionsOperation,\n typeof logoutOperation,\n typeof registerOperation,\n typeof userIdentityOperation,\n typeof verifyOperation,\n typeof webSocketTicketOperation,\n typeof getBlobBytesOperation,\n typeof receiveRevenueCatWebhookOperation,\n typeof receiveStripeWebhookOperation,\n typeof bindBlobAttachmentOperation,\n typeof detachBlobAttachmentOperation,\n typeof initiateMultipartBlobStageOperation,\n typeof getMultipartBlobStageOperation,\n typeof completeMultipartBlobStageOperation,\n typeof uploadMultipartBlobPartBytesOperation,\n typeof listDocumentAttachmentsOperation,\n typeof getDocumentAttributionOperation,\n typeof listDocumentAttributionRangesOperation,\n typeof createDocumentOperation,\n typeof getDocumentPurgeProofOperation,\n typeof linkDocumentOperation,\n typeof purgeDocumentOperation,\n typeof unlinkDocumentOperation,\n typeof getContainerKekLogOperation,\n typeof listContainerDocumentsOperation,\n typeof listContainerParentLanesOperation,\n typeof createContainerOperation,\n typeof createContainerWithMetadataDocumentOperation,\n typeof deleteContainerOperation,\n typeof moveContainerOperation,\n typeof reciteContainerOperation,\n typeof rekeyContainerOperation,\n typeof revokeContainerOperation,\n typeof shareContainerOperation,\n typeof getContainerWriterProjectionOperation,\n typeof getDocumentWriterProjectionOperation,\n typeof createOrganizationOperation,\n typeof getOrganizationBillingOperation,\n typeof getOrganizationBillingHistoryOperation,\n typeof getOrganizationBillingManagementUrlOperation,\n typeof getOrganizationNativePurchaseEligibilityOperation,\n typeof claimNativeOrganizationSubscriptionOperation,\n typeof startOrganizationTrialOperation,\n typeof getStripeCheckoutOptionsOperation,\n typeof createStripeCheckoutOperation,\n typeof createStripeCheckoutSessionOperation,\n typeof createStripePortalOperation,\n typeof cancelStripeSubscriptionOperation,\n typeof getOrganizationDataUsageOperation,\n typeof getOrganizationReadModelOperation,\n typeof getOrganizationPolicyHistoryOperation,\n typeof createOrganizationGroupOperation,\n typeof deleteOrganizationGroupOperation,\n typeof listOrganizationGroupMembersOperation,\n typeof updateOrganizationProfileOperation,\n typeof updateOrganizationRosterEntryOperation,\n typeof getPrincipalPolicyOperation,\n typeof getProjectionPolicyHistoryOperation,\n typeof commitOrganizationGroupPolicyOperation,\n typeof putPrincipalPolicyOperation,\n typeof listRootIdentitiesOperation,\n typeof listRootOrganizationsOperation,\n typeof getRootOrganizationDataUsageOperation,\n typeof listRootDataUsageReportOperation,\n typeof getRootOrganizationOperation,\n typeof listRootOrganizationIdentitiesOperation,\n typeof getRootIdentityOperation,\n typeof listRootIdentityOrganizationsOperation,\n typeof documentSyncOperation,\n] = [\n getContainerReplacementAuthorizationsOperation,\n getHealthOperation,\n challengeOperation,\n destroySessionOperation,\n listSessionsOperation,\n logoutOperation,\n registerOperation,\n userIdentityOperation,\n verifyOperation,\n webSocketTicketOperation,\n getBlobBytesOperation,\n receiveRevenueCatWebhookOperation,\n receiveStripeWebhookOperation,\n bindBlobAttachmentOperation,\n detachBlobAttachmentOperation,\n initiateMultipartBlobStageOperation,\n getMultipartBlobStageOperation,\n completeMultipartBlobStageOperation,\n uploadMultipartBlobPartBytesOperation,\n listDocumentAttachmentsOperation,\n getDocumentAttributionOperation,\n listDocumentAttributionRangesOperation,\n createDocumentOperation,\n getDocumentPurgeProofOperation,\n linkDocumentOperation,\n purgeDocumentOperation,\n unlinkDocumentOperation,\n getContainerKekLogOperation,\n listContainerDocumentsOperation,\n listContainerParentLanesOperation,\n createContainerOperation,\n createContainerWithMetadataDocumentOperation,\n deleteContainerOperation,\n moveContainerOperation,\n reciteContainerOperation,\n rekeyContainerOperation,\n revokeContainerOperation,\n shareContainerOperation,\n getContainerWriterProjectionOperation,\n getDocumentWriterProjectionOperation,\n createOrganizationOperation,\n getOrganizationBillingOperation,\n getOrganizationBillingHistoryOperation,\n getOrganizationBillingManagementUrlOperation,\n getOrganizationNativePurchaseEligibilityOperation,\n claimNativeOrganizationSubscriptionOperation,\n startOrganizationTrialOperation,\n getStripeCheckoutOptionsOperation,\n createStripeCheckoutOperation,\n createStripeCheckoutSessionOperation,\n createStripePortalOperation,\n cancelStripeSubscriptionOperation,\n getOrganizationDataUsageOperation,\n getOrganizationReadModelOperation,\n getOrganizationPolicyHistoryOperation,\n createOrganizationGroupOperation,\n deleteOrganizationGroupOperation,\n listOrganizationGroupMembersOperation,\n updateOrganizationProfileOperation,\n updateOrganizationRosterEntryOperation,\n getPrincipalPolicyOperation,\n getProjectionPolicyHistoryOperation,\n commitOrganizationGroupPolicyOperation,\n putPrincipalPolicyOperation,\n listRootIdentitiesOperation,\n listRootOrganizationsOperation,\n getRootOrganizationDataUsageOperation,\n listRootDataUsageReportOperation,\n getRootOrganizationOperation,\n listRootOrganizationIdentitiesOperation,\n getRootIdentityOperation,\n listRootIdentityOrganizationsOperation,\n documentSyncOperation,\n];\n"]}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["registry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n bindBlobAttachmentOperation,\n detachBlobAttachmentOperation,\n listDocumentAttachmentsOperation,\n} from \"./attachments\";\nimport {\n challengeOperation,\n destroySessionOperation,\n listSessionsOperation,\n logoutOperation,\n registerOperation,\n userIdentityOperation,\n verifyOperation,\n webSocketTicketOperation,\n} from \"./auth\";\nimport {\n receiveRevenueCatWebhookOperation,\n receiveStripeWebhookOperation,\n} from \"./billingWebhooks\";\nimport {\n getBlobBytesOperation,\n uploadMultipartBlobPartBytesOperation,\n} from \"./blobBytes\";\nimport { getBlobDownloadOperation } from \"./blobDownloads\";\nimport {\n createContainerOperation,\n createContainerWithMetadataDocumentOperation,\n deleteContainerOperation,\n moveContainerOperation,\n reciteContainerOperation,\n rekeyContainerOperation,\n revokeContainerOperation,\n shareContainerOperation,\n} from \"./containerMutations\";\nimport {\n getContainerKekLogOperation,\n listContainerDocumentsOperation,\n listContainerParentLanesOperation,\n} from \"./containerReads\";\nimport { getContainerReplacementAuthorizationsOperation } from \"./containerReplacement\";\nimport {\n getDocumentAttributionOperation,\n listDocumentAttributionRangesOperation,\n} from \"./documentAttribution\";\nimport {\n createDocumentOperation,\n getDocumentPurgeProofOperation,\n linkDocumentOperation,\n purgeDocumentOperation,\n unlinkDocumentOperation,\n} from \"./documentMutations\";\nimport { documentSyncOperation } from \"./documentSync\";\nimport { getHealthOperation } from \"./health\";\nimport {\n completeMultipartBlobStageOperation,\n getMultipartBlobStageOperation,\n initiateMultipartBlobStageOperation,\n} from \"./multipartBlobs\";\nimport {\n claimNativeOrganizationSubscriptionOperation,\n getOrganizationBillingHistoryOperation,\n getOrganizationBillingManagementUrlOperation,\n getOrganizationBillingOperation,\n getOrganizationNativePurchaseEligibilityOperation,\n startOrganizationTrialOperation,\n} from \"./organizationBilling\";\nimport { getOrganizationPolicyHistoryOperation } from \"./organizationPolicyHistory\";\nimport {\n createOrganizationGroupOperation,\n createOrganizationOperation,\n deleteOrganizationGroupOperation,\n getOrganizationDataUsageOperation,\n getOrganizationReadModelOperation,\n listOrganizationGroupMembersOperation,\n updateOrganizationProfileOperation,\n updateOrganizationRosterEntryOperation,\n} from \"./organizations\";\nimport {\n commitOrganizationGroupPolicyOperation,\n getPrincipalPolicyOperation,\n putPrincipalPolicyOperation,\n} from \"./principals\";\nimport { getProjectionPolicyHistoryOperation } from \"./projectionPolicyHistory\";\nimport {\n getRootIdentityOperation,\n listRootIdentitiesOperation,\n listRootIdentityOrganizationsOperation,\n} from \"./root\";\nimport {\n getRootOrganizationDataUsageOperation,\n getRootOrganizationOperation,\n listRootDataUsageReportOperation,\n listRootOrganizationIdentitiesOperation,\n listRootOrganizationsOperation,\n} from \"./rootOrganizations\";\nimport {\n cancelStripeSubscriptionOperation,\n createStripeCheckoutOperation,\n createStripeCheckoutSessionOperation,\n createStripePortalOperation,\n getStripeCheckoutOptionsOperation,\n} from \"./stripeCheckout\";\nimport {\n getContainerWriterProjectionOperation,\n getDocumentWriterProjectionOperation,\n} from \"./writerProjections\";\n\n// Name each imported operation type instead of expanding every Zod schema in\n// the emitted declaration; the exact readonly tuple and runtime order stay intact.\nexport const protocolOperations: readonly [\n typeof getContainerReplacementAuthorizationsOperation,\n typeof getHealthOperation,\n typeof challengeOperation,\n typeof destroySessionOperation,\n typeof listSessionsOperation,\n typeof logoutOperation,\n typeof registerOperation,\n typeof userIdentityOperation,\n typeof verifyOperation,\n typeof webSocketTicketOperation,\n typeof getBlobBytesOperation,\n typeof getBlobDownloadOperation,\n typeof receiveRevenueCatWebhookOperation,\n typeof receiveStripeWebhookOperation,\n typeof bindBlobAttachmentOperation,\n typeof detachBlobAttachmentOperation,\n typeof initiateMultipartBlobStageOperation,\n typeof getMultipartBlobStageOperation,\n typeof completeMultipartBlobStageOperation,\n typeof uploadMultipartBlobPartBytesOperation,\n typeof listDocumentAttachmentsOperation,\n typeof getDocumentAttributionOperation,\n typeof listDocumentAttributionRangesOperation,\n typeof createDocumentOperation,\n typeof getDocumentPurgeProofOperation,\n typeof linkDocumentOperation,\n typeof purgeDocumentOperation,\n typeof unlinkDocumentOperation,\n typeof getContainerKekLogOperation,\n typeof listContainerDocumentsOperation,\n typeof listContainerParentLanesOperation,\n typeof createContainerOperation,\n typeof createContainerWithMetadataDocumentOperation,\n typeof deleteContainerOperation,\n typeof moveContainerOperation,\n typeof reciteContainerOperation,\n typeof rekeyContainerOperation,\n typeof revokeContainerOperation,\n typeof shareContainerOperation,\n typeof getContainerWriterProjectionOperation,\n typeof getDocumentWriterProjectionOperation,\n typeof createOrganizationOperation,\n typeof getOrganizationBillingOperation,\n typeof getOrganizationBillingHistoryOperation,\n typeof getOrganizationBillingManagementUrlOperation,\n typeof getOrganizationNativePurchaseEligibilityOperation,\n typeof claimNativeOrganizationSubscriptionOperation,\n typeof startOrganizationTrialOperation,\n typeof getStripeCheckoutOptionsOperation,\n typeof createStripeCheckoutOperation,\n typeof createStripeCheckoutSessionOperation,\n typeof createStripePortalOperation,\n typeof cancelStripeSubscriptionOperation,\n typeof getOrganizationDataUsageOperation,\n typeof getOrganizationReadModelOperation,\n typeof getOrganizationPolicyHistoryOperation,\n typeof createOrganizationGroupOperation,\n typeof deleteOrganizationGroupOperation,\n typeof listOrganizationGroupMembersOperation,\n typeof updateOrganizationProfileOperation,\n typeof updateOrganizationRosterEntryOperation,\n typeof getPrincipalPolicyOperation,\n typeof getProjectionPolicyHistoryOperation,\n typeof commitOrganizationGroupPolicyOperation,\n typeof putPrincipalPolicyOperation,\n typeof listRootIdentitiesOperation,\n typeof listRootOrganizationsOperation,\n typeof getRootOrganizationDataUsageOperation,\n typeof listRootDataUsageReportOperation,\n typeof getRootOrganizationOperation,\n typeof listRootOrganizationIdentitiesOperation,\n typeof getRootIdentityOperation,\n typeof listRootIdentityOrganizationsOperation,\n typeof documentSyncOperation,\n] = [\n getContainerReplacementAuthorizationsOperation,\n getHealthOperation,\n challengeOperation,\n destroySessionOperation,\n listSessionsOperation,\n logoutOperation,\n registerOperation,\n userIdentityOperation,\n verifyOperation,\n webSocketTicketOperation,\n getBlobBytesOperation,\n getBlobDownloadOperation,\n receiveRevenueCatWebhookOperation,\n receiveStripeWebhookOperation,\n bindBlobAttachmentOperation,\n detachBlobAttachmentOperation,\n initiateMultipartBlobStageOperation,\n getMultipartBlobStageOperation,\n completeMultipartBlobStageOperation,\n uploadMultipartBlobPartBytesOperation,\n listDocumentAttachmentsOperation,\n getDocumentAttributionOperation,\n listDocumentAttributionRangesOperation,\n createDocumentOperation,\n getDocumentPurgeProofOperation,\n linkDocumentOperation,\n purgeDocumentOperation,\n unlinkDocumentOperation,\n getContainerKekLogOperation,\n listContainerDocumentsOperation,\n listContainerParentLanesOperation,\n createContainerOperation,\n createContainerWithMetadataDocumentOperation,\n deleteContainerOperation,\n moveContainerOperation,\n reciteContainerOperation,\n rekeyContainerOperation,\n revokeContainerOperation,\n shareContainerOperation,\n getContainerWriterProjectionOperation,\n getDocumentWriterProjectionOperation,\n createOrganizationOperation,\n getOrganizationBillingOperation,\n getOrganizationBillingHistoryOperation,\n getOrganizationBillingManagementUrlOperation,\n getOrganizationNativePurchaseEligibilityOperation,\n claimNativeOrganizationSubscriptionOperation,\n startOrganizationTrialOperation,\n getStripeCheckoutOptionsOperation,\n createStripeCheckoutOperation,\n createStripeCheckoutSessionOperation,\n createStripePortalOperation,\n cancelStripeSubscriptionOperation,\n getOrganizationDataUsageOperation,\n getOrganizationReadModelOperation,\n getOrganizationPolicyHistoryOperation,\n createOrganizationGroupOperation,\n deleteOrganizationGroupOperation,\n listOrganizationGroupMembersOperation,\n updateOrganizationProfileOperation,\n updateOrganizationRosterEntryOperation,\n getPrincipalPolicyOperation,\n getProjectionPolicyHistoryOperation,\n commitOrganizationGroupPolicyOperation,\n putPrincipalPolicyOperation,\n listRootIdentitiesOperation,\n listRootOrganizationsOperation,\n getRootOrganizationDataUsageOperation,\n listRootDataUsageReportOperation,\n getRootOrganizationOperation,\n listRootOrganizationIdentitiesOperation,\n getRootIdentityOperation,\n listRootIdentityOrganizationsOperation,\n documentSyncOperation,\n];\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tearleads/client-sdk",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "React-free Tearleads client runtime: local SQLite persistence, keys, sync, encrypted blobs, and domain workflows.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -23,6 +23,7 @@ function areSnapshotNodesEqual(left, right) {
23
23
  leftNode.icon === rightNode.icon &&
24
24
  leftNode.kind === rightNode.kind &&
25
25
  leftNode.metadataDocumentId === rightNode.metadataDocumentId &&
26
+ leftNode.metadataReady === rightNode.metadataReady &&
26
27
  leftNode.name === rightNode.name &&
27
28
  leftNode.organizationId === rightNode.organizationId &&
28
29
  leftNode.parentId === rightNode.parentId &&
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContainerContentsPersistence } from \"../../workflows/container-contents/containerPersistence\";\nimport {\n createContainerContentsProjectionUserKeyResolver,\n didContainerContentsProjectionKeyRuntimeChange,\n} from \"../../workflows/container-contents/projectionKeys\";\nimport { didRegainSyncPrerequisites } from \"../../workflows/container-contents/syncLane\";\nimport { ContainerStateMap } from \"./containerStateMap\";\nimport type {\n ContainerContentsStoreRuntime,\n ContainerContentsStoreSyncAgent,\n} from \"./syncAgentTypes\";\nimport type {\n ContainerContentsSnapshot,\n ContainerContentsStoreState,\n ContainerNode,\n} from \"./types\";\nimport { getSnapshotNodes } from \"./utils\";\nimport { didContainerWriteRuntimeChange } from \"./writeGeneration\";\n\nfunction areSyncStatesEqual(\n left: ContainerNode[\"syncState\"],\n right: ContainerNode[\"syncState\"],\n): boolean {\n return (\n left.lastError === right.lastError &&\n left.pendingAttachmentBytes === right.pendingAttachmentBytes &&\n left.pendingAttachmentCount === right.pendingAttachmentCount &&\n left.pendingUpdateCount === right.pendingUpdateCount &&\n left.status === right.status\n );\n}\n\nfunction areSnapshotNodesEqual(\n left: ReadonlyArray<ContainerNode>,\n right: ReadonlyArray<ContainerNode>,\n): boolean {\n if (left.length !== right.length) {\n return false;\n }\n\n return left.every((leftNode, index) => {\n const rightNode = right[index];\n return (\n rightNode !== undefined &&\n leftNode.createdAt === rightNode.createdAt &&\n leftNode.effectiveAccessLevel === rightNode.effectiveAccessLevel &&\n leftNode.id === rightNode.id &&\n leftNode.icon === rightNode.icon &&\n leftNode.kind === rightNode.kind &&\n leftNode.metadataDocumentId === rightNode.metadataDocumentId &&\n leftNode.name === rightNode.name &&\n leftNode.organizationId === rightNode.organizationId &&\n leftNode.parentId === rightNode.parentId &&\n areSyncStatesEqual(leftNode.syncState, rightNode.syncState) &&\n leftNode.systemSlot === rightNode.systemSlot &&\n leftNode.updatedAt === rightNode.updatedAt\n );\n });\n}\n\nfunction didStructuralRuntimeChange(\n previousRuntime: ContainerContentsStoreRuntime,\n nextRuntime: ContainerContentsStoreRuntime,\n): boolean {\n // Structural sync also depends on connectivity and event delivery. Local\n // writes use only the identity and storage checks shared below.\n return (\n didContainerWriteRuntimeChange(previousRuntime, nextRuntime) ||\n previousRuntime.state.online !== nextRuntime.state.online ||\n previousRuntime.state.peerScope !== nextRuntime.state.peerScope ||\n previousRuntime.state.serverEventsConnectionGeneration !==\n nextRuntime.state.serverEventsConnectionGeneration ||\n previousRuntime.util.isRemoteSyncBlocked !==\n nextRuntime.util.isRemoteSyncBlocked\n );\n}\n\nexport function createContainerContentsStoreState(\n initialRuntime: ContainerContentsStoreRuntime,\n persistence: ContainerContentsPersistence,\n logLabel?: string | undefined,\n): ContainerContentsStoreState {\n return {\n containersById: new ContainerStateMap(),\n containerParentIdsNeedingHydration: new Set(),\n documentStoresNeedPriming: true,\n initializeGeneration: null,\n initializePromise: null,\n initialized: false,\n localContainerRefreshPromise: null,\n localContainerRefreshGeneration: null,\n localContainerRefreshStructuralGeneration: null,\n localContainersNeedRefresh: false,\n lifecycleGeneration: 0,\n lastEventCount: 0,\n listeners: new Set(),\n locallyAcceptedMetadataUpdateIds: new Set(),\n logLabel,\n metadataDocumentIdsNeedingSync: new Set(),\n metadataSyncSignalSeqById: new Map(),\n persistence,\n remoteHydrationPromise: null,\n remoteHydrationGeneration: null,\n remoteHydrationStructuralGeneration: null,\n remoteReconnectRefreshPending: false,\n resolveProjectionUserKey:\n createContainerContentsProjectionUserKeyResolver(initialRuntime),\n rootLaneHydrated: false,\n runtime: initialRuntime,\n snapshot: {\n nodes: [],\n ready: false,\n },\n syncLane: null,\n structuralGeneration: 0,\n writeGeneration: 0,\n writeChain: Promise.resolve<ContainerNode | null>(null),\n };\n}\n\nfunction emitContainerContentsStore(state: ContainerContentsStoreState) {\n for (const listener of state.listeners) {\n listener();\n }\n}\n\nfunction setContainerContentsSnapshot(\n state: ContainerContentsStoreState,\n next: ContainerContentsSnapshot,\n) {\n if (\n next.ready === state.snapshot.ready &&\n areSnapshotNodesEqual(next.nodes, state.snapshot.nodes)\n ) {\n return;\n }\n\n state.snapshot = next;\n emitContainerContentsStore(state);\n}\n\nexport function updateContainerContentsSnapshot(\n state: ContainerContentsStoreState,\n) {\n setContainerContentsSnapshot(state, {\n nodes: getSnapshotNodes(state.containersById),\n ready: true,\n });\n}\n\nfunction resetContainerContentsStore(state: ContainerContentsStoreState) {\n state.lifecycleGeneration += 1;\n state.containersById = new ContainerStateMap();\n state.containerParentIdsNeedingHydration = new Set();\n state.documentStoresNeedPriming = true;\n state.initialized = false;\n state.localContainersNeedRefresh = false;\n // Runtime events are snapshots, not a destructive queue. A replacement\n // executor or persistence adapter has not observed any of them, even when\n // their effects were already applied to the previous database. Replay the\n // snapshot after replacement initialization rebuilds metadata identities.\n state.lastEventCount = 0;\n // Accepted-echo suppression state must not survive a reset: after a\n // database loss the tree rehydrates from remote, and a retained id would\n // suppress the next matching remote update signal. Mirrors\n // clearDocumentStoreState in the document store lane.\n state.locallyAcceptedMetadataUpdateIds = new Set();\n state.metadataDocumentIdsNeedingSync = new Set();\n state.metadataSyncSignalSeqById = new Map();\n state.rootLaneHydrated = false;\n state.writeChain = Promise.resolve<ContainerNode | null>(null);\n setContainerContentsSnapshot(state, {\n nodes: [],\n ready: false,\n });\n}\n\nexport function subscribeToContainerContentsStore(\n state: ContainerContentsStoreState,\n listener: () => void,\n) {\n state.listeners.add(listener);\n return () => state.listeners.delete(listener);\n}\n\nexport function updateContainerContentsStoreRuntime(\n state: ContainerContentsStoreState,\n nextRuntime: ContainerContentsStoreRuntime,\n syncAgent: ContainerContentsStoreSyncAgent,\n) {\n const previousRuntime = state.runtime;\n const runtimeReplaced = didStructuralRuntimeChange(\n previousRuntime,\n nextRuntime,\n );\n if (didContainerWriteRuntimeChange(previousRuntime, nextRuntime)) {\n state.writeGeneration += 1;\n }\n const executorReplaced =\n previousRuntime.infra.execSql !== nextRuntime.infra.execSql;\n const serverEventsConnectionChanged =\n previousRuntime.state.serverEventsConnectionGeneration !==\n nextRuntime.state.serverEventsConnectionGeneration;\n if (runtimeReplaced) {\n state.structuralGeneration += 1;\n state.localContainersNeedRefresh = true;\n }\n const contextChanged =\n previousRuntime.auth.organizationId !== nextRuntime.auth.organizationId ||\n previousRuntime.state.containerId !== nextRuntime.state.containerId;\n if (\n didContainerContentsProjectionKeyRuntimeChange(previousRuntime, nextRuntime)\n ) {\n state.resolveProjectionUserKey =\n createContainerContentsProjectionUserKeyResolver(nextRuntime);\n }\n state.runtime = nextRuntime;\n if (serverEventsConnectionChanged) {\n state.remoteReconnectRefreshPending = true;\n }\n\n if (nextRuntime.infra.dbStatus !== \"ready\") {\n if (state.snapshot.ready || state.initialized || state.initializePromise) {\n resetContainerContentsStore(state);\n }\n return;\n }\n\n if (executorReplaced) {\n // The in-memory tree and lane markers belong to the previous executor.\n // Rebuild them from the replacement database before any remote sync can\n // observe or persist the old database's state.\n resetContainerContentsStore(state);\n syncAgent.ensureInitialized();\n syncAgent.handleRemoteEvents();\n return;\n }\n\n // Gaining authentication within a domain scope does not change identity\n // (the scope is keyed on the signing fingerprint), so the locally-loaded\n // tree stays valid. Reconcile it in place instead of resetting — resetting\n // here is what blanked Explorer and forced a re-read on first open after\n // register. Identity/storage changes are handled by scope rotation and the\n // dbStatus-loss branch above.\n if (\n state.snapshot.ready &&\n (contextChanged || didRegainSyncPrerequisites(previousRuntime, nextRuntime))\n ) {\n state.localContainersNeedRefresh = true;\n state.documentStoresNeedPriming = true;\n void syncAgent.refreshLocalContainers();\n // The refresh alone does not run the sync lane; schedule it so newly\n // eligible documents (e.g. this organization's orphans) prime now.\n syncAgent.scheduleSync();\n }\n\n syncAgent.ensureInitialized();\n\n syncAgent.handleRemoteEvents();\n\n if (runtimeReplaced) {\n void syncAgent.refreshLocalContainers();\n syncAgent.scheduleSync();\n }\n\n consumePendingContainerContentsReconnectRefresh(state, syncAgent.refresh);\n\n if (\n state.snapshot.ready &&\n didRegainSyncPrerequisites(previousRuntime, nextRuntime)\n ) {\n // A pass blocked by missing prerequisites consumes its lane request before\n // returning early. Re-arm it directly when they return even if hydration\n // finds no remote delta; this also primes unopened document stores.\n syncAgent.scheduleSync();\n syncAgent.scheduleRemoteHydration();\n }\n}\n\nexport function consumePendingContainerContentsReconnectRefresh(\n state: {\n remoteReconnectRefreshPending: boolean;\n snapshot: { ready: boolean };\n },\n refresh: () => Promise<boolean>,\n): void {\n if (!state.snapshot.ready || !state.remoteReconnectRefreshPending) return;\n state.remoteReconnectRefreshPending = false;\n void refresh().then(\n (refreshed) => {\n if (!refreshed) state.remoteReconnectRefreshPending = true;\n },\n () => {\n state.remoteReconnectRefreshPending = true;\n },\n );\n}\n\nexport function updateContainerContentsStorePersistence(\n state: ContainerContentsStoreState,\n nextPersistence: ContainerContentsPersistence,\n syncAgent: ContainerContentsStoreSyncAgent,\n): void {\n if (state.persistence === nextPersistence) {\n return;\n }\n state.persistence = nextPersistence;\n state.structuralGeneration += 1;\n state.writeGeneration += 1;\n // Persistence replacement changes the authoritative local data source even\n // when the SQLite executor itself is stable. Clear storage-backed state and\n // let initialization load the replacement before scheduling remote work.\n resetContainerContentsStore(state);\n syncAgent.ensureInitialized();\n}\n"]}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContainerContentsPersistence } from \"../../workflows/container-contents/containerPersistence\";\nimport {\n createContainerContentsProjectionUserKeyResolver,\n didContainerContentsProjectionKeyRuntimeChange,\n} from \"../../workflows/container-contents/projectionKeys\";\nimport { didRegainSyncPrerequisites } from \"../../workflows/container-contents/syncLane\";\nimport { ContainerStateMap } from \"./containerStateMap\";\nimport type {\n ContainerContentsStoreRuntime,\n ContainerContentsStoreSyncAgent,\n} from \"./syncAgentTypes\";\nimport type {\n ContainerContentsSnapshot,\n ContainerContentsStoreState,\n ContainerNode,\n} from \"./types\";\nimport { getSnapshotNodes } from \"./utils\";\nimport { didContainerWriteRuntimeChange } from \"./writeGeneration\";\n\nfunction areSyncStatesEqual(\n left: ContainerNode[\"syncState\"],\n right: ContainerNode[\"syncState\"],\n): boolean {\n return (\n left.lastError === right.lastError &&\n left.pendingAttachmentBytes === right.pendingAttachmentBytes &&\n left.pendingAttachmentCount === right.pendingAttachmentCount &&\n left.pendingUpdateCount === right.pendingUpdateCount &&\n left.status === right.status\n );\n}\n\nfunction areSnapshotNodesEqual(\n left: ReadonlyArray<ContainerNode>,\n right: ReadonlyArray<ContainerNode>,\n): boolean {\n if (left.length !== right.length) {\n return false;\n }\n\n return left.every((leftNode, index) => {\n const rightNode = right[index];\n return (\n rightNode !== undefined &&\n leftNode.createdAt === rightNode.createdAt &&\n leftNode.effectiveAccessLevel === rightNode.effectiveAccessLevel &&\n leftNode.id === rightNode.id &&\n leftNode.icon === rightNode.icon &&\n leftNode.kind === rightNode.kind &&\n leftNode.metadataDocumentId === rightNode.metadataDocumentId &&\n leftNode.metadataReady === rightNode.metadataReady &&\n leftNode.name === rightNode.name &&\n leftNode.organizationId === rightNode.organizationId &&\n leftNode.parentId === rightNode.parentId &&\n areSyncStatesEqual(leftNode.syncState, rightNode.syncState) &&\n leftNode.systemSlot === rightNode.systemSlot &&\n leftNode.updatedAt === rightNode.updatedAt\n );\n });\n}\n\nfunction didStructuralRuntimeChange(\n previousRuntime: ContainerContentsStoreRuntime,\n nextRuntime: ContainerContentsStoreRuntime,\n): boolean {\n // Structural sync also depends on connectivity and event delivery. Local\n // writes use only the identity and storage checks shared below.\n return (\n didContainerWriteRuntimeChange(previousRuntime, nextRuntime) ||\n previousRuntime.state.online !== nextRuntime.state.online ||\n previousRuntime.state.peerScope !== nextRuntime.state.peerScope ||\n previousRuntime.state.serverEventsConnectionGeneration !==\n nextRuntime.state.serverEventsConnectionGeneration ||\n previousRuntime.util.isRemoteSyncBlocked !==\n nextRuntime.util.isRemoteSyncBlocked\n );\n}\n\nexport function createContainerContentsStoreState(\n initialRuntime: ContainerContentsStoreRuntime,\n persistence: ContainerContentsPersistence,\n logLabel?: string | undefined,\n): ContainerContentsStoreState {\n return {\n containersById: new ContainerStateMap(),\n containerParentIdsNeedingHydration: new Set(),\n documentStoresNeedPriming: true,\n initializeGeneration: null,\n initializePromise: null,\n initialized: false,\n localContainerRefreshPromise: null,\n localContainerRefreshGeneration: null,\n localContainerRefreshStructuralGeneration: null,\n localContainersNeedRefresh: false,\n lifecycleGeneration: 0,\n lastEventCount: 0,\n listeners: new Set(),\n locallyAcceptedMetadataUpdateIds: new Set(),\n logLabel,\n metadataDocumentIdsNeedingSync: new Set(),\n metadataSyncSignalSeqById: new Map(),\n persistence,\n remoteHydrationPromise: null,\n remoteHydrationGeneration: null,\n remoteHydrationStructuralGeneration: null,\n remoteReconnectRefreshPending: false,\n resolveProjectionUserKey:\n createContainerContentsProjectionUserKeyResolver(initialRuntime),\n rootLaneHydrated: false,\n runtime: initialRuntime,\n snapshot: {\n nodes: [],\n ready: false,\n },\n syncLane: null,\n structuralGeneration: 0,\n writeGeneration: 0,\n writeChain: Promise.resolve<ContainerNode | null>(null),\n };\n}\n\nfunction emitContainerContentsStore(state: ContainerContentsStoreState) {\n for (const listener of state.listeners) {\n listener();\n }\n}\n\nfunction setContainerContentsSnapshot(\n state: ContainerContentsStoreState,\n next: ContainerContentsSnapshot,\n) {\n if (\n next.ready === state.snapshot.ready &&\n areSnapshotNodesEqual(next.nodes, state.snapshot.nodes)\n ) {\n return;\n }\n\n state.snapshot = next;\n emitContainerContentsStore(state);\n}\n\nexport function updateContainerContentsSnapshot(\n state: ContainerContentsStoreState,\n) {\n setContainerContentsSnapshot(state, {\n nodes: getSnapshotNodes(state.containersById),\n ready: true,\n });\n}\n\nfunction resetContainerContentsStore(state: ContainerContentsStoreState) {\n state.lifecycleGeneration += 1;\n state.containersById = new ContainerStateMap();\n state.containerParentIdsNeedingHydration = new Set();\n state.documentStoresNeedPriming = true;\n state.initialized = false;\n state.localContainersNeedRefresh = false;\n // Runtime events are snapshots, not a destructive queue. A replacement\n // executor or persistence adapter has not observed any of them, even when\n // their effects were already applied to the previous database. Replay the\n // snapshot after replacement initialization rebuilds metadata identities.\n state.lastEventCount = 0;\n // Accepted-echo suppression state must not survive a reset: after a\n // database loss the tree rehydrates from remote, and a retained id would\n // suppress the next matching remote update signal. Mirrors\n // clearDocumentStoreState in the document store lane.\n state.locallyAcceptedMetadataUpdateIds = new Set();\n state.metadataDocumentIdsNeedingSync = new Set();\n state.metadataSyncSignalSeqById = new Map();\n state.rootLaneHydrated = false;\n state.writeChain = Promise.resolve<ContainerNode | null>(null);\n setContainerContentsSnapshot(state, {\n nodes: [],\n ready: false,\n });\n}\n\nexport function subscribeToContainerContentsStore(\n state: ContainerContentsStoreState,\n listener: () => void,\n) {\n state.listeners.add(listener);\n return () => state.listeners.delete(listener);\n}\n\nexport function updateContainerContentsStoreRuntime(\n state: ContainerContentsStoreState,\n nextRuntime: ContainerContentsStoreRuntime,\n syncAgent: ContainerContentsStoreSyncAgent,\n) {\n const previousRuntime = state.runtime;\n const runtimeReplaced = didStructuralRuntimeChange(\n previousRuntime,\n nextRuntime,\n );\n if (didContainerWriteRuntimeChange(previousRuntime, nextRuntime)) {\n state.writeGeneration += 1;\n }\n const executorReplaced =\n previousRuntime.infra.execSql !== nextRuntime.infra.execSql;\n const serverEventsConnectionChanged =\n previousRuntime.state.serverEventsConnectionGeneration !==\n nextRuntime.state.serverEventsConnectionGeneration;\n if (runtimeReplaced) {\n state.structuralGeneration += 1;\n state.localContainersNeedRefresh = true;\n }\n const contextChanged =\n previousRuntime.auth.organizationId !== nextRuntime.auth.organizationId ||\n previousRuntime.state.containerId !== nextRuntime.state.containerId;\n if (\n didContainerContentsProjectionKeyRuntimeChange(previousRuntime, nextRuntime)\n ) {\n state.resolveProjectionUserKey =\n createContainerContentsProjectionUserKeyResolver(nextRuntime);\n }\n state.runtime = nextRuntime;\n if (serverEventsConnectionChanged) {\n state.remoteReconnectRefreshPending = true;\n }\n\n if (nextRuntime.infra.dbStatus !== \"ready\") {\n if (state.snapshot.ready || state.initialized || state.initializePromise) {\n resetContainerContentsStore(state);\n }\n return;\n }\n\n if (executorReplaced) {\n // The in-memory tree and lane markers belong to the previous executor.\n // Rebuild them from the replacement database before any remote sync can\n // observe or persist the old database's state.\n resetContainerContentsStore(state);\n syncAgent.ensureInitialized();\n syncAgent.handleRemoteEvents();\n return;\n }\n\n // Gaining authentication within a domain scope does not change identity\n // (the scope is keyed on the signing fingerprint), so the locally-loaded\n // tree stays valid. Reconcile it in place instead of resetting — resetting\n // here is what blanked Explorer and forced a re-read on first open after\n // register. Identity/storage changes are handled by scope rotation and the\n // dbStatus-loss branch above.\n if (\n state.snapshot.ready &&\n (contextChanged || didRegainSyncPrerequisites(previousRuntime, nextRuntime))\n ) {\n state.localContainersNeedRefresh = true;\n state.documentStoresNeedPriming = true;\n void syncAgent.refreshLocalContainers();\n // The refresh alone does not run the sync lane; schedule it so newly\n // eligible documents (e.g. this organization's orphans) prime now.\n syncAgent.scheduleSync();\n }\n\n syncAgent.ensureInitialized();\n\n syncAgent.handleRemoteEvents();\n\n if (runtimeReplaced) {\n void syncAgent.refreshLocalContainers();\n syncAgent.scheduleSync();\n }\n\n consumePendingContainerContentsReconnectRefresh(state, syncAgent.refresh);\n\n if (\n state.snapshot.ready &&\n didRegainSyncPrerequisites(previousRuntime, nextRuntime)\n ) {\n // A pass blocked by missing prerequisites consumes its lane request before\n // returning early. Re-arm it directly when they return even if hydration\n // finds no remote delta; this also primes unopened document stores.\n syncAgent.scheduleSync();\n syncAgent.scheduleRemoteHydration();\n }\n}\n\nexport function consumePendingContainerContentsReconnectRefresh(\n state: {\n remoteReconnectRefreshPending: boolean;\n snapshot: { ready: boolean };\n },\n refresh: () => Promise<boolean>,\n): void {\n if (!state.snapshot.ready || !state.remoteReconnectRefreshPending) return;\n state.remoteReconnectRefreshPending = false;\n void refresh().then(\n (refreshed) => {\n if (!refreshed) state.remoteReconnectRefreshPending = true;\n },\n () => {\n state.remoteReconnectRefreshPending = true;\n },\n );\n}\n\nexport function updateContainerContentsStorePersistence(\n state: ContainerContentsStoreState,\n nextPersistence: ContainerContentsPersistence,\n syncAgent: ContainerContentsStoreSyncAgent,\n): void {\n if (state.persistence === nextPersistence) {\n return;\n }\n state.persistence = nextPersistence;\n state.structuralGeneration += 1;\n state.writeGeneration += 1;\n // Persistence replacement changes the authoritative local data source even\n // when the SQLite executor itself is stable. Clear storage-backed state and\n // let initialization load the replacement before scheduling remote work.\n resetContainerContentsStore(state);\n syncAgent.ensureInitialized();\n}\n"]}
@@ -17,6 +17,8 @@ export interface ContainerNode {
17
17
  id: string;
18
18
  icon?: string | null;
19
19
  metadataDocumentId?: string | null;
20
+ /** False while a discovered remote folder has no local metadata content. */
21
+ metadataReady?: boolean;
20
22
  organizationId: string;
21
23
  name: string;
22
24
  parentId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ContainerAccessLevel,\n ReferencedPrincipalHead,\n} from \"@tearleads/crypto\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type { PurgeOptions } from \"../../workflows/container-contents/container-state/purgeProgress\";\nimport type { ContainerContentsPersistence } from \"../../workflows/container-contents/containerPersistence\";\nimport type { ContainerDocumentObjectSyncState } from \"../../workflows/container-contents/syncState\";\nimport type {\n ContainerContentsStoreRuntime,\n ContainerContentsStoreSyncState,\n RefreshRootLaneOptions,\n} from \"./syncAgentTypes\";\n\n// Reuse the canonical access-level union from the crypto layer (the same source\n// `ContainerShareAccessLevel` chains to) rather than re-spelling the literals,\n// so the two can't drift.\nexport type ContainerContentsShareAccessLevel = ContainerAccessLevel;\n\nexport interface ContainerContentsStoreOptions {\n logLabel?: string | undefined;\n persistence?: ContainerContentsPersistence | undefined;\n}\n\nexport interface ContainerNode {\n systemSlot?: ContainerSystemSlot | null;\n createdAt?: string | null;\n effectiveAccessLevel?: ContainerAccessLevel | undefined;\n id: string;\n icon?: string | null;\n metadataDocumentId?: string | null;\n organizationId: string;\n name: string;\n parentId: string | null;\n syncState: ContainerDocumentObjectSyncState;\n kind: \"container\";\n updatedAt?: string | null;\n}\n\n// The store surface exposed through context: the snapshot fields plus the\n// store's mutation/refresh methods, spelled as a Pick so the two can't drift.\nexport type ContainerContentsContextValue = ContainerContentsSnapshot &\n Pick<\n ContainerContentsStore,\n | \"createChild\"\n | \"deleteContainer\"\n | \"emptyTrash\"\n | \"ensureSystemContainer\"\n | \"moveContainer\"\n | \"purgeContainer\"\n | \"refresh\"\n | \"refreshRootLane\"\n | \"renameContainer\"\n | \"requestSync\"\n | \"setContainerIcon\"\n | \"shareWithGroup\"\n | \"shareWithUser\"\n >;\n\nexport interface ContainerContentsSnapshot {\n nodes: ReadonlyArray<ContainerNode>;\n ready: boolean;\n}\n\nexport type ContainerGroupRewrapPreparation =\n | {\n status: \"not-granted\";\n }\n | {\n isCurrent(\n expectedGroupHead: ReferencedPrincipalHead,\n expectedContainerId: string,\n expectedOrganizationId: string,\n ): Promise<boolean>;\n rewrap(): Promise<boolean>;\n status: \"prepared\";\n };\n\n/**\n * Shared per-scope container tree and mutation store.\n *\n * Ordinary metadata/topology writes (`createChild`, `moveContainer`,\n * `renameContainer`, and `setContainerIcon`) commit to local persistence and\n * update subscribers before their queued remote sync converges. Destructive\n * and access-control operations retain their explicit remote-authority gates.\n */\nexport interface ContainerContentsStore {\n createChild: (\n parentId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n deleteContainer: (containerId: string) => Promise<boolean>;\n ensureSystemContainer: (\n systemSlot: ContainerSystemSlot,\n name: string,\n options?: EnsureSystemContainerOptions | undefined,\n ) => Promise<ContainerNode | null>;\n moveContainer: (\n containerId: string,\n parentId: string,\n ) => Promise<ContainerNode | null>;\n purgeContainer: (\n containerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n emptyTrash: (\n trashContainerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n // `options.requireExistingGrant` gates the preparation check only. The\n // prepared `rewrap` is always grant-preserving: it re-wraps a signed grant\n // and never mints one, so it carries no chosen group name, and it throws\n // (rather than healing through a policy mutation) when the container\n // manifest grants the group but the verified policy has no matching grant.\n prepareGroupRewrap: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options?: { requireExistingGrant?: boolean } | undefined,\n ) => Promise<ContainerGroupRewrapPreparation | null>;\n refresh: () => Promise<boolean>;\n refreshRootLane: (options?: RefreshRootLaneOptions) => Promise<boolean>;\n // Re-read root-lane containers from local SQLite into the snapshot with NO\n // server round-trip. Surfaces a just-persisted container — e.g. the Trash bin\n // that registration/org-creation provisioned server-side and wrote to SQLite\n // via persistRegistrationBootstrap — instantly, instead of waiting for the\n // remote root-lane pull. Idempotent with a later remote pull: the merge is\n // keyed by container id, so the pull reconciles in place rather than duplicating.\n refreshLocalContainers: () => Promise<void>;\n requestSync: () => void;\n renameContainer: (\n containerId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n setContainerIcon: (\n containerId: string,\n icon: string | null,\n ) => Promise<ContainerNode | null>;\n shareWithGroup: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options: {\n /**\n * The display name the group was chosen by. Required: the share fails\n * closed if the verified group policy commits a different name. Signed\n * names are unique within an organization by construction (enforced at\n * group creation), so the target's own name identifies it.\n */\n expectedGroupName: string;\n },\n ) => Promise<boolean>;\n shareWithUser: (containerId: string, userId: string) => Promise<boolean>;\n getCachedContainerWriterProjection: (\n containerId: string,\n ) => ContainerWriterProjectionResponse | null;\n getSnapshot: () => ContainerContentsSnapshot;\n subscribe: (listener: () => void) => () => void;\n updateRuntime: (runtime: ContainerContentsStoreRuntime) => void;\n}\n\nexport interface EnsureSystemContainerOptions {\n icon?: string | null | undefined;\n skipAdvancedManagedRoot?: boolean | undefined;\n // For local-first bootstrap paths where slow remote I/O must not block the\n // caller from creating the deterministic local system container.\n deferRemoteBootstrap?: boolean | undefined;\n // Create the deterministic local system container without queuing the remote\n // create. A later ensureSystemContainer call without this flag promotes the\n // local slot into the sync queue.\n deferRemoteSync?: boolean | undefined;\n}\n\nexport interface ContainerContentsStoreState\n extends ContainerContentsStoreSyncState {\n listeners: Set<() => void>;\n snapshot: ContainerContentsSnapshot;\n writeChain: Promise<ContainerNode | null>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ContainerAccessLevel,\n ReferencedPrincipalHead,\n} from \"@tearleads/crypto\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type { PurgeOptions } from \"../../workflows/container-contents/container-state/purgeProgress\";\nimport type { ContainerContentsPersistence } from \"../../workflows/container-contents/containerPersistence\";\nimport type { ContainerDocumentObjectSyncState } from \"../../workflows/container-contents/syncState\";\nimport type {\n ContainerContentsStoreRuntime,\n ContainerContentsStoreSyncState,\n RefreshRootLaneOptions,\n} from \"./syncAgentTypes\";\n\n// Reuse the canonical access-level union from the crypto layer (the same source\n// `ContainerShareAccessLevel` chains to) rather than re-spelling the literals,\n// so the two can't drift.\nexport type ContainerContentsShareAccessLevel = ContainerAccessLevel;\n\nexport interface ContainerContentsStoreOptions {\n logLabel?: string | undefined;\n persistence?: ContainerContentsPersistence | undefined;\n}\n\nexport interface ContainerNode {\n systemSlot?: ContainerSystemSlot | null;\n createdAt?: string | null;\n effectiveAccessLevel?: ContainerAccessLevel | undefined;\n id: string;\n icon?: string | null;\n metadataDocumentId?: string | null;\n /** False while a discovered remote folder has no local metadata content. */\n metadataReady?: boolean;\n organizationId: string;\n name: string;\n parentId: string | null;\n syncState: ContainerDocumentObjectSyncState;\n kind: \"container\";\n updatedAt?: string | null;\n}\n\n// The store surface exposed through context: the snapshot fields plus the\n// store's mutation/refresh methods, spelled as a Pick so the two can't drift.\nexport type ContainerContentsContextValue = ContainerContentsSnapshot &\n Pick<\n ContainerContentsStore,\n | \"createChild\"\n | \"deleteContainer\"\n | \"emptyTrash\"\n | \"ensureSystemContainer\"\n | \"moveContainer\"\n | \"purgeContainer\"\n | \"refresh\"\n | \"refreshRootLane\"\n | \"renameContainer\"\n | \"requestSync\"\n | \"setContainerIcon\"\n | \"shareWithGroup\"\n | \"shareWithUser\"\n >;\n\nexport interface ContainerContentsSnapshot {\n nodes: ReadonlyArray<ContainerNode>;\n ready: boolean;\n}\n\nexport type ContainerGroupRewrapPreparation =\n | {\n status: \"not-granted\";\n }\n | {\n isCurrent(\n expectedGroupHead: ReferencedPrincipalHead,\n expectedContainerId: string,\n expectedOrganizationId: string,\n ): Promise<boolean>;\n rewrap(): Promise<boolean>;\n status: \"prepared\";\n };\n\n/**\n * Shared per-scope container tree and mutation store.\n *\n * Ordinary metadata/topology writes (`createChild`, `moveContainer`,\n * `renameContainer`, and `setContainerIcon`) commit to local persistence and\n * update subscribers before their queued remote sync converges. Destructive\n * and access-control operations retain their explicit remote-authority gates.\n */\nexport interface ContainerContentsStore {\n createChild: (\n parentId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n deleteContainer: (containerId: string) => Promise<boolean>;\n ensureSystemContainer: (\n systemSlot: ContainerSystemSlot,\n name: string,\n options?: EnsureSystemContainerOptions | undefined,\n ) => Promise<ContainerNode | null>;\n moveContainer: (\n containerId: string,\n parentId: string,\n ) => Promise<ContainerNode | null>;\n purgeContainer: (\n containerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n emptyTrash: (\n trashContainerId: string,\n options?: PurgeOptions,\n ) => Promise<boolean>;\n // `options.requireExistingGrant` gates the preparation check only. The\n // prepared `rewrap` is always grant-preserving: it re-wraps a signed grant\n // and never mints one, so it carries no chosen group name, and it throws\n // (rather than healing through a policy mutation) when the container\n // manifest grants the group but the verified policy has no matching grant.\n prepareGroupRewrap: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options?: { requireExistingGrant?: boolean } | undefined,\n ) => Promise<ContainerGroupRewrapPreparation | null>;\n refresh: () => Promise<boolean>;\n refreshRootLane: (options?: RefreshRootLaneOptions) => Promise<boolean>;\n // Re-read root-lane containers from local SQLite into the snapshot with NO\n // server round-trip. Surfaces a just-persisted container — e.g. the Trash bin\n // that registration/org-creation provisioned server-side and wrote to SQLite\n // via persistRegistrationBootstrap — instantly, instead of waiting for the\n // remote root-lane pull. Idempotent with a later remote pull: the merge is\n // keyed by container id, so the pull reconciles in place rather than duplicating.\n refreshLocalContainers: () => Promise<void>;\n requestSync: () => void;\n renameContainer: (\n containerId: string,\n name: string,\n ) => Promise<ContainerNode | null>;\n setContainerIcon: (\n containerId: string,\n icon: string | null,\n ) => Promise<ContainerNode | null>;\n shareWithGroup: (\n containerId: string,\n groupId: string,\n accessLevel: ContainerContentsShareAccessLevel,\n options: {\n /**\n * The display name the group was chosen by. Required: the share fails\n * closed if the verified group policy commits a different name. Signed\n * names are unique within an organization by construction (enforced at\n * group creation), so the target's own name identifies it.\n */\n expectedGroupName: string;\n },\n ) => Promise<boolean>;\n shareWithUser: (containerId: string, userId: string) => Promise<boolean>;\n getCachedContainerWriterProjection: (\n containerId: string,\n ) => ContainerWriterProjectionResponse | null;\n getSnapshot: () => ContainerContentsSnapshot;\n subscribe: (listener: () => void) => () => void;\n updateRuntime: (runtime: ContainerContentsStoreRuntime) => void;\n}\n\nexport interface EnsureSystemContainerOptions {\n icon?: string | null | undefined;\n skipAdvancedManagedRoot?: boolean | undefined;\n // For local-first bootstrap paths where slow remote I/O must not block the\n // caller from creating the deterministic local system container.\n deferRemoteBootstrap?: boolean | undefined;\n // Create the deterministic local system container without queuing the remote\n // create. A later ensureSystemContainer call without this flag promotes the\n // local slot into the sync queue.\n deferRemoteSync?: boolean | undefined;\n}\n\nexport interface ContainerContentsStoreState\n extends ContainerContentsStoreSyncState {\n listeners: Set<() => void>;\n snapshot: ContainerContentsSnapshot;\n writeChain: Promise<ContainerNode | null>;\n}\n"]}
@@ -1,5 +1,14 @@
1
1
  import { normalizeEffectiveAccessLevel } from "../../data/accessLevel.js";
2
2
  import { createContainerDocumentObjectSyncState } from "../../workflows/container-contents/syncState.js";
3
+ function hasContainerMetadata(containerState) {
4
+ const version = containerState.doc.oplogVersion();
5
+ try {
6
+ return version.length() > 0;
7
+ }
8
+ finally {
9
+ version.free();
10
+ }
11
+ }
3
12
  function hasPendingContainerTimestamp(container) {
4
13
  const localUpdatedAt = container.localUpdatedAt ?? null;
5
14
  const serverUpdatedAt = container.serverUpdatedAt ?? null;
@@ -15,6 +24,7 @@ export function toContainerNode(containerState) {
15
24
  id: container.id,
16
25
  kind: "container",
17
26
  metadataDocumentId: container.metadataDocumentId ?? record.documentId,
27
+ metadataReady: !record.documentId || hasContainerMetadata(containerState),
18
28
  name: container.name,
19
29
  organizationId: container.organizationId,
20
30
  parentId: container.parentId,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { normalizeEffectiveAccessLevel } from \"../../data/accessLevel\";\nimport type { ContainerRecord } from \"../../workflows/container-contents/containerPersistence\";\nimport type { ContainerState } from \"../../workflows/container-contents/remoteHydration\";\nimport { createContainerDocumentObjectSyncState } from \"../../workflows/container-contents/syncState\";\nimport type { ContainerNode } from \"./types\";\n\nfunction hasPendingContainerTimestamp(container: ContainerRecord): boolean {\n const localUpdatedAt = container.localUpdatedAt ?? null;\n const serverUpdatedAt = container.serverUpdatedAt ?? null;\n\n return (\n localUpdatedAt !== null &&\n (serverUpdatedAt === null ||\n localUpdatedAt.localeCompare(serverUpdatedAt) > 0)\n );\n}\n\nexport function toContainerNode(containerState: ContainerState): ContainerNode {\n const { container, record } = containerState;\n const systemSlot = container.systemSlot ?? null;\n const node: ContainerNode = {\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n container.effectiveAccessLevel,\n ),\n id: container.id,\n kind: \"container\",\n metadataDocumentId: container.metadataDocumentId ?? record.documentId,\n name: container.name,\n organizationId: container.organizationId,\n parentId: container.parentId,\n syncState: createContainerDocumentObjectSyncState({\n localOnly:\n !container.serverCreatedAt ||\n !container.metadataDocumentId ||\n !record.documentId,\n pendingUpdateCount: hasPendingContainerTimestamp(container) ? 1 : 0,\n }),\n };\n\n if (systemSlot) {\n node.systemSlot = systemSlot;\n }\n\n if (container.icon) {\n node.icon = container.icon;\n }\n\n if (container.createdAt) {\n node.createdAt = container.createdAt;\n }\n if (container.updatedAt) {\n node.updatedAt = container.updatedAt;\n }\n\n return node;\n}\n\nexport function isContainerInSubtree(\n containersById: ReadonlyMap<string, ContainerState>,\n containerId: string,\n rootContainerId: string,\n): boolean {\n let currentContainerId: string | null = containerId;\n const visitedContainerIds = new Set<string>();\n\n while (currentContainerId !== null) {\n if (currentContainerId === rootContainerId) {\n return true;\n }\n\n if (visitedContainerIds.has(currentContainerId)) {\n return false;\n }\n visitedContainerIds.add(currentContainerId);\n\n const currentContainerState = containersById.get(currentContainerId);\n currentContainerId = currentContainerState?.container.parentId ?? null;\n }\n\n return false;\n}\n\nexport function getSnapshotNodes(\n containersById: ReadonlyMap<string, ContainerState>,\n): ReadonlyArray<ContainerNode> {\n return Array.from(containersById.values(), (containerState) =>\n toContainerNode(containerState),\n ).sort((left, right) =>\n left.name.localeCompare(right.name, undefined, {\n sensitivity: \"base\",\n }),\n );\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAGvE,OAAO,EAAE,sCAAsC,EAAE,MAAM,8CAA8C,CAAC;AAGtG,SAAS,oBAAoB,CAAC,cAA8B;IAC1D,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAClD,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,IAAI,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,4BAA4B,CAAC,SAA0B;IAC9D,MAAM,cAAc,GAAG,SAAS,CAAC,cAAc,IAAI,IAAI,CAAC;IACxD,MAAM,eAAe,GAAG,SAAS,CAAC,eAAe,IAAI,IAAI,CAAC;IAE1D,OAAO,CACL,cAAc,KAAK,IAAI;QACvB,CAAC,eAAe,KAAK,IAAI;YACvB,cAAc,CAAC,aAAa,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,cAA8B;IAC5D,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC;IAC7C,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,IAAI,IAAI,CAAC;IAChD,MAAM,IAAI,GAAkB;QAC1B,oBAAoB,EAAE,6BAA6B,CACjD,SAAS,CAAC,oBAAoB,CAC/B;QACD,EAAE,EAAE,SAAS,CAAC,EAAE;QAChB,IAAI,EAAE,WAAW;QACjB,kBAAkB,EAAE,SAAS,CAAC,kBAAkB,IAAI,MAAM,CAAC,UAAU;QACrE,aAAa,EAAE,CAAC,MAAM,CAAC,UAAU,IAAI,oBAAoB,CAAC,cAAc,CAAC;QACzE,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,SAAS,EAAE,sCAAsC,CAAC;YAChD,SAAS,EACP,CAAC,SAAS,CAAC,eAAe;gBAC1B,CAAC,SAAS,CAAC,kBAAkB;gBAC7B,CAAC,MAAM,CAAC,UAAU;YACpB,kBAAkB,EAAE,4BAA4B,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACpE,CAAC;KACH,CAAC;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;IACvC,CAAC;IACD,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;IACvC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,cAAmD,EACnD,WAAmB,EACnB,eAAuB;IAEvB,IAAI,kBAAkB,GAAkB,WAAW,CAAC;IACpD,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE9C,OAAO,kBAAkB,KAAK,IAAI,EAAE,CAAC;QACnC,IAAI,kBAAkB,KAAK,eAAe,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,mBAAmB,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAChD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,mBAAmB,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAE5C,MAAM,qBAAqB,GAAG,cAAc,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACrE,kBAAkB,GAAG,qBAAqB,EAAE,SAAS,CAAC,QAAQ,IAAI,IAAI,CAAC;IACzE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,cAAmD;IAEnD,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,EAAE,EAAE,CAC5D,eAAe,CAAC,cAAc,CAAC,CAChC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACrB,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE;QAC7C,WAAW,EAAE,MAAM;KACpB,CAAC,CACH,CAAC;AACJ,CAAC","sourcesContent":["import { normalizeEffectiveAccessLevel } from \"../../data/accessLevel\";\nimport type { ContainerRecord } from \"../../workflows/container-contents/containerPersistence\";\nimport type { ContainerState } from \"../../workflows/container-contents/remoteHydration\";\nimport { createContainerDocumentObjectSyncState } from \"../../workflows/container-contents/syncState\";\nimport type { ContainerNode } from \"./types\";\n\nfunction hasContainerMetadata(containerState: ContainerState): boolean {\n const version = containerState.doc.oplogVersion();\n try {\n return version.length() > 0;\n } finally {\n version.free();\n }\n}\n\nfunction hasPendingContainerTimestamp(container: ContainerRecord): boolean {\n const localUpdatedAt = container.localUpdatedAt ?? null;\n const serverUpdatedAt = container.serverUpdatedAt ?? null;\n\n return (\n localUpdatedAt !== null &&\n (serverUpdatedAt === null ||\n localUpdatedAt.localeCompare(serverUpdatedAt) > 0)\n );\n}\n\nexport function toContainerNode(containerState: ContainerState): ContainerNode {\n const { container, record } = containerState;\n const systemSlot = container.systemSlot ?? null;\n const node: ContainerNode = {\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n container.effectiveAccessLevel,\n ),\n id: container.id,\n kind: \"container\",\n metadataDocumentId: container.metadataDocumentId ?? record.documentId,\n metadataReady: !record.documentId || hasContainerMetadata(containerState),\n name: container.name,\n organizationId: container.organizationId,\n parentId: container.parentId,\n syncState: createContainerDocumentObjectSyncState({\n localOnly:\n !container.serverCreatedAt ||\n !container.metadataDocumentId ||\n !record.documentId,\n pendingUpdateCount: hasPendingContainerTimestamp(container) ? 1 : 0,\n }),\n };\n\n if (systemSlot) {\n node.systemSlot = systemSlot;\n }\n\n if (container.icon) {\n node.icon = container.icon;\n }\n\n if (container.createdAt) {\n node.createdAt = container.createdAt;\n }\n if (container.updatedAt) {\n node.updatedAt = container.updatedAt;\n }\n\n return node;\n}\n\nexport function isContainerInSubtree(\n containersById: ReadonlyMap<string, ContainerState>,\n containerId: string,\n rootContainerId: string,\n): boolean {\n let currentContainerId: string | null = containerId;\n const visitedContainerIds = new Set<string>();\n\n while (currentContainerId !== null) {\n if (currentContainerId === rootContainerId) {\n return true;\n }\n\n if (visitedContainerIds.has(currentContainerId)) {\n return false;\n }\n visitedContainerIds.add(currentContainerId);\n\n const currentContainerState = containersById.get(currentContainerId);\n currentContainerId = currentContainerState?.container.parentId ?? null;\n }\n\n return false;\n}\n\nexport function getSnapshotNodes(\n containersById: ReadonlyMap<string, ContainerState>,\n): ReadonlyArray<ContainerNode> {\n return Array.from(containersById.values(), (containerState) =>\n toContainerNode(containerState),\n ).sort((left, right) =>\n left.name.localeCompare(right.name, undefined, {\n sensitivity: \"base\",\n }),\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { bytesToBase64 } from "../../../internal/encoding/index.js";
2
- import { encodeVersionVector, getImportBlobMetadata, mergeVersionVectors, } from "../../../internal/loro/index.js";
2
+ import { emptyVersionVector, encodeVersionVector, getImportBlobMetadata, mergeVersionVectors, } from "../../../internal/loro/index.js";
3
3
  import { readPullContinuation } from "../../../data/documents/shared/syncPagination.js";
4
4
  import { settleOutgoingPassAndDecideReArm, shouldClearDocumentSyncFailureAfterPass, } from "../../../workflows/documents/index.js";
5
5
  import { requestDocumentStoreSync } from "../registry.js";
@@ -51,10 +51,14 @@ function pulledHistoryUpdates(synced) {
51
51
  * edit whose durable row has not landed yet.
52
52
  */
53
53
  function coveredSyncFrontier(state, currentRecord, synced) {
54
+ const liveFrontier = (state.record ?? currentRecord).snapshotEndVersion;
54
55
  if (synced.decryptedUpdates.length === 0) {
55
- return {};
56
+ // A completed empty pull distinguishes a real blank note from discovery.
57
+ // An intermediate page cannot establish that no content exists yet.
58
+ return liveFrontier === "" && !synced.hasIncompletePull
59
+ ? { snapshotEndVersion: emptyVersionVector() }
60
+ : {};
56
61
  }
57
- const liveFrontier = (state.record ?? currentRecord).snapshotEndVersion;
58
62
  return {
59
63
  snapshotEndVersion: mergeVersionVectors([
60
64
  ...(liveFrontier.length > 0 ? [liveFrontier] : []),
@@ -1 +1 @@
1
- {"version":3,"file":"syncFinalize.js","sourceRoot":"","sources":["syncFinalize.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n encodeVersionVector,\n getImportBlobMetadata,\n mergeVersionVectors,\n} from \"@tearleads/loro\";\nimport { readPullContinuation } from \"../../../data/documents/shared/syncPagination\";\nimport {\n type DocumentRecord,\n settleOutgoingPassAndDecideReArm,\n shouldClearDocumentSyncFailureAfterPass,\n} from \"../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../registry\";\nimport { hydrateAttachmentBlobs } from \"./attachmentHydration\";\nimport { chainIdentityWrite } from \"./identityWriteChain\";\nimport { publishPersistedDocument, saveDocumentRecord } from \"./persistence\";\nimport { logRevalidationApplied as logApplied } from \"./remoteRevalidationTelemetry\";\nimport type {\n DocumentState,\n DocumentStoreState,\n DocumentSyncAttempt,\n SaveDocumentRecordOptions,\n} from \"./state\";\nimport {\n discardPreRegisteredUpdateIds,\n discardUnacceptedPreRegisteredUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport {\n type DocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"./syncGeneration\";\nimport { clearConsumedRemoteUpdateSignal } from \"./syncRemoteSignals\";\nimport {\n applyIncomingSyncedUpdates,\n documentSyncContextMatches,\n importSyncedDocumentUpdates,\n} from \"./syncUpdateImport\";\nimport { extendDocumentVersionCoverage } from \"./versionCoverage\";\nimport { installDocumentWriterProjection } from \"./writerProjectionGeneration\";\n\nfunction documentWriterProjectionMatchesSyncResponse(\n writerProjection: NonNullable<\n DocumentSyncAttempt[\"synced\"][\"writerProjection\"]\n >,\n synced: DocumentSyncAttempt[\"synced\"],\n): boolean {\n return (\n writerProjection.contentKeyBundle.contentKeyEpoch ===\n synced.response.contentKeyBundle.contentKeyEpoch &&\n writerProjection.contentKeyBundle.linkSetManifestHash ===\n synced.response.contentKeyBundle.linkSetManifestHash &&\n writerProjection.contentKeyBundle.targetHash ===\n synced.response.contentKeyBundle.targetHash &&\n writerProjection.documentKekTargets.linkSetManifestHash ===\n synced.response.documentKekTargets.linkSetManifestHash &&\n writerProjection.documentKekTargets.documentKeyTargetHash ===\n synced.response.documentKekTargets.documentKeyTargetHash\n );\n}\n\nfunction resolveSyncedDocumentWriterProjection(\n state: DocumentStoreState,\n synced: DocumentSyncAttempt[\"synced\"],\n) {\n const writerProjection =\n synced.writerProjection ??\n (state.writerProjection?.documentId === synced.plan.documentId\n ? state.writerProjection\n : null);\n return writerProjection &&\n documentWriterProjectionMatchesSyncResponse(writerProjection, synced)\n ? writerProjection\n : null;\n}\n\n/**\n * Durable-history tail: append pulled updates BEFORE the record persist so\n * the tail stays a superset of what the snapshot covers (duplicates are\n * idempotent by op identity; a crash between the writes can only leave the\n * safe superset).\n */\nfunction pulledHistoryUpdates(synced: DocumentSyncAttempt[\"synced\"]): string[] {\n return synced.decryptedUpdates.map((update) =>\n bytesToBase64(update.updateData),\n );\n}\n\n/**\n * The frontier a finalize persist may publish: the stored frontier advanced\n * by exactly the pulled updates just appended to the durable tail — never the\n * live document's version, which can transiently include an in-flight local\n * edit whose durable row has not landed yet.\n */\nfunction coveredSyncFrontier(\n state: DocumentStoreState,\n currentRecord: DocumentRecord,\n synced: DocumentSyncAttempt[\"synced\"],\n): { snapshotEndVersion: string } | Record<string, never> {\n if (synced.decryptedUpdates.length === 0) {\n return {};\n }\n const liveFrontier = (state.record ?? currentRecord).snapshotEndVersion;\n return {\n snapshotEndVersion: mergeVersionVectors([\n ...(liveFrontier.length > 0 ? [liveFrontier] : []),\n ...synced.decryptedUpdates.map(\n (update) =>\n getImportBlobMetadata(update.updateData).partialEndVersionVector,\n ),\n ]),\n };\n}\n\nfunction documentSyncSaveOptions(\n syncAttempt: DocumentSyncAttempt,\n): SaveDocumentRecordOptions {\n return {\n acceptedPendingUpdateIds: syncAttempt.synced.settledPendingUpdateIds,\n clearSyncFailure: shouldClearDocumentSyncFailureAfterPass(\n syncAttempt.synced,\n syncAttempt.outgoingUpdateCount,\n ),\n expectedSyncState: {\n pullContinuation: syncAttempt.consumedPullContinuation,\n record: syncAttempt.requestRecord,\n },\n historyUpdateOrigin: \"remote\",\n historyUpdates: pulledHistoryUpdates(syncAttempt.synced),\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n };\n}\n\nasync function persistSyncedDocument(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n generation: DocumentStoreSyncGeneration,\n) {\n const { synced } = syncAttempt;\n const updates = synced.decryptedUpdates;\n const candidate = currentDoc.fork();\n const previousDocumentId = state.record?.documentId ?? null;\n const options = documentSyncSaveOptions(syncAttempt);\n const isCurrent = () =>\n isDocumentStoreSyncGenerationCurrent(state, generation);\n try {\n importSyncedDocumentUpdates(candidate, updates);\n if (state.pendingBaseVersion === null) {\n throw new Error(\"Document sync requires an initialized pending base\");\n }\n const persisted = await saveDocumentRecord(\n state,\n candidate,\n {\n ...synced.persistedState,\n lastCommitLsn:\n synced.response.commitLsn ?? currentRecord.lastCommitLsn ?? null,\n pullContinuation: readPullContinuation(synced.response),\n ...coveredSyncFrontier(state, currentRecord, synced),\n },\n {\n ...options,\n pendingBaseVersionOverride: extendDocumentVersionCoverage({\n baseVersion: state.pendingBaseVersion,\n documentVersion: encodeVersionVector(candidate),\n spans: updates,\n }),\n },\n generation,\n );\n if (\n persisted &&\n isCurrent() &&\n !persisted.pullContinuationSuperseded &&\n !persisted.syncIdentitySuperseded\n ) {\n // Publish a remote edit only once its history and continuation commit.\n // Importing earlier lets a losing CAS expose text that the next local\n // write authors against an older, reloaded CRDT history.\n // The durable CAS already checked the request's complete context. The\n // successful row is now live, so publication uses that committed context\n // (which may contain refreshed keying metadata) and the same generation.\n applyIncomingSyncedUpdates(\n state,\n currentDoc,\n persisted.record,\n syncAttempt,\n generation,\n );\n }\n return await publishPersistedDocument(\n state,\n currentDoc,\n persisted,\n previousDocumentId,\n options,\n isCurrent,\n );\n } finally {\n candidate.free();\n }\n}\n\nexport function shouldReArmDocumentSync(\n state: DocumentStoreState,\n syncAttempt: DocumentSyncAttempt,\n): boolean {\n const { synced } = syncAttempt;\n const shouldReArmOutgoing = settleOutgoingPassAndDecideReArm(state, {\n exhaustedPendingUpdateCount: synced.exhaustedPendingUpdateCount,\n outgoingUpdateCount: syncAttempt.outgoingUpdateCount,\n rekeyedUpdateCount: synced.rekeyedPendingUpdateIds.length,\n settledUpdateCount: synced.settledPendingUpdateIds.length,\n acceptedRecoveryBaseline: synced.acceptedRecoveryBaseline,\n });\n return (\n synced.hasDeferredPendingUpdates ||\n synced.hasIncompletePull ||\n shouldReArmOutgoing\n );\n}\n\nexport async function finalizeDocumentSync(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n consumedRemoteUpdateSignalSeq: number,\n generation: DocumentStoreSyncGeneration,\n sentUpdateIds: readonly string[],\n wasRemoteProbe: boolean,\n): Promise<DocumentRecord> {\n const { synced } = syncAttempt;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? currentRecord;\n }\n\n // The sent IDs were pre-registered as self-authored before the network call so\n // the redis echo can never beat us. Reconcile against what the server actually\n // accepted: an ID we sent but the server did not accept will never be echoed,\n // so drop it to keep locallyAcceptedUpdateIds from leaking. Accepted IDs (a\n // subset of what we sent) stay registered until their echo consumes them.\n discardUnacceptedPreRegisteredUpdateIds(\n state,\n sentUpdateIds,\n synced.response.acceptedOutgoingUpdateIds,\n );\n // Persist on the identity-write chain: synced.persistedState carries this\n // pass's documentId, so it would clobber a relink that landed mid-pass. If\n // the identity moved, the response describes the OLD document — skip every\n // response-derived in-memory mutation and let the new identity's own sync\n // pass take over.\n let responseApplied = false;\n const { record: nextRecord } = await chainIdentityWrite(state, async () => {\n const liveRecord = state.record;\n if (\n !isDocumentStoreSyncGenerationCurrent(state, generation) ||\n !documentSyncContextMatches(\n liveRecord,\n currentRecord,\n synced.plan.documentId,\n )\n ) {\n return { record: liveRecord ?? currentRecord };\n }\n\n installDocumentWriterProjection(\n state,\n resolveSyncedDocumentWriterProjection(state, synced),\n syncAttempt.writerProjectionGeneration,\n );\n const persisted = await persistSyncedDocument(\n state,\n currentDoc,\n currentRecord,\n syncAttempt,\n generation,\n );\n if (\n !persisted ||\n !isDocumentStoreSyncGenerationCurrent(state, generation)\n ) {\n return { record: state.record ?? currentRecord };\n }\n\n state.pullContinuation = persisted.record.pullContinuation ?? null;\n if (persisted.pullContinuationSuperseded) {\n state.writerProjection = null;\n }\n // A CAS loss means neither this response's acknowledgements nor its\n // continuation were committed. Keep the pass unapplied so its signals and\n // accepted-id registrations cannot be cleared without a follow-up.\n responseApplied = !persisted.pullContinuationSuperseded;\n return persisted;\n });\n if (!responseApplied) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return nextRecord;\n }\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n\n // A bounded pull request owns the whole page chain. Completing the signal on\n // an intermediate page would let a failed/null continuation pass report the\n // original request as successful even though the server frontier was never\n // drained.\n if (!synced.hasIncompletePull) {\n clearConsumedRemoteUpdateSignal(state, consumedRemoteUpdateSignalSeq);\n }\n\n if (shouldReArmDocumentSync(state, syncAttempt)) {\n requestDocumentStoreSync(state);\n }\n\n await hydrateAttachmentBlobs(state, currentDoc, nextRecord, generation);\n logApplied(state, currentDoc, synced.decryptedUpdates.length, wasRemoteProbe);\n return nextRecord;\n}\n"]}
1
+ {"version":3,"file":"syncFinalize.js","sourceRoot":"","sources":["syncFinalize.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n emptyVersionVector,\n encodeVersionVector,\n getImportBlobMetadata,\n mergeVersionVectors,\n} from \"@tearleads/loro\";\nimport { readPullContinuation } from \"../../../data/documents/shared/syncPagination\";\nimport {\n type DocumentRecord,\n settleOutgoingPassAndDecideReArm,\n shouldClearDocumentSyncFailureAfterPass,\n} from \"../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../registry\";\nimport { hydrateAttachmentBlobs } from \"./attachmentHydration\";\nimport { chainIdentityWrite } from \"./identityWriteChain\";\nimport { publishPersistedDocument, saveDocumentRecord } from \"./persistence\";\nimport { logRevalidationApplied as logApplied } from \"./remoteRevalidationTelemetry\";\nimport type {\n DocumentState,\n DocumentStoreState,\n DocumentSyncAttempt,\n SaveDocumentRecordOptions,\n} from \"./state\";\nimport {\n discardPreRegisteredUpdateIds,\n discardUnacceptedPreRegisteredUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport {\n type DocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"./syncGeneration\";\nimport { clearConsumedRemoteUpdateSignal } from \"./syncRemoteSignals\";\nimport {\n applyIncomingSyncedUpdates,\n documentSyncContextMatches,\n importSyncedDocumentUpdates,\n} from \"./syncUpdateImport\";\nimport { extendDocumentVersionCoverage } from \"./versionCoverage\";\nimport { installDocumentWriterProjection } from \"./writerProjectionGeneration\";\n\nfunction documentWriterProjectionMatchesSyncResponse(\n writerProjection: NonNullable<\n DocumentSyncAttempt[\"synced\"][\"writerProjection\"]\n >,\n synced: DocumentSyncAttempt[\"synced\"],\n): boolean {\n return (\n writerProjection.contentKeyBundle.contentKeyEpoch ===\n synced.response.contentKeyBundle.contentKeyEpoch &&\n writerProjection.contentKeyBundle.linkSetManifestHash ===\n synced.response.contentKeyBundle.linkSetManifestHash &&\n writerProjection.contentKeyBundle.targetHash ===\n synced.response.contentKeyBundle.targetHash &&\n writerProjection.documentKekTargets.linkSetManifestHash ===\n synced.response.documentKekTargets.linkSetManifestHash &&\n writerProjection.documentKekTargets.documentKeyTargetHash ===\n synced.response.documentKekTargets.documentKeyTargetHash\n );\n}\n\nfunction resolveSyncedDocumentWriterProjection(\n state: DocumentStoreState,\n synced: DocumentSyncAttempt[\"synced\"],\n) {\n const writerProjection =\n synced.writerProjection ??\n (state.writerProjection?.documentId === synced.plan.documentId\n ? state.writerProjection\n : null);\n return writerProjection &&\n documentWriterProjectionMatchesSyncResponse(writerProjection, synced)\n ? writerProjection\n : null;\n}\n\n/**\n * Durable-history tail: append pulled updates BEFORE the record persist so\n * the tail stays a superset of what the snapshot covers (duplicates are\n * idempotent by op identity; a crash between the writes can only leave the\n * safe superset).\n */\nfunction pulledHistoryUpdates(synced: DocumentSyncAttempt[\"synced\"]): string[] {\n return synced.decryptedUpdates.map((update) =>\n bytesToBase64(update.updateData),\n );\n}\n\n/**\n * The frontier a finalize persist may publish: the stored frontier advanced\n * by exactly the pulled updates just appended to the durable tail — never the\n * live document's version, which can transiently include an in-flight local\n * edit whose durable row has not landed yet.\n */\nfunction coveredSyncFrontier(\n state: DocumentStoreState,\n currentRecord: DocumentRecord,\n synced: DocumentSyncAttempt[\"synced\"],\n): { snapshotEndVersion: string } | Record<string, never> {\n const liveFrontier = (state.record ?? currentRecord).snapshotEndVersion;\n if (synced.decryptedUpdates.length === 0) {\n // A completed empty pull distinguishes a real blank note from discovery.\n // An intermediate page cannot establish that no content exists yet.\n return liveFrontier === \"\" && !synced.hasIncompletePull\n ? { snapshotEndVersion: emptyVersionVector() }\n : {};\n }\n return {\n snapshotEndVersion: mergeVersionVectors([\n ...(liveFrontier.length > 0 ? [liveFrontier] : []),\n ...synced.decryptedUpdates.map(\n (update) =>\n getImportBlobMetadata(update.updateData).partialEndVersionVector,\n ),\n ]),\n };\n}\n\nfunction documentSyncSaveOptions(\n syncAttempt: DocumentSyncAttempt,\n): SaveDocumentRecordOptions {\n return {\n acceptedPendingUpdateIds: syncAttempt.synced.settledPendingUpdateIds,\n clearSyncFailure: shouldClearDocumentSyncFailureAfterPass(\n syncAttempt.synced,\n syncAttempt.outgoingUpdateCount,\n ),\n expectedSyncState: {\n pullContinuation: syncAttempt.consumedPullContinuation,\n record: syncAttempt.requestRecord,\n },\n historyUpdateOrigin: \"remote\",\n historyUpdates: pulledHistoryUpdates(syncAttempt.synced),\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n };\n}\n\nasync function persistSyncedDocument(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n generation: DocumentStoreSyncGeneration,\n) {\n const { synced } = syncAttempt;\n const updates = synced.decryptedUpdates;\n const candidate = currentDoc.fork();\n const previousDocumentId = state.record?.documentId ?? null;\n const options = documentSyncSaveOptions(syncAttempt);\n const isCurrent = () =>\n isDocumentStoreSyncGenerationCurrent(state, generation);\n try {\n importSyncedDocumentUpdates(candidate, updates);\n if (state.pendingBaseVersion === null) {\n throw new Error(\"Document sync requires an initialized pending base\");\n }\n const persisted = await saveDocumentRecord(\n state,\n candidate,\n {\n ...synced.persistedState,\n lastCommitLsn:\n synced.response.commitLsn ?? currentRecord.lastCommitLsn ?? null,\n pullContinuation: readPullContinuation(synced.response),\n ...coveredSyncFrontier(state, currentRecord, synced),\n },\n {\n ...options,\n pendingBaseVersionOverride: extendDocumentVersionCoverage({\n baseVersion: state.pendingBaseVersion,\n documentVersion: encodeVersionVector(candidate),\n spans: updates,\n }),\n },\n generation,\n );\n if (\n persisted &&\n isCurrent() &&\n !persisted.pullContinuationSuperseded &&\n !persisted.syncIdentitySuperseded\n ) {\n // Publish a remote edit only once its history and continuation commit.\n // Importing earlier lets a losing CAS expose text that the next local\n // write authors against an older, reloaded CRDT history.\n // The durable CAS already checked the request's complete context. The\n // successful row is now live, so publication uses that committed context\n // (which may contain refreshed keying metadata) and the same generation.\n applyIncomingSyncedUpdates(\n state,\n currentDoc,\n persisted.record,\n syncAttempt,\n generation,\n );\n }\n return await publishPersistedDocument(\n state,\n currentDoc,\n persisted,\n previousDocumentId,\n options,\n isCurrent,\n );\n } finally {\n candidate.free();\n }\n}\n\nexport function shouldReArmDocumentSync(\n state: DocumentStoreState,\n syncAttempt: DocumentSyncAttempt,\n): boolean {\n const { synced } = syncAttempt;\n const shouldReArmOutgoing = settleOutgoingPassAndDecideReArm(state, {\n exhaustedPendingUpdateCount: synced.exhaustedPendingUpdateCount,\n outgoingUpdateCount: syncAttempt.outgoingUpdateCount,\n rekeyedUpdateCount: synced.rekeyedPendingUpdateIds.length,\n settledUpdateCount: synced.settledPendingUpdateIds.length,\n acceptedRecoveryBaseline: synced.acceptedRecoveryBaseline,\n });\n return (\n synced.hasDeferredPendingUpdates ||\n synced.hasIncompletePull ||\n shouldReArmOutgoing\n );\n}\n\nexport async function finalizeDocumentSync(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n consumedRemoteUpdateSignalSeq: number,\n generation: DocumentStoreSyncGeneration,\n sentUpdateIds: readonly string[],\n wasRemoteProbe: boolean,\n): Promise<DocumentRecord> {\n const { synced } = syncAttempt;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? currentRecord;\n }\n\n // The sent IDs were pre-registered as self-authored before the network call so\n // the redis echo can never beat us. Reconcile against what the server actually\n // accepted: an ID we sent but the server did not accept will never be echoed,\n // so drop it to keep locallyAcceptedUpdateIds from leaking. Accepted IDs (a\n // subset of what we sent) stay registered until their echo consumes them.\n discardUnacceptedPreRegisteredUpdateIds(\n state,\n sentUpdateIds,\n synced.response.acceptedOutgoingUpdateIds,\n );\n // Persist on the identity-write chain: synced.persistedState carries this\n // pass's documentId, so it would clobber a relink that landed mid-pass. If\n // the identity moved, the response describes the OLD document — skip every\n // response-derived in-memory mutation and let the new identity's own sync\n // pass take over.\n let responseApplied = false;\n const { record: nextRecord } = await chainIdentityWrite(state, async () => {\n const liveRecord = state.record;\n if (\n !isDocumentStoreSyncGenerationCurrent(state, generation) ||\n !documentSyncContextMatches(\n liveRecord,\n currentRecord,\n synced.plan.documentId,\n )\n ) {\n return { record: liveRecord ?? currentRecord };\n }\n\n installDocumentWriterProjection(\n state,\n resolveSyncedDocumentWriterProjection(state, synced),\n syncAttempt.writerProjectionGeneration,\n );\n const persisted = await persistSyncedDocument(\n state,\n currentDoc,\n currentRecord,\n syncAttempt,\n generation,\n );\n if (\n !persisted ||\n !isDocumentStoreSyncGenerationCurrent(state, generation)\n ) {\n return { record: state.record ?? currentRecord };\n }\n\n state.pullContinuation = persisted.record.pullContinuation ?? null;\n if (persisted.pullContinuationSuperseded) {\n state.writerProjection = null;\n }\n // A CAS loss means neither this response's acknowledgements nor its\n // continuation were committed. Keep the pass unapplied so its signals and\n // accepted-id registrations cannot be cleared without a follow-up.\n responseApplied = !persisted.pullContinuationSuperseded;\n return persisted;\n });\n if (!responseApplied) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return nextRecord;\n }\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n\n // A bounded pull request owns the whole page chain. Completing the signal on\n // an intermediate page would let a failed/null continuation pass report the\n // original request as successful even though the server frontier was never\n // drained.\n if (!synced.hasIncompletePull) {\n clearConsumedRemoteUpdateSignal(state, consumedRemoteUpdateSignalSeq);\n }\n\n if (shouldReArmDocumentSync(state, syncAttempt)) {\n requestDocumentStoreSync(state);\n }\n\n await hydrateAttachmentBlobs(state, currentDoc, nextRecord, generation);\n logApplied(state, currentDoc, synced.decryptedUpdates.length, wasRemoteProbe);\n return nextRecord;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import { emptyVersionVector } from "../../../internal/loro/index.js";
2
+ // Discovery persists a shell before its first content pull. Keep those rows
3
+ // available to sync, but out of Explorer's selectable, paginated projections.
4
+ export function emptyContentFrontierSql(alias) {
5
+ return `(${alias}.snapshot_end_version = '' OR (${alias}.app_kind = 'container-metadata' AND ${alias}.snapshot_end_version = '${emptyVersionVector()}'))`;
6
+ }
7
+ export function hydratedProjectionSql(localId, appKind) {
8
+ return `NOT EXISTS (
9
+ SELECT 1 FROM documents hydration
10
+ WHERE hydration.app_kind = '${appKind}'
11
+ AND hydration.local_id = ${localId}
12
+ AND hydration.document_id IS NOT NULL
13
+ AND ${emptyContentFrontierSql("hydration")}
14
+ )`;
15
+ }
16
+ //# sourceMappingURL=hydrationSql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrationSql.js","sourceRoot":"","sources":["hydrationSql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,4EAA4E;AAC5E,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,OAAO,IAAI,KAAK,kCAAkC,KAAK,wCAAwC,KAAK,4BAA4B,kBAAkB,EAAE,KAAK,CAAC;AAC5J,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAe,EACf,OAA2C;IAE3C,OAAO;;kCAEyB,OAAO;iCACR,OAAO;;YAE5B,uBAAuB,CAAC,WAAW,CAAC;IAC5C,CAAC;AACL,CAAC","sourcesContent":["import { emptyVersionVector } from \"@tearleads/loro\";\n\n// Discovery persists a shell before its first content pull. Keep those rows\n// available to sync, but out of Explorer's selectable, paginated projections.\nexport function emptyContentFrontierSql(alias: string): string {\n return `(${alias}.snapshot_end_version = '' OR (${alias}.app_kind = 'container-metadata' AND ${alias}.snapshot_end_version = '${emptyVersionVector()}'))`;\n}\n\nexport function hydratedProjectionSql(\n localId: string,\n appKind: \"documents\" | \"container-metadata\",\n): string {\n return `NOT EXISTS (\n SELECT 1 FROM documents hydration\n WHERE hydration.app_kind = '${appKind}'\n AND hydration.local_id = ${localId}\n AND hydration.document_id IS NOT NULL\n AND ${emptyContentFrontierSql(\"hydration\")}\n )`;\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { getOrphanedDocumentWhereSql } from "../orphanedDocumentSql.js";
2
+ import { hydratedProjectionSql } from "./hydrationSql.js";
2
3
  // Keep each IN clause below SQLite's historical 999 bind-parameter limit.
3
4
  const CONTAINER_DOCUMENT_SQL_ID_BATCH_SIZE = 500;
4
5
  const MAX_CONTAINER_ITEM_WINDOW_LIMIT = 200;
@@ -140,6 +141,7 @@ export function getContainerContentsContainerItemsBaseSql(visibleSystemSlotCount
140
141
  LEFT JOIN pending_container_create_intents create_intent
141
142
  ON create_intent.container_id = c.id
142
143
  WHERE c.parent_id = ?
144
+ AND ${hydratedProjectionSql("c.id", "container-metadata")}
143
145
  AND ${getContainerContentsContainerSystemSlotFilter({
144
146
  visibleForeignSystemContainerNameCount,
145
147
  visibleSystemSlotCount,
@@ -171,7 +173,8 @@ export function getContainerContentsContainerItemsBaseSql(visibleSystemSlotCount
171
173
  ON document_updates.local_id = d.local_id
172
174
  LEFT JOIN document_pending_attachment_counts document_attachments
173
175
  ON document_attachments.local_id = d.local_id
174
- WHERE d.container_id = ?${getHeldPlacementExclusionSql("d.document_id", "d.container_id")}
176
+ WHERE ${hydratedProjectionSql("d.local_id", "documents")}
177
+ AND d.container_id = ?${getHeldPlacementExclusionSql("d.document_id", "d.container_id")}
175
178
 
176
179
  UNION ALL
177
180
 
@@ -200,7 +203,8 @@ export function getContainerContentsContainerItemsBaseSql(visibleSystemSlotCount
200
203
  ON document_updates.local_id = d.local_id
201
204
  LEFT JOIN document_pending_attachment_counts document_attachments
202
205
  ON document_attachments.local_id = d.local_id
203
- WHERE linked.container_id = ?
206
+ WHERE ${hydratedProjectionSql("d.local_id", "documents")}
207
+ AND linked.container_id = ?
204
208
  AND (
205
209
  d.container_id IS NULL
206
210
  OR d.container_id != linked.container_id
@@ -229,7 +233,8 @@ export function getContainerContentsDocumentRowsBaseSql() {
229
233
  ON document_updates.local_id = d.local_id
230
234
  LEFT JOIN document_pending_attachment_counts document_attachments
231
235
  ON document_attachments.local_id = d.local_id
232
- WHERE d.container_id = ?${getHeldPlacementExclusionSql("d.document_id", "d.container_id")}
236
+ WHERE ${hydratedProjectionSql("d.local_id", "documents")}
237
+ AND d.container_id = ?${getHeldPlacementExclusionSql("d.document_id", "d.container_id")}
233
238
 
234
239
  UNION ALL
235
240
 
@@ -249,7 +254,8 @@ export function getContainerContentsDocumentRowsBaseSql() {
249
254
  ON document_updates.local_id = d.local_id
250
255
  LEFT JOIN document_pending_attachment_counts document_attachments
251
256
  ON document_attachments.local_id = d.local_id
252
- WHERE linked.container_id = ?
257
+ WHERE ${hydratedProjectionSql("d.local_id", "documents")}
258
+ AND linked.container_id = ?
253
259
  AND (
254
260
  d.container_id IS NULL
255
261
  OR d.container_id != linked.container_id
@@ -287,7 +293,8 @@ export function getOrphanedDocumentItemsBaseSql() {
287
293
  ON document_updates.local_id = d.local_id
288
294
  LEFT JOIN document_pending_attachment_counts document_attachments
289
295
  ON document_attachments.local_id = d.local_id
290
- WHERE ${getOrphanedDocumentWhereSql({
296
+ WHERE ${hydratedProjectionSql("d.local_id", "documents")}
297
+ AND ${getOrphanedDocumentWhereSql({
291
298
  documentIdSql: "d.document_id",
292
299
  projectionAlias: "d",
293
300
  })}
@@ -314,7 +321,8 @@ export function getOrphanedDocumentRowsBaseSql() {
314
321
  ON document_updates.local_id = d.local_id
315
322
  LEFT JOIN document_pending_attachment_counts document_attachments
316
323
  ON document_attachments.local_id = d.local_id
317
- WHERE ${getOrphanedDocumentWhereSql({
324
+ WHERE ${hydratedProjectionSql("d.local_id", "documents")}
325
+ AND ${getOrphanedDocumentWhereSql({
318
326
  documentIdSql: "d.document_id",
319
327
  projectionAlias: "d",
320
328
  })}
@@ -324,7 +332,8 @@ export function getOrphanedDocumentExistsSql() {
324
332
  return `
325
333
  SELECT 1
326
334
  FROM document_projection d
327
- WHERE ${getOrphanedDocumentWhereSql({
335
+ WHERE ${hydratedProjectionSql("d.local_id", "documents")}
336
+ AND ${getOrphanedDocumentWhereSql({
328
337
  documentIdSql: "d.document_id",
329
338
  projectionAlias: "d",
330
339
  })}