@tearleads/client-sdk 0.1.69 → 0.1.72

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 (102) hide show
  1. package/data/shared/userTiming.js +42 -0
  2. package/data/shared/userTiming.js.map +1 -0
  3. package/data/sqlite/sqlExec.js +27 -3
  4. package/data/sqlite/sqlExec.js.map +1 -1
  5. package/data/sync/coordinatorLaneRun.js +29 -6
  6. package/data/sync/coordinatorLaneRun.js.map +1 -1
  7. package/data/sync/coordinatorState.d.ts +3 -1
  8. package/data/sync/coordinatorState.js +1 -0
  9. package/data/sync/coordinatorState.js.map +1 -1
  10. package/data/sync/syncTelemetry.d.ts +15 -0
  11. package/data/sync/syncTelemetry.js +10 -0
  12. package/data/sync/syncTelemetry.js.map +1 -1
  13. package/data/sync/uploadLane.js +20 -3
  14. package/data/sync/uploadLane.js.map +1 -1
  15. package/internal/api-client/ApiClient.d.ts +73 -3
  16. package/internal/api-client/apiRequestMetrics.d.ts +18 -4
  17. package/internal/api-client/apiRequestMetrics.js +55 -5
  18. package/internal/api-client/apiRequestMetrics.js.map +1 -1
  19. package/internal/api-client/durationSampleWindow.d.ts +26 -0
  20. package/internal/api-client/durationSampleWindow.js +42 -0
  21. package/internal/api-client/durationSampleWindow.js.map +1 -0
  22. package/internal/api-client/measureApiRequest.js +9 -4
  23. package/internal/api-client/measureApiRequest.js.map +1 -1
  24. package/internal/api-client/serverTiming.d.ts +12 -0
  25. package/internal/api-client/serverTiming.js +49 -0
  26. package/internal/api-client/serverTiming.js.map +1 -0
  27. package/internal/validators/documentCreateSeedRefinements.js +9 -0
  28. package/internal/validators/documentCreateSeedRefinements.js.map +1 -0
  29. package/internal/validators/operation/auth.d.ts +120 -0
  30. package/internal/validators/operation/containerMutations.d.ts +355 -0
  31. package/internal/validators/operation/containerMutations.js +7 -1
  32. package/internal/validators/operation/containerMutations.js.map +1 -1
  33. package/internal/validators/operation/documentMutations.d.ts +356 -0
  34. package/internal/validators/operation/documentMutations.js +6 -1
  35. package/internal/validators/operation/documentMutations.js.map +1 -1
  36. package/internal/validators/operation/documentSync.d.ts +9 -9
  37. package/internal/validators/operation/organizations.d.ts +120 -0
  38. package/internal/validators/request/containerMetadata.d.ts +313 -0
  39. package/internal/validators/request/containerMetadata.js +20 -3
  40. package/internal/validators/request/containerMetadata.js.map +1 -1
  41. package/internal/validators/request/document.d.ts +571 -0
  42. package/internal/validators/request/document.js +19 -1
  43. package/internal/validators/request/document.js.map +1 -1
  44. package/internal/validators/request/documentCreateSeed.js +35 -0
  45. package/internal/validators/request/documentCreateSeed.js.map +1 -0
  46. package/internal/validators/request/organizationProvisioning.js +9 -22
  47. package/internal/validators/request/organizationProvisioning.js.map +1 -1
  48. package/internal/validators/response/containerMetadata.d.ts +20 -0
  49. package/internal/validators/response/documentMutation.d.ts +43 -0
  50. package/internal/validators/response/documentMutation.js +12 -1
  51. package/internal/validators/response/documentMutation.js.map +1 -1
  52. package/internal/validators/response/documentSyncSchema.d.ts +13 -9
  53. package/internal/validators/response/documentSyncSchema.js +23 -18
  54. package/internal/validators/response/documentSyncSchema.js.map +1 -1
  55. package/internal/validators/response/index.d.ts +1 -1
  56. package/internal/validators/response/index.js.map +1 -1
  57. package/internal/validators/response/organizationProvisioning.d.ts +350 -0
  58. package/internal/validators/response/registration.d.ts +120 -0
  59. package/package.json +1 -1
  60. package/stores/container-contents/containerState/containerStatePersistence.js +2 -0
  61. package/stores/container-contents/containerState/containerStatePersistence.js.map +1 -1
  62. package/stores/container-contents/remoteEvents/remoteEventSync.js +1 -1
  63. package/stores/container-contents/remoteEvents/remoteEventSync.js.map +1 -1
  64. package/stores/container-contents/state.js +2 -0
  65. package/stores/container-contents/state.js.map +1 -1
  66. package/stores/container-contents/syncAgent/syncAgentTypes.d.ts +5 -0
  67. package/stores/container-contents/syncAgent/syncAgentTypes.js.map +1 -1
  68. package/stores/documents/documentStore/sync/createdDocumentPersistence.js +71 -0
  69. package/stores/documents/documentStore/sync/createdDocumentPersistence.js.map +1 -0
  70. package/stores/documents/documentStore/sync/index.js +13 -2
  71. package/stores/documents/documentStore/sync/index.js.map +1 -1
  72. package/stores/documents/documentStore/sync/syncRemoteSignals.js +21 -3
  73. package/stores/documents/documentStore/sync/syncRemoteSignals.js.map +1 -1
  74. package/stores/documents/documentStore/sync/syncSeededCreate.js +50 -0
  75. package/stores/documents/documentStore/sync/syncSeededCreate.js.map +1 -0
  76. package/stores/documents/documentStore/sync/syncShared.js +16 -8
  77. package/stores/documents/documentStore/sync/syncShared.js.map +1 -1
  78. package/workflows/container-contents/container-state/create/createIntentSeed.js +60 -0
  79. package/workflows/container-contents/container-state/create/createIntentSeed.js.map +1 -0
  80. package/workflows/container-contents/container-state/create/createIntentSync.js +18 -19
  81. package/workflows/container-contents/container-state/create/createIntentSync.js.map +1 -1
  82. package/workflows/container-contents/container-state/create/createWithMetadata.js +43 -6
  83. package/workflows/container-contents/container-state/create/createWithMetadata.js.map +1 -1
  84. package/workflows/container-contents/container-state/create/createWithMetadataPlan.js +5 -1
  85. package/workflows/container-contents/container-state/create/createWithMetadataPlan.js.map +1 -1
  86. package/workflows/container-contents/container-state/remote.js +15 -0
  87. package/workflows/container-contents/container-state/remote.js.map +1 -1
  88. package/workflows/container-contents/container-state/types.js.map +1 -1
  89. package/workflows/container-contents/metadata/metadataEvents.d.ts +7 -1
  90. package/workflows/container-contents/metadata/metadataEvents.js +8 -2
  91. package/workflows/container-contents/metadata/metadataEvents.js.map +1 -1
  92. package/workflows/container-contents/remoteHydration/types.d.ts +3 -0
  93. package/workflows/container-contents/remoteHydration/types.js.map +1 -1
  94. package/workflows/documents/create/index.d.ts +7 -0
  95. package/workflows/documents/create/index.js +40 -2
  96. package/workflows/documents/create/index.js.map +1 -1
  97. package/workflows/documents/index.d.ts +1 -0
  98. package/workflows/documents/index.js +1 -0
  99. package/workflows/documents/index.js.map +1 -1
  100. package/workflows/documents/sync/initialSync.d.ts +39 -0
  101. package/workflows/documents/sync/initialSync.js +39 -6
  102. package/workflows/documents/sync/initialSync.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"metadataEvents.js","sourceRoot":"","sources":["metadataEvents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AAGpF,MAAM,UAAU,uCAAuC,CACrD,MAA8B,EAC9B,cAAwE,EACxE,wBAAsC;IAEtC,0EAA0E;IAC1E,mCAAmC;IACnC,OAAO,CACL,sCAAsC,CACpC,MAAM,EACN,cAAc,EACd,wBAAwB,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,SAAS,CACzE,CAAC,MAAM,GAAG,CAAC,CACb,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,SAAS,4BAA4B,CACnC,KAAoD,EACpD,wBAAiD;IAEjD,IACE,CAAC,wBAAwB;QACzB,CAAC,KAAK,CAAC,SAAS;QAChB,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAC5B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAC9B,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACvC,IAAI,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3C,wBAAwB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,iBAAiB,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,sCAAsC,CACpD,MAA8B,EAC9B,cAAwE,EACxE,wBAAsC;IAEtC,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9C,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,IAAI,OAAO,aAAa,CAAC,MAAM,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YACxD,mBAAmB,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,IAAI,mBAAmB,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE9C,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC3C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IACE,CAAC,4BAA4B,CAAC,KAAK,CAAC;YACpC,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAC1C,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,4BAA4B,CAAC,KAAK,EAAE,wBAAwB,CAAC,EAAE,CAAC;YACnE,SAAS;QACX,CAAC;QACD,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AACtC,CAAC","sourcesContent":["import { isDocumentUpdateCreatedEvent } from \"../../../data/documents/documentSync\";\nimport type { DocumentRecord } from \"../../../data/sqlite/documentPersistence\";\n\nexport function hasContainerMetadataDocumentUpdateEvent(\n events: ReadonlyArray<unknown>,\n metadataStates: Iterable<{ record: Pick<DocumentRecord, \"documentId\"> }>,\n locallyAcceptedUpdateIds?: Set<string>,\n): boolean {\n // A boolean predicate must not consume self-echo ids before the real list\n // pass classifies the same events.\n return (\n listContainerMetadataDocumentUpdateIds(\n events,\n metadataStates,\n locallyAcceptedUpdateIds ? new Set(locallyAcceptedUpdateIds) : undefined,\n ).length > 0\n );\n}\n\n/** Consume local ids and report whether an event still contains a peer id. */\nfunction metadataEventHasRemoteUpdate(\n event: { updateIds?: readonly string[] | undefined },\n locallyAcceptedUpdateIds: Set<string> | undefined,\n): boolean {\n if (\n !locallyAcceptedUpdateIds ||\n !event.updateIds ||\n event.updateIds.length === 0\n ) {\n return true;\n }\n\n let remoteUpdateFound = false;\n for (const updateId of event.updateIds) {\n if (locallyAcceptedUpdateIds.has(updateId)) {\n locallyAcceptedUpdateIds.delete(updateId);\n } else {\n remoteUpdateFound = true;\n }\n }\n return remoteUpdateFound;\n}\n\nexport function listContainerMetadataDocumentUpdateIds(\n events: ReadonlyArray<unknown>,\n metadataStates: Iterable<{ record: Pick<DocumentRecord, \"documentId\"> }>,\n locallyAcceptedUpdateIds?: Set<string>,\n): string[] {\n const metadataDocumentIds = new Set<string>();\n for (const metadataState of metadataStates) {\n if (typeof metadataState.record.documentId === \"string\") {\n metadataDocumentIds.add(metadataState.record.documentId);\n }\n }\n if (metadataDocumentIds.size === 0) return [];\n\n const eventDocumentIds = new Set<string>();\n for (const event of events) {\n if (\n !isDocumentUpdateCreatedEvent(event) ||\n !metadataDocumentIds.has(event.documentId)\n ) {\n continue;\n }\n if (!metadataEventHasRemoteUpdate(event, locallyAcceptedUpdateIds)) {\n continue;\n }\n eventDocumentIds.add(event.documentId);\n }\n\n return Array.from(eventDocumentIds);\n}\n"]}
1
+ {"version":3,"file":"metadataEvents.js","sourceRoot":"","sources":["metadataEvents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AAGpF,MAAM,UAAU,uCAAuC,CACrD,MAA8B,EAC9B,cAAwE,EACxE,wBAAsC;IAEtC,0EAA0E;IAC1E,mCAAmC;IACnC,OAAO,CACL,sCAAsC,CACpC,MAAM,EACN,cAAc,EACd,wBAAwB,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,SAAS,CACzE,CAAC,MAAM,GAAG,CAAC,CACb,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,SAAS,4BAA4B,CACnC,KAAoD,EACpD,wBAAiD;IAEjD,IACE,CAAC,wBAAwB;QACzB,CAAC,KAAK,CAAC,SAAS;QAChB,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAC5B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAC9B,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACvC,IAAI,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3C,wBAAwB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,iBAAiB,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sCAAsC,CACpD,MAA8B,EAC9B,cAAwE,EACxE,wBAAsC,EACtC,kBAAqC;IAErC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAS,kBAAkB,CAAC,CAAC;IAChE,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,IAAI,OAAO,aAAa,CAAC,MAAM,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YACxD,mBAAmB,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,IAAI,mBAAmB,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE9C,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC3C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IACE,CAAC,4BAA4B,CAAC,KAAK,CAAC;YACpC,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAC1C,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,4BAA4B,CAAC,KAAK,EAAE,wBAAwB,CAAC,EAAE,CAAC;YACnE,SAAS;QACX,CAAC;QACD,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AACtC,CAAC","sourcesContent":["import { isDocumentUpdateCreatedEvent } from \"../../../data/documents/documentSync\";\nimport type { DocumentRecord } from \"../../../data/sqlite/documentPersistence\";\n\nexport function hasContainerMetadataDocumentUpdateEvent(\n events: ReadonlyArray<unknown>,\n metadataStates: Iterable<{ record: Pick<DocumentRecord, \"documentId\"> }>,\n locallyAcceptedUpdateIds?: Set<string>,\n): boolean {\n // A boolean predicate must not consume self-echo ids before the real list\n // pass classifies the same events.\n return (\n listContainerMetadataDocumentUpdateIds(\n events,\n metadataStates,\n locallyAcceptedUpdateIds ? new Set(locallyAcceptedUpdateIds) : undefined,\n ).length > 0\n );\n}\n\n/** Consume local ids and report whether an event still contains a peer id. */\nfunction metadataEventHasRemoteUpdate(\n event: { updateIds?: readonly string[] | undefined },\n locallyAcceptedUpdateIds: Set<string> | undefined,\n): boolean {\n if (\n !locallyAcceptedUpdateIds ||\n !event.updateIds ||\n event.updateIds.length === 0\n ) {\n return true;\n }\n\n let remoteUpdateFound = false;\n for (const updateId of event.updateIds) {\n if (locallyAcceptedUpdateIds.has(updateId)) {\n locallyAcceptedUpdateIds.delete(updateId);\n } else {\n remoteUpdateFound = true;\n }\n }\n return remoteUpdateFound;\n}\n\n/**\n * `plannedDocumentIds` names the metadata documents of folders whose create is\n * in flight. A peer can edit one after the create commits but before the\n * response installs its id, and a committed seed stands in for the folder's\n * first metadata sync, so that hint must still queue a read.\n */\nexport function listContainerMetadataDocumentUpdateIds(\n events: ReadonlyArray<unknown>,\n metadataStates: Iterable<{ record: Pick<DocumentRecord, \"documentId\"> }>,\n locallyAcceptedUpdateIds?: Set<string>,\n plannedDocumentIds?: Iterable<string>,\n): string[] {\n const metadataDocumentIds = new Set<string>(plannedDocumentIds);\n for (const metadataState of metadataStates) {\n if (typeof metadataState.record.documentId === \"string\") {\n metadataDocumentIds.add(metadataState.record.documentId);\n }\n }\n if (metadataDocumentIds.size === 0) return [];\n\n const eventDocumentIds = new Set<string>();\n for (const event of events) {\n if (\n !isDocumentUpdateCreatedEvent(event) ||\n !metadataDocumentIds.has(event.documentId)\n ) {\n continue;\n }\n if (!metadataEventHasRemoteUpdate(event, locallyAcceptedUpdateIds)) {\n continue;\n }\n eventDocumentIds.add(event.documentId);\n }\n\n return Array.from(eventDocumentIds);\n}\n"]}
@@ -64,6 +64,9 @@ export type PersistContainerStateResult = {
64
64
  };
65
65
  export interface RemoteContainerHydrationHost {
66
66
  persistContainerState: (containerState: ContainerState, patch?: Partial<ContainerMetadataPatch>, updateView?: boolean, saveOptions?: SaveContainerOptions, mutationOptions?: {
67
+ /** Queued metadata rows the server committed, settled in this write. */
68
+ acceptedPendingUpdateIds?: readonly string[] | undefined;
69
+ clearSyncFailure?: boolean | undefined;
67
70
  expectedStateWhenMissing?: ContainerState | undefined;
68
71
  isCurrent?: (() => boolean) | undefined;
69
72
  createIntentSettlement?: Parameters<ContainerContentsPersistence["commitMetadataMutation"]>[1]["createIntentSettlement"];
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type { RequestResult } from \"@tearleads/api-client\";\nimport type { ContainerReplacementAuthorizationsResponse } from \"@tearleads/validators/operation\";\nimport type { ListContainerParentLanesRequest } from \"@tearleads/validators/request\";\nimport type {\n ContainerSummary,\n ContainerWriterProjectionResponse,\n DocumentWriterProjectionResponse,\n ListContainerParentLanesResponse,\n ListContainersResponse,\n ReferencedPrincipalStateResponse,\n} from \"@tearleads/validators/response\";\nimport type { createContainerMetadataDocument } from \"../../../data/containers/containerMetadataDocument\";\nimport type { CurrentPrincipalPolicyReader } from \"../../principals/currentPrincipalPolicyReader\";\nimport type { PrincipalPolicyHistoryReader } from \"../../principals/principalPolicyHistoryReader\";\nimport type {\n ContainerContentsPersistence,\n ContainerDocumentRecord,\n ContainerHydrationTombstone,\n ContainerRecord,\n createContainerParentSyncLane,\n} from \"../containerPersistence\";\nimport type { ContainerMetadataPatch } from \"../metadata\";\nimport type { ContainerContentsWorkflowRuntime } from \"../runtime\";\n\nexport type ListedRemoteContainerPageItem =\n ListContainersResponse[\"items\"][number];\nexport type ContainerChildIndex = Map<string, Set<string>>;\nexport type QueueContainerParentLane = (parentId: string | null) => void;\nexport type RemoteContainerIngestQueue = Map<string, RemoteContainer>;\nexport type SaveContainerOptions = Parameters<\n ContainerContentsPersistence[\"saveContainer\"]\n>[3];\n\nexport type ContainerMetadataDocumentState = Awaited<\n ReturnType<typeof createContainerMetadataDocument>\n>;\nexport type RemoteContainer = Pick<\n ContainerSummary,\n | \"createdAt\"\n | \"effectiveAccessLevel\"\n | \"systemSlot\"\n | \"id\"\n | \"metadataAccessEpoch\"\n | \"metadataAccessStateHash\"\n | \"metadataDocumentId\"\n | \"metadataReferencedPrincipals\"\n | \"organizationId\"\n | \"parentId\"\n | \"updatedAt\"\n>;\n\nexport interface ContainerState {\n containerWriterProjection?:\n | ContainerWriterProjectionResponse\n | null\n | undefined;\n /**\n * Bumped whenever a realtime hint drops this container's cached writer\n * projections (container and metadata document alike); an operation that\n * fetched or carried a projection installs it only if this is unchanged\n * since it started, so a pre-hint answer never lands after the hint.\n */\n writerProjectionGeneration?: number | undefined;\n metadataReferencedPrincipals?:\n | readonly ReferencedPrincipalStateResponse[]\n | undefined;\n container: ContainerRecord;\n doc: ContainerMetadataDocumentState;\n metadataWriterProjection?:\n | DocumentWriterProjectionResponse\n | null\n | undefined;\n /** Durable pull progress mirrored from the metadata document record. */\n pullContinuation?: ContainerDocumentRecord[\"pullContinuation\"] | undefined;\n record: ContainerDocumentRecord;\n}\n\ninterface RemoteContainerHydrationApi\n extends Partial<PrincipalPolicyHistoryReader>,\n CurrentPrincipalPolicyReader {\n getContainerReplacementAuthorizationsResult(\n containerId: string,\n replacesOrganizationId: string,\n ): Promise<RequestResult<ContainerReplacementAuthorizationsResponse>>;\n evictContainerWriterProjection(containerId: string): void;\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n listContainerParentLanes(\n input: ListContainerParentLanesRequest,\n ): Promise<ListContainerParentLanesResponse | null>;\n}\n\ninterface RemoteContainerHydrationRuntime\n extends Pick<\n ContainerContentsWorkflowRuntime,\n | \"auth\"\n | \"adoptRootContainer\"\n | \"crypto\"\n | \"infra\"\n | \"resolveTrustedUserIdentity\"\n | \"state\"\n | \"util\"\n > {\n apiClient: RemoteContainerHydrationApi;\n}\n\nexport interface RemoteContainerHydrationState {\n containersById: Map<string, ContainerState>;\n lifecycleGeneration?: number | undefined;\n persistence: ContainerContentsPersistence;\n rootLaneHydrated?: boolean | undefined;\n runtime: RemoteContainerHydrationRuntime;\n structuralGeneration?: number | undefined;\n}\n\nexport type PersistContainerStateResult =\n | { status: \"identity-superseded\"; record: ContainerDocumentRecord }\n | { status: \"missing\" }\n | {\n status: \"persisted\";\n record: ContainerDocumentRecord;\n createIntentSettled?: true | undefined;\n moveIntentSettled?: true | undefined;\n }\n | { status: \"stale-generation\" };\n\nexport interface RemoteContainerHydrationHost {\n persistContainerState: (\n containerState: ContainerState,\n patch?: Partial<ContainerMetadataPatch>,\n updateView?: boolean,\n saveOptions?: SaveContainerOptions,\n mutationOptions?: {\n expectedStateWhenMissing?: ContainerState | undefined;\n isCurrent?: (() => boolean) | undefined;\n createIntentSettlement?: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[1][\"createIntentSettlement\"];\n moveIntentSettlement?: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[1][\"moveIntentSettlement\"];\n preserveDurableStructureWhenPending?: boolean | undefined;\n },\n ) => Promise<PersistContainerStateResult>;\n requestDocumentPriming?: (() => void) | undefined;\n updateSnapshot: () => void;\n}\n\nexport interface ContainerParentHydrationLane {\n parentId: string | null;\n watermark?: ListContainersResponse[\"nextWatermark\"];\n}\n\nexport interface ExpectedContainerState {\n container: ContainerRecord;\n fingerprint: string;\n}\n\nexport interface FetchedContainerParentLanePage {\n expectedContainerStates: ReadonlyMap<string, ExpectedContainerState>;\n expectedHydrationTombstones: ReadonlyMap<string, ContainerHydrationTombstone>;\n lane: ContainerParentHydrationLane;\n response: ListContainersResponse;\n syncLane: ReturnType<typeof createContainerParentSyncLane>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type { RequestResult } from \"@tearleads/api-client\";\nimport type { ContainerReplacementAuthorizationsResponse } from \"@tearleads/validators/operation\";\nimport type { ListContainerParentLanesRequest } from \"@tearleads/validators/request\";\nimport type {\n ContainerSummary,\n ContainerWriterProjectionResponse,\n DocumentWriterProjectionResponse,\n ListContainerParentLanesResponse,\n ListContainersResponse,\n ReferencedPrincipalStateResponse,\n} from \"@tearleads/validators/response\";\nimport type { createContainerMetadataDocument } from \"../../../data/containers/containerMetadataDocument\";\nimport type { CurrentPrincipalPolicyReader } from \"../../principals/currentPrincipalPolicyReader\";\nimport type { PrincipalPolicyHistoryReader } from \"../../principals/principalPolicyHistoryReader\";\nimport type {\n ContainerContentsPersistence,\n ContainerDocumentRecord,\n ContainerHydrationTombstone,\n ContainerRecord,\n createContainerParentSyncLane,\n} from \"../containerPersistence\";\nimport type { ContainerMetadataPatch } from \"../metadata\";\nimport type { ContainerContentsWorkflowRuntime } from \"../runtime\";\n\nexport type ListedRemoteContainerPageItem =\n ListContainersResponse[\"items\"][number];\nexport type ContainerChildIndex = Map<string, Set<string>>;\nexport type QueueContainerParentLane = (parentId: string | null) => void;\nexport type RemoteContainerIngestQueue = Map<string, RemoteContainer>;\nexport type SaveContainerOptions = Parameters<\n ContainerContentsPersistence[\"saveContainer\"]\n>[3];\n\nexport type ContainerMetadataDocumentState = Awaited<\n ReturnType<typeof createContainerMetadataDocument>\n>;\nexport type RemoteContainer = Pick<\n ContainerSummary,\n | \"createdAt\"\n | \"effectiveAccessLevel\"\n | \"systemSlot\"\n | \"id\"\n | \"metadataAccessEpoch\"\n | \"metadataAccessStateHash\"\n | \"metadataDocumentId\"\n | \"metadataReferencedPrincipals\"\n | \"organizationId\"\n | \"parentId\"\n | \"updatedAt\"\n>;\n\nexport interface ContainerState {\n containerWriterProjection?:\n | ContainerWriterProjectionResponse\n | null\n | undefined;\n /**\n * Bumped whenever a realtime hint drops this container's cached writer\n * projections (container and metadata document alike); an operation that\n * fetched or carried a projection installs it only if this is unchanged\n * since it started, so a pre-hint answer never lands after the hint.\n */\n writerProjectionGeneration?: number | undefined;\n metadataReferencedPrincipals?:\n | readonly ReferencedPrincipalStateResponse[]\n | undefined;\n container: ContainerRecord;\n doc: ContainerMetadataDocumentState;\n metadataWriterProjection?:\n | DocumentWriterProjectionResponse\n | null\n | undefined;\n /** Durable pull progress mirrored from the metadata document record. */\n pullContinuation?: ContainerDocumentRecord[\"pullContinuation\"] | undefined;\n record: ContainerDocumentRecord;\n}\n\ninterface RemoteContainerHydrationApi\n extends Partial<PrincipalPolicyHistoryReader>,\n CurrentPrincipalPolicyReader {\n getContainerReplacementAuthorizationsResult(\n containerId: string,\n replacesOrganizationId: string,\n ): Promise<RequestResult<ContainerReplacementAuthorizationsResponse>>;\n evictContainerWriterProjection(containerId: string): void;\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n listContainerParentLanes(\n input: ListContainerParentLanesRequest,\n ): Promise<ListContainerParentLanesResponse | null>;\n}\n\ninterface RemoteContainerHydrationRuntime\n extends Pick<\n ContainerContentsWorkflowRuntime,\n | \"auth\"\n | \"adoptRootContainer\"\n | \"crypto\"\n | \"infra\"\n | \"resolveTrustedUserIdentity\"\n | \"state\"\n | \"util\"\n > {\n apiClient: RemoteContainerHydrationApi;\n}\n\nexport interface RemoteContainerHydrationState {\n containersById: Map<string, ContainerState>;\n lifecycleGeneration?: number | undefined;\n persistence: ContainerContentsPersistence;\n rootLaneHydrated?: boolean | undefined;\n runtime: RemoteContainerHydrationRuntime;\n structuralGeneration?: number | undefined;\n}\n\nexport type PersistContainerStateResult =\n | { status: \"identity-superseded\"; record: ContainerDocumentRecord }\n | { status: \"missing\" }\n | {\n status: \"persisted\";\n record: ContainerDocumentRecord;\n createIntentSettled?: true | undefined;\n moveIntentSettled?: true | undefined;\n }\n | { status: \"stale-generation\" };\n\nexport interface RemoteContainerHydrationHost {\n persistContainerState: (\n containerState: ContainerState,\n patch?: Partial<ContainerMetadataPatch>,\n updateView?: boolean,\n saveOptions?: SaveContainerOptions,\n mutationOptions?: {\n /** Queued metadata rows the server committed, settled in this write. */\n acceptedPendingUpdateIds?: readonly string[] | undefined;\n clearSyncFailure?: boolean | undefined;\n expectedStateWhenMissing?: ContainerState | undefined;\n isCurrent?: (() => boolean) | undefined;\n createIntentSettlement?: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[1][\"createIntentSettlement\"];\n moveIntentSettlement?: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[1][\"moveIntentSettlement\"];\n preserveDurableStructureWhenPending?: boolean | undefined;\n },\n ) => Promise<PersistContainerStateResult>;\n requestDocumentPriming?: (() => void) | undefined;\n updateSnapshot: () => void;\n}\n\nexport interface ContainerParentHydrationLane {\n parentId: string | null;\n watermark?: ListContainersResponse[\"nextWatermark\"];\n}\n\nexport interface ExpectedContainerState {\n container: ContainerRecord;\n fingerprint: string;\n}\n\nexport interface FetchedContainerParentLanePage {\n expectedContainerStates: ReadonlyMap<string, ExpectedContainerState>;\n expectedHydrationTombstones: ReadonlyMap<string, ContainerHydrationTombstone>;\n lane: ContainerParentHydrationLane;\n response: ListContainersResponse;\n syncLane: ReturnType<typeof createContainerParentSyncLane>;\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { type ContainerWriterProjectionResponse, type DocumentCreateResponse } from "../../../internal/validators/response/index.js";
2
2
  import type { CreateRemoteDocumentResult, DocumentCreateApi, DocumentCreateAuthor, MaterializedDocumentCreatePlan, ProjectionVerificationOptions } from "../../../data/documents/shared/types.js";
3
3
  import type { ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer } from "../../../data/keyingProjectionVerification/index.js";
4
+ import type { PendingUpdateRecord } from "../../../data/sqlite/documentPersistence/index.js";
4
5
  import type { ExecSql } from "../../../data/sqlite/sqlSchema.js";
5
6
  import type { DocumentCreateTerminalFailureHandler } from "./createProjectionFetch.js";
6
7
  export declare function buildMaterializedDocumentCreatePlan(input: {
@@ -37,6 +38,12 @@ interface RemoteDocumentCreateInput {
37
38
  */
38
39
  onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;
39
40
  resolveProjectionUserKey: ProjectionUserKeyResolver;
41
+ /**
42
+ * The queued row holding the new document's whole content (see
43
+ * `documentCreateSeedCandidate`). The create commits it as its seed, and the
44
+ * caller settles the row from the response instead of syncing it.
45
+ */
46
+ seedUpdate?: PendingUpdateRecord | undefined;
40
47
  signedAt?: string | undefined;
41
48
  stillCurrent?: (() => boolean) | undefined;
42
49
  targetSecretKey: Uint8Array;
@@ -6,6 +6,7 @@ import { projectionVerificationOptions } from "../../../data/documents/shared/ty
6
6
  import { collectContainerWriterProjectionPrincipalPolicies, nullOnProjectionVerificationCancellation, requireProjectionUserKeyResolver, } from "../../../data/keyingProjectionVerification/index.js";
7
7
  import { isContainerCreatePending } from "../../../data/persistence/container-contents/pendingContainerCreate.js";
8
8
  import { recordDocumentAuthorAccessFailure } from "../authorAccessFailure.js";
9
+ import { buildDocumentCreateSeedRequest, documentCreateSeedFits, } from "../sync/initialSync.js";
9
10
  import { isDocumentManifestAlreadyExistsConflict, shouldRetryWithFreshProjection, } from "../syncFailures/syncFailureClassification.js";
10
11
  import { adoptExistingRemoteDocument } from "./createAdoption.js";
11
12
  import { fetchContainerWriterProjectionForCreate } from "./createProjectionFetch.js";
@@ -119,6 +120,39 @@ async function buildMaterializedDocumentCreatePlanWithFreshProjection(input) {
119
120
  });
120
121
  return refreshedProjection ? buildWithProjection(refreshedProjection) : null;
121
122
  }
123
+ /**
124
+ * A seed only saves the first sync. A refusal of the seeded create falls back
125
+ * to the plain create once, so the row syncs as before and seeding adds no
126
+ * failure mode. A lost response is adopted, and a stale target is replanned
127
+ * with a fresh seed, exactly as for a plain create. Building the seed awaits
128
+ * its encryption, so each submission rechecks the caller is still current and
129
+ * returns null instead of creating a document whose response would be dropped.
130
+ */
131
+ async function submitPlannedDocumentCreateRequest(input, createPlan) {
132
+ const request = createPlan.materializedPlan.plan.request;
133
+ const organizationId = createPlan.containerProjection.organizationId;
134
+ const seed = input.seedUpdate
135
+ ? await buildDocumentCreateSeedRequest({
136
+ author: input.author,
137
+ containerProjection: createPlan.containerProjection,
138
+ materializedDocument: createPlan.materializedPlan,
139
+ pendingUpdate: input.seedUpdate,
140
+ })
141
+ : null;
142
+ if (seed && documentCreateSeedFits(seed)) {
143
+ if (input.stillCurrent?.() === false)
144
+ return null;
145
+ const seeded = await submitDocumentCreate(input.apiClient, { ...request, initialSync: seed }, organizationId);
146
+ if (seeded.ok ||
147
+ isDocumentManifestAlreadyExistsConflict(seeded) ||
148
+ isStaleDocumentCreateTargetConflict(seeded)) {
149
+ return seeded;
150
+ }
151
+ }
152
+ if (input.stillCurrent?.() === false)
153
+ return null;
154
+ return submitDocumentCreate(input.apiClient, request, organizationId);
155
+ }
122
156
  function isRemoteDocumentCreatePlanBlocked(input, createPlan) {
123
157
  const organizationId = createPlan.containerProjection.organizationId;
124
158
  return input.isRemoteSyncBlocked?.(organizationId) ?? false;
@@ -152,7 +186,9 @@ async function submitPlannedDocumentCreate(input, resolveProjectionUserKey) {
152
186
  return null;
153
187
  if (input.stillCurrent?.() === false)
154
188
  return null;
155
- let submission = await submitDocumentCreate(input.apiClient, createPlan.materializedPlan.plan.request, createPlan.containerProjection.organizationId);
189
+ let submission = await submitPlannedDocumentCreateRequest(input, createPlan);
190
+ if (!submission)
191
+ return null;
156
192
  if (isStaleDocumentCreateTargetConflict(submission)) {
157
193
  if (input.stillCurrent?.() === false) {
158
194
  return { createPlan, submission };
@@ -185,7 +221,9 @@ async function submitPlannedDocumentCreate(input, resolveProjectionUserKey) {
185
221
  createPlan = refreshedPlan;
186
222
  if (input.stillCurrent?.() === false)
187
223
  return null;
188
- submission = await submitDocumentCreate(input.apiClient, createPlan.materializedPlan.plan.request, createPlan.containerProjection.organizationId);
224
+ submission = await submitPlannedDocumentCreateRequest(input, createPlan);
225
+ if (!submission)
226
+ return null;
189
227
  }
190
228
  return { createPlan, submission };
191
229
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentCreateRequest } from \"@tearleads/validators/request\";\nimport {\n type ContainerWriterProjectionResponse,\n DOCUMENT_SYNC_ERROR_CODES,\n type DocumentCreateResponse,\n} from \"@tearleads/validators/response\";\nimport { assertContainerAuthorAccess } from \"../../../data/containers/shared/authorAccess\";\nimport { buildDocumentCreatePlan } from \"../../../data/documents/shared/events\";\nimport { wrapDocumentContentKeyForCreate } from \"../../../data/documents/shared/projection\";\nimport type {\n CreateRemoteDocumentResult,\n DocumentCreateApi,\n DocumentCreateAuthor,\n MaterializedDocumentCreatePlan,\n ProjectionVerificationOptions,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport {\n collectContainerWriterProjectionPrincipalPolicies,\n nullOnProjectionVerificationCancellation,\n requireProjectionUserKeyResolver,\n} from \"../../../data/keyingProjectionVerification\";\nimport { isContainerCreatePending } from \"../../../data/persistence/container-contents/pendingContainerCreate\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport { recordDocumentAuthorAccessFailure } from \"../authorAccessFailure\";\nimport {\n isDocumentManifestAlreadyExistsConflict,\n shouldRetryWithFreshProjection,\n} from \"../syncFailures/syncFailureClassification\";\nimport { adoptExistingRemoteDocument } from \"./createAdoption\";\nimport type { DocumentCreateTerminalFailureHandler } from \"./createProjectionFetch\";\nimport { fetchContainerWriterProjectionForCreate } from \"./createProjectionFetch\";\nimport { acknowledgeRemoteDocumentCreate } from \"./createResponse\";\n\nexport async function buildMaterializedDocumentCreatePlan(\n input: {\n author: DocumentCreateAuthor;\n containerProjection: ContainerWriterProjectionResponse;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql?: ExecSql | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n signedAt?: string | undefined;\n targetSecretKey: Uint8Array;\n } & ProjectionVerificationOptions,\n): Promise<MaterializedDocumentCreatePlan> {\n const contentKey =\n input.contentKey ?? crypto.getRandomValues(new Uint8Array(32));\n if (contentKey.byteLength !== 32) {\n throw new Error(\"Document content key must be 32 bytes\");\n }\n // Resolved before wrapping: each envelope is sealed to its document and\n // content-key epoch.\n const documentId = input.documentId ?? crypto.randomUUID();\n const contentKeyEpoch = input.contentKeyEpoch ?? 1;\n const targetEnvelopes = await wrapDocumentContentKeyForCreate({\n contentKey,\n contentKeyEpoch,\n documentId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n projection: input.containerProjection,\n secretKey: input.targetSecretKey,\n ...projectionVerificationOptions(input),\n });\n if (input.resolveProjectionUserKey) {\n const principalPolicies =\n await collectContainerWriterProjectionPrincipalPolicies({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n projection: input.containerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n });\n assertContainerAuthorAccess({\n // Document signing derives its organization from the verified target.\n author: {\n ...input.author,\n organizationId: input.containerProjection.organizationId,\n },\n projection: input.containerProjection,\n principalPolicies,\n minimumAccess: \"write\",\n });\n }\n // The explicit local-trust variant builds provisioning artifacts before\n // their new principal policies exist remotely; remote creates cannot use it.\n const plan = await buildDocumentCreatePlan({\n author: input.author,\n containerProjection: input.containerProjection,\n contentKeyEpoch,\n documentId,\n ...(input.eventId === undefined ? {} : { eventId: input.eventId }),\n ...(input.signedAt === undefined ? {} : { signedAt: input.signedAt }),\n targetEnvelopes,\n });\n\n return {\n contentKey,\n plan,\n };\n}\n\nexport { documentWriterProjectionFromCreateResponse } from \"./createProjection\";\n\ninterface MaterializedDocumentCreatePlanWithProjection {\n readonly containerProjection: ContainerWriterProjectionResponse;\n readonly materializedPlan: MaterializedDocumentCreatePlan;\n}\n\nasync function buildMaterializedDocumentCreatePlanWithFreshProjection(input: {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<MaterializedDocumentCreatePlanWithProjection | null> {\n const buildWithProjection = async (\n containerProjection: ContainerWriterProjectionResponse,\n ) => {\n if (\n containerProjection.containerId !== input.containerId ||\n (input.expectedOrganizationId !== undefined &&\n containerProjection.organizationId !== input.expectedOrganizationId)\n ) {\n throw new Error(\n \"Container writer projection belongs to another container or organization\",\n );\n }\n return {\n containerProjection,\n materializedPlan: await buildMaterializedDocumentCreatePlan({\n author: input.author,\n containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n signedAt: input.signedAt,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n };\n };\n\n const containerProjection =\n input.containerProjection ??\n (await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n }));\n if (!containerProjection) {\n return null;\n }\n\n try {\n return await buildWithProjection(containerProjection);\n } catch (error) {\n if (\n !shouldRetryWithFreshProjection(error, (message) =>\n message.includes(\"could not be unwrapped\"),\n )\n ) {\n throw error;\n }\n }\n\n // Only this container's projection was stale; evict just it rather than\n // wiping every cached projection.\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const refreshedProjection = await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n });\n return refreshedProjection ? buildWithProjection(refreshedProjection) : null;\n}\n\ninterface RemoteDocumentCreateInput {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n /**\n * Invoked when the create submission fails terminally (not a benign\n * adopt/stale-target conflict) — e.g. the server denies the write. Callers\n * persist the failure so the write queue can surface it.\n */\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}\n\nfunction isRemoteDocumentCreatePlanBlocked(\n input: RemoteDocumentCreateInput,\n createPlan: MaterializedDocumentCreatePlanWithProjection,\n): boolean {\n const organizationId = createPlan.containerProjection.organizationId;\n return input.isRemoteSyncBlocked?.(organizationId) ?? false;\n}\n\nasync function submitPlannedDocumentCreate(\n input: RemoteDocumentCreateInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<{\n readonly createPlan: MaterializedDocumentCreatePlanWithProjection;\n readonly submission: DocumentCreateSubmission;\n} | null> {\n const verificationOptions = { stillCurrent: input.stillCurrent };\n const warmReferencedPrincipalPolicies = input.warmReferencedPrincipalPolicies;\n let createPlan = await buildMaterializedDocumentCreatePlanWithFreshProjection(\n {\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n containerProjection: input.containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n },\n );\n if (!createPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, createPlan)) return null;\n if (input.stillCurrent?.() === false) return null;\n let submission = await submitDocumentCreate(\n input.apiClient,\n createPlan.materializedPlan.plan.request,\n createPlan.containerProjection.organizationId,\n );\n if (isStaleDocumentCreateTargetConflict(submission)) {\n if (input.stillCurrent?.() === false) {\n return { createPlan, submission };\n }\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const firstPlan = createPlan.materializedPlan;\n const refreshedPlan =\n await buildMaterializedDocumentCreatePlanWithFreshProjection({\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n contentKey: firstPlan.contentKey,\n contentKeyEpoch:\n firstPlan.plan.request.contentKeyBundle.contentKeyEpoch,\n documentId: firstPlan.plan.documentId,\n eventId: firstPlan.plan.event.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: firstPlan.plan.event.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n });\n if (!refreshedPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, refreshedPlan)) return null;\n createPlan = refreshedPlan;\n if (input.stillCurrent?.() === false) return null;\n submission = await submitDocumentCreate(\n input.apiClient,\n createPlan.materializedPlan.plan.request,\n createPlan.containerProjection.organizationId,\n );\n }\n return { createPlan, submission };\n}\n\nexport async function createRemoteDocument(\n input: RemoteDocumentCreateInput,\n): Promise<CreateRemoteDocumentResult | null> {\n // The store retries once the folder's own create settles.\n if (await isContainerCreatePending(input.execSql, input.containerId)) {\n return null;\n }\n const resolveProjectionUserKey = requireProjectionUserKeyResolver(\n input.resolveProjectionUserKey,\n \"Remote document create\",\n );\n const plannedSubmission = await recordDocumentAuthorAccessFailure(\n () =>\n nullOnProjectionVerificationCancellation(() =>\n submitPlannedDocumentCreate(input, resolveProjectionUserKey),\n ),\n input.onTerminalSubmitFailure,\n );\n if (!plannedSubmission) {\n return null;\n }\n const { createPlan, submission } = plannedSubmission;\n if (input.stillCurrent?.() === false) return null;\n if (submission.ok)\n return acknowledgeRemoteDocumentCreate({\n ...input,\n ...createPlan,\n resolveProjectionUserKey,\n response: submission.data,\n });\n\n // A stable documentId means a retry after a lost create response re-submits\n // the same id; the server then reports the manifest already exists. That is\n // not a failure — the first attempt committed. Adopt the existing remote\n // document instead of leaking a duplicate. Requires the stable id we sent, so\n // we can fetch its projection back.\n const stableDocumentId = input.documentId;\n if (stableDocumentId && isDocumentManifestAlreadyExistsConflict(submission)) {\n if (input.stillCurrent?.() === false) return null;\n const adopted = await nullOnProjectionVerificationCancellation(() =>\n adoptExistingRemoteDocument({\n apiClient: input.apiClient,\n documentId: stableDocumentId,\n execSql: input.execSql,\n expectedContainerId: input.containerId,\n expectedOrganizationId:\n input.expectedOrganizationId ??\n createPlan.containerProjection.organizationId,\n expectedSignerUserId: input.author.signerUserId,\n resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n );\n if (adopted) {\n return adopted;\n }\n // A conflict is the expected, benign outcome of an idempotent retry after a\n // lost create response. If adoption cannot complete yet (e.g. the writer\n // projection fetch failed transiently), do not surface the conflict as a UI\n // error — the sync engine retries and adopts it on a later tick.\n return null;\n }\n\n submission.report?.();\n await input.onTerminalSubmitFailure?.(submission);\n return null;\n}\n\ntype DocumentCreateSubmission =\n | {\n readonly data: DocumentCreateResponse;\n readonly ok: true;\n }\n | {\n readonly code?: string | undefined;\n readonly message: string;\n readonly ok: false;\n readonly report?: (() => void) | undefined;\n readonly status: number | null;\n };\n\nexport function isStaleDocumentCreateTargetConflict(\n submission: DocumentCreateSubmission,\n): boolean {\n return (\n !submission.ok &&\n submission.status === 409 &&\n submission.code === DOCUMENT_SYNC_ERROR_CODES.stateStale\n );\n}\n\nasync function submitDocumentCreate(\n apiClient: DocumentCreateApi,\n request: DocumentCreateRequest,\n expectedOrganizationId: string,\n): Promise<DocumentCreateSubmission> {\n return apiClient.createDocumentResult(request, {\n expectedPaymentRequiredOrganizationId: expectedOrganizationId,\n reportErrors: false,\n });\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentCreateRequest } from \"@tearleads/validators/request\";\nimport {\n type ContainerWriterProjectionResponse,\n DOCUMENT_SYNC_ERROR_CODES,\n type DocumentCreateResponse,\n} from \"@tearleads/validators/response\";\nimport { assertContainerAuthorAccess } from \"../../../data/containers/shared/authorAccess\";\nimport { buildDocumentCreatePlan } from \"../../../data/documents/shared/events\";\nimport { wrapDocumentContentKeyForCreate } from \"../../../data/documents/shared/projection\";\nimport type {\n CreateRemoteDocumentResult,\n DocumentCreateApi,\n DocumentCreateAuthor,\n MaterializedDocumentCreatePlan,\n ProjectionVerificationOptions,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport {\n collectContainerWriterProjectionPrincipalPolicies,\n nullOnProjectionVerificationCancellation,\n requireProjectionUserKeyResolver,\n} from \"../../../data/keyingProjectionVerification\";\nimport { isContainerCreatePending } from \"../../../data/persistence/container-contents/pendingContainerCreate\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport { recordDocumentAuthorAccessFailure } from \"../authorAccessFailure\";\nimport {\n buildDocumentCreateSeedRequest,\n documentCreateSeedFits,\n} from \"../sync/initialSync\";\nimport {\n isDocumentManifestAlreadyExistsConflict,\n shouldRetryWithFreshProjection,\n} from \"../syncFailures/syncFailureClassification\";\nimport { adoptExistingRemoteDocument } from \"./createAdoption\";\nimport type { DocumentCreateTerminalFailureHandler } from \"./createProjectionFetch\";\nimport { fetchContainerWriterProjectionForCreate } from \"./createProjectionFetch\";\nimport { acknowledgeRemoteDocumentCreate } from \"./createResponse\";\n\nexport async function buildMaterializedDocumentCreatePlan(\n input: {\n author: DocumentCreateAuthor;\n containerProjection: ContainerWriterProjectionResponse;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql?: ExecSql | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n signedAt?: string | undefined;\n targetSecretKey: Uint8Array;\n } & ProjectionVerificationOptions,\n): Promise<MaterializedDocumentCreatePlan> {\n const contentKey =\n input.contentKey ?? crypto.getRandomValues(new Uint8Array(32));\n if (contentKey.byteLength !== 32) {\n throw new Error(\"Document content key must be 32 bytes\");\n }\n // Resolved before wrapping: each envelope is sealed to its document and\n // content-key epoch.\n const documentId = input.documentId ?? crypto.randomUUID();\n const contentKeyEpoch = input.contentKeyEpoch ?? 1;\n const targetEnvelopes = await wrapDocumentContentKeyForCreate({\n contentKey,\n contentKeyEpoch,\n documentId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n projection: input.containerProjection,\n secretKey: input.targetSecretKey,\n ...projectionVerificationOptions(input),\n });\n if (input.resolveProjectionUserKey) {\n const principalPolicies =\n await collectContainerWriterProjectionPrincipalPolicies({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n projection: input.containerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n });\n assertContainerAuthorAccess({\n // Document signing derives its organization from the verified target.\n author: {\n ...input.author,\n organizationId: input.containerProjection.organizationId,\n },\n projection: input.containerProjection,\n principalPolicies,\n minimumAccess: \"write\",\n });\n }\n // The explicit local-trust variant builds provisioning artifacts before\n // their new principal policies exist remotely; remote creates cannot use it.\n const plan = await buildDocumentCreatePlan({\n author: input.author,\n containerProjection: input.containerProjection,\n contentKeyEpoch,\n documentId,\n ...(input.eventId === undefined ? {} : { eventId: input.eventId }),\n ...(input.signedAt === undefined ? {} : { signedAt: input.signedAt }),\n targetEnvelopes,\n });\n\n return {\n contentKey,\n plan,\n };\n}\n\nexport { documentWriterProjectionFromCreateResponse } from \"./createProjection\";\n\ninterface MaterializedDocumentCreatePlanWithProjection {\n readonly containerProjection: ContainerWriterProjectionResponse;\n readonly materializedPlan: MaterializedDocumentCreatePlan;\n}\n\nasync function buildMaterializedDocumentCreatePlanWithFreshProjection(input: {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<MaterializedDocumentCreatePlanWithProjection | null> {\n const buildWithProjection = async (\n containerProjection: ContainerWriterProjectionResponse,\n ) => {\n if (\n containerProjection.containerId !== input.containerId ||\n (input.expectedOrganizationId !== undefined &&\n containerProjection.organizationId !== input.expectedOrganizationId)\n ) {\n throw new Error(\n \"Container writer projection belongs to another container or organization\",\n );\n }\n return {\n containerProjection,\n materializedPlan: await buildMaterializedDocumentCreatePlan({\n author: input.author,\n containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n signedAt: input.signedAt,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n };\n };\n\n const containerProjection =\n input.containerProjection ??\n (await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n }));\n if (!containerProjection) {\n return null;\n }\n\n try {\n return await buildWithProjection(containerProjection);\n } catch (error) {\n if (\n !shouldRetryWithFreshProjection(error, (message) =>\n message.includes(\"could not be unwrapped\"),\n )\n ) {\n throw error;\n }\n }\n\n // Only this container's projection was stale; evict just it rather than\n // wiping every cached projection.\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const refreshedProjection = await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n });\n return refreshedProjection ? buildWithProjection(refreshedProjection) : null;\n}\n\ninterface RemoteDocumentCreateInput {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n /**\n * Invoked when the create submission fails terminally (not a benign\n * adopt/stale-target conflict) — e.g. the server denies the write. Callers\n * persist the failure so the write queue can surface it.\n */\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n /**\n * The queued row holding the new document's whole content (see\n * `documentCreateSeedCandidate`). The create commits it as its seed, and the\n * caller settles the row from the response instead of syncing it.\n */\n seedUpdate?: PendingUpdateRecord | undefined;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}\n\n/**\n * A seed only saves the first sync. A refusal of the seeded create falls back\n * to the plain create once, so the row syncs as before and seeding adds no\n * failure mode. A lost response is adopted, and a stale target is replanned\n * with a fresh seed, exactly as for a plain create. Building the seed awaits\n * its encryption, so each submission rechecks the caller is still current and\n * returns null instead of creating a document whose response would be dropped.\n */\nasync function submitPlannedDocumentCreateRequest(\n input: RemoteDocumentCreateInput,\n createPlan: MaterializedDocumentCreatePlanWithProjection,\n): Promise<DocumentCreateSubmission | null> {\n const request = createPlan.materializedPlan.plan.request;\n const organizationId = createPlan.containerProjection.organizationId;\n const seed = input.seedUpdate\n ? await buildDocumentCreateSeedRequest({\n author: input.author,\n containerProjection: createPlan.containerProjection,\n materializedDocument: createPlan.materializedPlan,\n pendingUpdate: input.seedUpdate,\n })\n : null;\n if (seed && documentCreateSeedFits(seed)) {\n if (input.stillCurrent?.() === false) return null;\n const seeded = await submitDocumentCreate(\n input.apiClient,\n { ...request, initialSync: seed },\n organizationId,\n );\n if (\n seeded.ok ||\n isDocumentManifestAlreadyExistsConflict(seeded) ||\n isStaleDocumentCreateTargetConflict(seeded)\n ) {\n return seeded;\n }\n }\n if (input.stillCurrent?.() === false) return null;\n return submitDocumentCreate(input.apiClient, request, organizationId);\n}\n\nfunction isRemoteDocumentCreatePlanBlocked(\n input: RemoteDocumentCreateInput,\n createPlan: MaterializedDocumentCreatePlanWithProjection,\n): boolean {\n const organizationId = createPlan.containerProjection.organizationId;\n return input.isRemoteSyncBlocked?.(organizationId) ?? false;\n}\n\nasync function submitPlannedDocumentCreate(\n input: RemoteDocumentCreateInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<{\n readonly createPlan: MaterializedDocumentCreatePlanWithProjection;\n readonly submission: DocumentCreateSubmission;\n} | null> {\n const verificationOptions = { stillCurrent: input.stillCurrent };\n const warmReferencedPrincipalPolicies = input.warmReferencedPrincipalPolicies;\n let createPlan = await buildMaterializedDocumentCreatePlanWithFreshProjection(\n {\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n containerProjection: input.containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n },\n );\n if (!createPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, createPlan)) return null;\n if (input.stillCurrent?.() === false) return null;\n let submission = await submitPlannedDocumentCreateRequest(input, createPlan);\n if (!submission) return null;\n if (isStaleDocumentCreateTargetConflict(submission)) {\n if (input.stillCurrent?.() === false) {\n return { createPlan, submission };\n }\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const firstPlan = createPlan.materializedPlan;\n const refreshedPlan =\n await buildMaterializedDocumentCreatePlanWithFreshProjection({\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n contentKey: firstPlan.contentKey,\n contentKeyEpoch:\n firstPlan.plan.request.contentKeyBundle.contentKeyEpoch,\n documentId: firstPlan.plan.documentId,\n eventId: firstPlan.plan.event.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: firstPlan.plan.event.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n });\n if (!refreshedPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, refreshedPlan)) return null;\n createPlan = refreshedPlan;\n if (input.stillCurrent?.() === false) return null;\n submission = await submitPlannedDocumentCreateRequest(input, createPlan);\n if (!submission) return null;\n }\n return { createPlan, submission };\n}\n\nexport async function createRemoteDocument(\n input: RemoteDocumentCreateInput,\n): Promise<CreateRemoteDocumentResult | null> {\n // The store retries once the folder's own create settles.\n if (await isContainerCreatePending(input.execSql, input.containerId)) {\n return null;\n }\n const resolveProjectionUserKey = requireProjectionUserKeyResolver(\n input.resolveProjectionUserKey,\n \"Remote document create\",\n );\n const plannedSubmission = await recordDocumentAuthorAccessFailure(\n () =>\n nullOnProjectionVerificationCancellation(() =>\n submitPlannedDocumentCreate(input, resolveProjectionUserKey),\n ),\n input.onTerminalSubmitFailure,\n );\n if (!plannedSubmission) {\n return null;\n }\n const { createPlan, submission } = plannedSubmission;\n if (input.stillCurrent?.() === false) return null;\n if (submission.ok)\n return acknowledgeRemoteDocumentCreate({\n ...input,\n ...createPlan,\n resolveProjectionUserKey,\n response: submission.data,\n });\n\n // A stable documentId means a retry after a lost create response re-submits\n // the same id; the server then reports the manifest already exists. That is\n // not a failure — the first attempt committed. Adopt the existing remote\n // document instead of leaking a duplicate. Requires the stable id we sent, so\n // we can fetch its projection back.\n const stableDocumentId = input.documentId;\n if (stableDocumentId && isDocumentManifestAlreadyExistsConflict(submission)) {\n if (input.stillCurrent?.() === false) return null;\n const adopted = await nullOnProjectionVerificationCancellation(() =>\n adoptExistingRemoteDocument({\n apiClient: input.apiClient,\n documentId: stableDocumentId,\n execSql: input.execSql,\n expectedContainerId: input.containerId,\n expectedOrganizationId:\n input.expectedOrganizationId ??\n createPlan.containerProjection.organizationId,\n expectedSignerUserId: input.author.signerUserId,\n resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n );\n if (adopted) {\n return adopted;\n }\n // A conflict is the expected, benign outcome of an idempotent retry after a\n // lost create response. If adoption cannot complete yet (e.g. the writer\n // projection fetch failed transiently), do not surface the conflict as a UI\n // error — the sync engine retries and adopts it on a later tick.\n return null;\n }\n\n submission.report?.();\n await input.onTerminalSubmitFailure?.(submission);\n return null;\n}\n\ntype DocumentCreateSubmission =\n | {\n readonly data: DocumentCreateResponse;\n readonly ok: true;\n }\n | {\n readonly code?: string | undefined;\n readonly message: string;\n readonly ok: false;\n readonly report?: (() => void) | undefined;\n readonly status: number | null;\n };\n\nexport function isStaleDocumentCreateTargetConflict(\n submission: DocumentCreateSubmission,\n): boolean {\n return (\n !submission.ok &&\n submission.status === 409 &&\n submission.code === DOCUMENT_SYNC_ERROR_CODES.stateStale\n );\n}\n\nasync function submitDocumentCreate(\n apiClient: DocumentCreateApi,\n request: DocumentCreateRequest,\n expectedOrganizationId: string,\n): Promise<DocumentCreateSubmission> {\n return apiClient.createDocumentResult(request, {\n expectedPaymentRequiredOrganizationId: expectedOrganizationId,\n reportErrors: false,\n });\n}\n"]}
@@ -24,6 +24,7 @@ export { buildDocumentPurgeRequest, purgeRemoteDocument, } from "./purge/index.j
24
24
  export { type DiscardedDocumentShellResult, deletePersistedDocument, discardPersistedDocumentToShell, } from "./purge/persistedDocumentRemoval.js";
25
25
  export { createDocumentsWorkflowRuntime, type DocumentsWorkflowRuntime, type DocumentsWorkflowRuntimeGroups, type DocumentsWorkflowRuntimeInfra, type DocumentsWorkflowRuntimeInput, type DocumentsWorkflowRuntimeInputGroups, } from "./runtime.js";
26
26
  export { hasDocumentUpdateEvent, syncRemoteDocument, } from "./sync/index.js";
27
+ export { documentCreateSeedCandidate } from "./sync/initialSync.js";
27
28
  export type { SyncRemoteDocumentInput } from "./sync/readOnlySync.js";
28
29
  export type { DocumentSyncContainerRekeyBuilder } from "./sync/syncAttemptState.js";
29
30
  export { type DocumentSyncLane, registerDocumentSyncLane, requestDocumentSyncLaneAndWait, } from "./sync/syncLane.js";
@@ -22,6 +22,7 @@ export { buildDocumentPurgeRequest, purgeRemoteDocument, } from "./purge/index.j
22
22
  export { deletePersistedDocument, discardPersistedDocumentToShell, } from "./purge/persistedDocumentRemoval.js";
23
23
  export { createDocumentsWorkflowRuntime, } from "./runtime.js";
24
24
  export { hasDocumentUpdateEvent, syncRemoteDocument, } from "./sync/index.js";
25
+ export { documentCreateSeedCandidate } from "./sync/initialSync.js";
25
26
  export { registerDocumentSyncLane, requestDocumentSyncLaneAndWait, } from "./sync/syncLane.js";
26
27
  export { DOCUMENT_SYNC_TRACE_FRAGMENT, DOCUMENT_SYNC_TRACE_PATTERN, } from "./sync/syncTrace.js";
27
28
  export { describeDocumentRevalidationFailure, describeDocumentSyncSubmitFailure, } from "./syncFailures/syncFailureClassification.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,wCAAwC,EAAE,MAAM,uCAAuC,CAAC;AACjG,OAAO,EAGL,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,8DAA8D,CAAC;AACtE,OAAO,EAEL,kCAAkC,EAClC,oBAAoB,GACrB,MAAM,iDAAiD,CAAC;AAOzD,OAAO,EACL,wBAAwB,EACxB,sCAAsC,EACtC,yBAAyB,GAC1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,qCAAqC,EACrC,oCAAoC,GACrC,MAAM,kEAAkE,CAAC;AAE1E,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,EAC/B,mCAAmC,EACnC,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,iCAAiC,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,mCAAmC,EACnC,oBAAoB,EACpB,0CAA0C,GAC3C,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,gCAAgC,EAChC,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,4CAA4C,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,kBAAkB,EAGlB,2BAA2B,EAE3B,+BAA+B,EAK/B,oBAAoB,EAEpB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uCAAuC,EAGvC,qCAAqC,GACtC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,8BAA8B,GAM/B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAEL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mCAAmC,EACnC,iCAAiC,GAElC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,uCAAuC,EAAE,MAAM,qCAAqC,CAAC;AAC9F,OAAO,EAAE,kCAAkC,EAAE,MAAM,4BAA4B,CAAC;AAEhF,OAAO,EAAE,qCAAqC,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export {\n unwrapContainerKekPath,\n unwrapDocumentContentKeyTarget,\n} from \"../../data/documents/shared/projection\";\nexport { persistedDocumentCreateStateFromResponse } from \"../../data/documents/shared/responses\";\nexport {\n type DocumentSyncUpdateIsolationError,\n type IncomingDocumentSyncUpdateValidator,\n isDocumentSyncUpdateIsolationError,\n validateDocumentSyncUpdateImports,\n} from \"../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nexport {\n type DocumentSyncPullContinuation,\n documentSyncPullContinuationsEqual,\n readPullContinuation,\n} from \"../../data/documents/shared/sync/syncPagination\";\nexport type {\n DocumentCreateAuthor,\n DocumentLinkSetFailureHandler,\n DocumentLinkSetMutationFailure,\n RelinkRemoteDocumentResult,\n} from \"../../data/documents/shared/types\";\nexport {\n clearDocumentSyncFailure,\n invalidateDocumentSyncPullContinuation,\n recordDocumentSyncFailure,\n} from \"../../data/sqlite/documentPersistence\";\nexport {\n DOCUMENT_HISTORY_COMPACTION_MAX_BYTES,\n DOCUMENT_HISTORY_COMPACTION_MAX_ROWS,\n} from \"../../data/sqlite/documentPersistence/documentHistoryPersistence\";\nexport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nexport { selectDocumentSyncOutgoingBatch } from \"../../data/sync/documentSyncOutgoingBatch\";\nexport { settleOutgoingPassAndDecideReArm } from \"../../data/sync/outgoingUpdateSettlement\";\nexport {\n didRegainSyncPrerequisites,\n isDatabaseUnavailableError,\n} from \"../../data/sync/syncCoordinator\";\nexport {\n deleteLocalDocumentAttachment,\n deletePendingDocumentAttachment,\n markLocalDocumentAttachmentDetached,\n saveLocalDocumentAttachments,\n savePendingDocumentAttachment,\n} from \"./attachments/attachmentPersistence\";\nexport { runSerializedDocumentBlobMutation } from \"./attachments/blobMutationLock\";\nexport { reclaimDocumentOrphanBlobs } from \"./attachments/orphanBlobReclaims\";\nexport { resolveDocumentCreateAuthor } from \"./author\";\nexport {\n buildMaterializedDocumentCreatePlan,\n createRemoteDocument,\n documentWriterProjectionFromCreateResponse,\n} from \"./create\";\nexport {\n importDocumentHistoryTailUpdates,\n loadPersistedDocumentContent,\n mergePersistedDocumentHistory,\n} from \"./historyContent\";\nexport { buildMaterializedDocumentLinkSetMutationPlan } from \"./linkSet\";\nexport { relinkRemoteDocument } from \"./linkSet/linkSetRemote\";\nexport {\n enqueuePendingDocumentUpdate,\n listPendingDocumentUpdates,\n} from \"./pendingUpdatePersistence\";\nexport {\n type AttachmentRemovalRows,\n type AttachmentStagingRows,\n DOCUMENTS_APP_KIND,\n type DocumentRecord,\n type DocumentsPersistence,\n defaultDocumentsPersistence,\n type LocalAttachmentRecord,\n loadPersistedDocumentStoreState,\n type PendingAttachmentRecord,\n type PendingAttachmentUploadIdentity,\n type PendingUpdateInsert,\n type PendingUpdateRecord,\n persistDocumentState,\n type RelinkPersistedDocumentInput,\n runSerializedSqlMutation,\n} from \"./persistence\";\nexport {\n createDocumentProjectionUserKeyResolver,\n type DocumentProjectionKeyRuntime,\n type DocumentProjectionUserKeyResolver,\n didDocumentProjectionKeyRuntimeChange,\n} from \"./projectionKeys\";\nexport {\n buildDocumentPurgeRequest,\n purgeRemoteDocument,\n} from \"./purge\";\nexport {\n type DiscardedDocumentShellResult,\n deletePersistedDocument,\n discardPersistedDocumentToShell,\n} from \"./purge/persistedDocumentRemoval\";\nexport {\n createDocumentsWorkflowRuntime,\n type DocumentsWorkflowRuntime,\n type DocumentsWorkflowRuntimeGroups,\n type DocumentsWorkflowRuntimeInfra,\n type DocumentsWorkflowRuntimeInput,\n type DocumentsWorkflowRuntimeInputGroups,\n} from \"./runtime\";\nexport {\n hasDocumentUpdateEvent,\n syncRemoteDocument,\n} from \"./sync\";\nexport type { SyncRemoteDocumentInput } from \"./sync/readOnlySync\";\nexport type { DocumentSyncContainerRekeyBuilder } from \"./sync/syncAttemptState\";\nexport {\n type DocumentSyncLane,\n registerDocumentSyncLane,\n requestDocumentSyncLaneAndWait,\n} from \"./sync/syncLane\";\nexport {\n DOCUMENT_SYNC_TRACE_FRAGMENT,\n DOCUMENT_SYNC_TRACE_PATTERN,\n} from \"./sync/syncTrace\";\nexport {\n describeDocumentRevalidationFailure,\n describeDocumentSyncSubmitFailure,\n type TerminalSubmitFailureHandler,\n} from \"./syncFailures/syncFailureClassification\";\nexport { shouldClearDocumentSyncFailureAfterPass } from \"./syncFailures/syncFailureClearance\";\nexport { DocumentRawHistoryUnavailableError } from \"./syncPlan/syncContentKeys\";\nexport type { RekeyPendingUpdate } from \"./syncRekeys/syncRecoveryRekey\";\nexport { createDocumentWriterPublicKeyResolver } from \"./writerKeys\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,wCAAwC,EAAE,MAAM,uCAAuC,CAAC;AACjG,OAAO,EAGL,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,8DAA8D,CAAC;AACtE,OAAO,EAEL,kCAAkC,EAClC,oBAAoB,GACrB,MAAM,iDAAiD,CAAC;AAOzD,OAAO,EACL,wBAAwB,EACxB,sCAAsC,EACtC,yBAAyB,GAC1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,qCAAqC,EACrC,oCAAoC,GACrC,MAAM,kEAAkE,CAAC;AAE1E,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,EAC/B,mCAAmC,EACnC,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,iCAAiC,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,mCAAmC,EACnC,oBAAoB,EACpB,0CAA0C,GAC3C,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,gCAAgC,EAChC,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,4CAA4C,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,kBAAkB,EAGlB,2BAA2B,EAE3B,+BAA+B,EAK/B,oBAAoB,EAEpB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uCAAuC,EAGvC,qCAAqC,GACtC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,8BAA8B,GAM/B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAGjE,OAAO,EAEL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mCAAmC,EACnC,iCAAiC,GAElC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,uCAAuC,EAAE,MAAM,qCAAqC,CAAC;AAC9F,OAAO,EAAE,kCAAkC,EAAE,MAAM,4BAA4B,CAAC;AAEhF,OAAO,EAAE,qCAAqC,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export {\n unwrapContainerKekPath,\n unwrapDocumentContentKeyTarget,\n} from \"../../data/documents/shared/projection\";\nexport { persistedDocumentCreateStateFromResponse } from \"../../data/documents/shared/responses\";\nexport {\n type DocumentSyncUpdateIsolationError,\n type IncomingDocumentSyncUpdateValidator,\n isDocumentSyncUpdateIsolationError,\n validateDocumentSyncUpdateImports,\n} from \"../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nexport {\n type DocumentSyncPullContinuation,\n documentSyncPullContinuationsEqual,\n readPullContinuation,\n} from \"../../data/documents/shared/sync/syncPagination\";\nexport type {\n DocumentCreateAuthor,\n DocumentLinkSetFailureHandler,\n DocumentLinkSetMutationFailure,\n RelinkRemoteDocumentResult,\n} from \"../../data/documents/shared/types\";\nexport {\n clearDocumentSyncFailure,\n invalidateDocumentSyncPullContinuation,\n recordDocumentSyncFailure,\n} from \"../../data/sqlite/documentPersistence\";\nexport {\n DOCUMENT_HISTORY_COMPACTION_MAX_BYTES,\n DOCUMENT_HISTORY_COMPACTION_MAX_ROWS,\n} from \"../../data/sqlite/documentPersistence/documentHistoryPersistence\";\nexport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nexport { selectDocumentSyncOutgoingBatch } from \"../../data/sync/documentSyncOutgoingBatch\";\nexport { settleOutgoingPassAndDecideReArm } from \"../../data/sync/outgoingUpdateSettlement\";\nexport {\n didRegainSyncPrerequisites,\n isDatabaseUnavailableError,\n} from \"../../data/sync/syncCoordinator\";\nexport {\n deleteLocalDocumentAttachment,\n deletePendingDocumentAttachment,\n markLocalDocumentAttachmentDetached,\n saveLocalDocumentAttachments,\n savePendingDocumentAttachment,\n} from \"./attachments/attachmentPersistence\";\nexport { runSerializedDocumentBlobMutation } from \"./attachments/blobMutationLock\";\nexport { reclaimDocumentOrphanBlobs } from \"./attachments/orphanBlobReclaims\";\nexport { resolveDocumentCreateAuthor } from \"./author\";\nexport {\n buildMaterializedDocumentCreatePlan,\n createRemoteDocument,\n documentWriterProjectionFromCreateResponse,\n} from \"./create\";\nexport {\n importDocumentHistoryTailUpdates,\n loadPersistedDocumentContent,\n mergePersistedDocumentHistory,\n} from \"./historyContent\";\nexport { buildMaterializedDocumentLinkSetMutationPlan } from \"./linkSet\";\nexport { relinkRemoteDocument } from \"./linkSet/linkSetRemote\";\nexport {\n enqueuePendingDocumentUpdate,\n listPendingDocumentUpdates,\n} from \"./pendingUpdatePersistence\";\nexport {\n type AttachmentRemovalRows,\n type AttachmentStagingRows,\n DOCUMENTS_APP_KIND,\n type DocumentRecord,\n type DocumentsPersistence,\n defaultDocumentsPersistence,\n type LocalAttachmentRecord,\n loadPersistedDocumentStoreState,\n type PendingAttachmentRecord,\n type PendingAttachmentUploadIdentity,\n type PendingUpdateInsert,\n type PendingUpdateRecord,\n persistDocumentState,\n type RelinkPersistedDocumentInput,\n runSerializedSqlMutation,\n} from \"./persistence\";\nexport {\n createDocumentProjectionUserKeyResolver,\n type DocumentProjectionKeyRuntime,\n type DocumentProjectionUserKeyResolver,\n didDocumentProjectionKeyRuntimeChange,\n} from \"./projectionKeys\";\nexport {\n buildDocumentPurgeRequest,\n purgeRemoteDocument,\n} from \"./purge\";\nexport {\n type DiscardedDocumentShellResult,\n deletePersistedDocument,\n discardPersistedDocumentToShell,\n} from \"./purge/persistedDocumentRemoval\";\nexport {\n createDocumentsWorkflowRuntime,\n type DocumentsWorkflowRuntime,\n type DocumentsWorkflowRuntimeGroups,\n type DocumentsWorkflowRuntimeInfra,\n type DocumentsWorkflowRuntimeInput,\n type DocumentsWorkflowRuntimeInputGroups,\n} from \"./runtime\";\nexport {\n hasDocumentUpdateEvent,\n syncRemoteDocument,\n} from \"./sync\";\nexport { documentCreateSeedCandidate } from \"./sync/initialSync\";\nexport type { SyncRemoteDocumentInput } from \"./sync/readOnlySync\";\nexport type { DocumentSyncContainerRekeyBuilder } from \"./sync/syncAttemptState\";\nexport {\n type DocumentSyncLane,\n registerDocumentSyncLane,\n requestDocumentSyncLaneAndWait,\n} from \"./sync/syncLane\";\nexport {\n DOCUMENT_SYNC_TRACE_FRAGMENT,\n DOCUMENT_SYNC_TRACE_PATTERN,\n} from \"./sync/syncTrace\";\nexport {\n describeDocumentRevalidationFailure,\n describeDocumentSyncSubmitFailure,\n type TerminalSubmitFailureHandler,\n} from \"./syncFailures/syncFailureClassification\";\nexport { shouldClearDocumentSyncFailureAfterPass } from \"./syncFailures/syncFailureClearance\";\nexport { DocumentRawHistoryUnavailableError } from \"./syncPlan/syncContentKeys\";\nexport type { RekeyPendingUpdate } from \"./syncRekeys/syncRecoveryRekey\";\nexport { createDocumentWriterPublicKeyResolver } from \"./writerKeys\";\n"]}
@@ -0,0 +1,39 @@
1
+ import type { DocumentSyncRequest } from "../../../internal/validators/request/index.js";
2
+ import type { ContainerWriterProjectionResponse } from "../../../internal/validators/response/index.js";
3
+ import type { DocumentCreateAuthor, MaterializedDocumentCreatePlan } from "../../../data/documents/shared/types.js";
4
+ import type { PendingUpdateRecord } from "../../../data/sqlite/documentPersistence/index.js";
5
+ /**
6
+ * Builds the single encrypted initial write for a provisioned document. The
7
+ * server commits it with the organization and document manifest transaction.
8
+ */
9
+ export declare function buildInitialDocumentSyncRequest(input: {
10
+ readonly author: DocumentCreateAuthor;
11
+ readonly containerProjection: ContainerWriterProjectionResponse;
12
+ readonly initialUpdate: Uint8Array;
13
+ readonly materializedDocument: MaterializedDocumentCreatePlan;
14
+ }): Promise<DocumentSyncRequest>;
15
+ /**
16
+ * Builds a create's seed: the one queued update that holds a new document's
17
+ * whole content, signed against the create plan, so the create commits it and
18
+ * no follow-up sync is needed. The update keeps its queue row id.
19
+ */
20
+ export declare function buildDocumentCreateSeedRequest(input: {
21
+ readonly author: DocumentCreateAuthor;
22
+ readonly containerProjection: ContainerWriterProjectionResponse;
23
+ readonly materializedDocument: MaterializedDocumentCreatePlan;
24
+ readonly pendingUpdate: PendingUpdateRecord;
25
+ }): Promise<DocumentSyncRequest>;
26
+ /**
27
+ * The queued row that may seed a create: the only row, a plain update (not a
28
+ * rotation baseline) that holds the document's whole content. Anything else
29
+ * syncs after the create as before.
30
+ */
31
+ export declare function documentCreateSeedCandidate(input: {
32
+ readonly documentVersion: string;
33
+ readonly pendingUpdates: readonly PendingUpdateRecord[];
34
+ }): PendingUpdateRecord | null;
35
+ /**
36
+ * A seed is held to the sync request limit (the API refuses a larger one), so
37
+ * a seed that does not fit is left out and the row syncs in ordinary batches.
38
+ */
39
+ export declare function documentCreateSeedFits(seed: DocumentSyncRequest): boolean;
@@ -1,3 +1,5 @@
1
+ import { emptyVersionVector, satisfiesVersionVector, versionVectorsEqual, } from "../../../internal/loro/index.js";
2
+ import { MAX_DOCUMENT_SYNC_REQUEST_BYTES } from "../../../internal/validators/util/index.js";
1
3
  import { createPendingUpdateFields } from "../../../data/documents/documentSync.js";
2
4
  import { importContentKeyMaterial } from "../../../data/documents/shared/contentRecordKeys.js";
3
5
  import { encryptDocumentPendingUpdate } from "../../../data/documents/shared/crypto.js";
@@ -12,12 +14,20 @@ export async function buildInitialDocumentSyncRequest(input) {
12
14
  if (!pendingFields) {
13
15
  throw new Error("Initial document sync update is empty");
14
16
  }
17
+ return buildDocumentCreateSeedRequest({
18
+ ...input,
19
+ pendingUpdate: { id: crypto.randomUUID(), ...pendingFields },
20
+ });
21
+ }
22
+ /**
23
+ * Builds a create's seed: the one queued update that holds a new document's
24
+ * whole content, signed against the create plan, so the create commits it and
25
+ * no follow-up sync is needed. The update keeps its queue row id.
26
+ */
27
+ export async function buildDocumentCreateSeedRequest(input) {
28
+ const { pendingUpdate } = input;
15
29
  const documentId = input.materializedDocument.plan.documentId;
16
30
  const contentKeyBundle = input.materializedDocument.plan.request.contentKeyBundle;
17
- const pendingUpdate = {
18
- id: crypto.randomUUID(),
19
- ...pendingFields,
20
- };
21
31
  const encrypted = await encryptDocumentPendingUpdate({
22
32
  contentKeyMaterial: await importContentKeyMaterial(input.materializedDocument.contentKey),
23
33
  contentKeyEpoch: contentKeyBundle.contentKeyEpoch,
@@ -55,11 +65,34 @@ export async function buildInitialDocumentSyncRequest(input) {
55
65
  contentKeyEpoch: contentKeyBundle.contentKeyEpoch,
56
66
  expectedLinkSetManifestHash: contentKeyBundle.linkSetManifestHash,
57
67
  expectedTargetHash: contentKeyBundle.targetHash,
58
- // The provisioning device already holds this exact initialized snapshot,
59
- // so it does not need the transaction response to echo the update back.
68
+ // The creating device already holds this exact content, so it does not
69
+ // need the transaction response to echo the update back.
60
70
  localVersionVector: pendingUpdate.partialEndVersionVector,
61
71
  outgoingUpdates: [outgoingUpdate],
62
72
  supportsPullPagination: true,
63
73
  };
64
74
  }
75
+ /**
76
+ * The queued row that may seed a create: the only row, a plain update (not a
77
+ * rotation baseline) that holds the document's whole content. Anything else
78
+ * syncs after the create as before.
79
+ */
80
+ export function documentCreateSeedCandidate(input) {
81
+ const [row, ...rest] = input.pendingUpdates;
82
+ if (!row || rest.length > 0 || row.sourceVersionVector != null)
83
+ return null;
84
+ // The start may name peers at counter zero; the server checks it the same way.
85
+ return satisfiesVersionVector(emptyVersionVector(), row.partialStartVersionVector) && versionVectorsEqual(row.partialEndVersionVector, input.documentVersion)
86
+ ? row
87
+ : null;
88
+ }
89
+ const TEXT_ENCODER = new TextEncoder();
90
+ /**
91
+ * A seed is held to the sync request limit (the API refuses a larger one), so
92
+ * a seed that does not fit is left out and the row syncs in ordinary batches.
93
+ */
94
+ export function documentCreateSeedFits(seed) {
95
+ return (TEXT_ENCODER.encode(JSON.stringify(seed)).byteLength <=
96
+ MAX_DOCUMENT_SYNC_REQUEST_BYTES);
97
+ }
65
98
  //# sourceMappingURL=initialSync.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"initialSync.js","sourceRoot":"","sources":["initialSync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,kDAAkD,CAAC;AAC5F,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAM9E,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,KAKrD;IACC,MAAM,aAAa,GAAG,yBAAyB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACrE,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC;IAC9D,MAAM,gBAAgB,GACpB,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC;IAC3D,MAAM,aAAa,GAAwB;QACzC,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,GAAG,aAAa;KACjB,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,4BAA4B,CAAC;QACnD,kBAAkB,EAAE,MAAM,wBAAwB,CAChD,KAAK,CAAC,oBAAoB,CAAC,UAAU,CACtC;QACD,eAAe,EAAE,gBAAgB,CAAC,eAAe;QACjD,UAAU;QACV,cAAc,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc;QACxD,MAAM,EAAE,aAAa;KACtB,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,MAAM,0BAA0B,CAAC;QACtD,4BAA4B,EAAE;YAC5B,iBAAiB,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC;SAClD;QACD,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,eAAe,EAAE,gBAAgB,CAAC,eAAe;QACjD,UAAU;QACV,2BAA2B,EAAE,gBAAgB,CAAC,mBAAmB;QACjE,kBAAkB,EAAE,gBAAgB,CAAC,UAAU;QAC/C,cAAc,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc;QACxD,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAClC,MAAM,EAAE;YACN,eAAe,EAAE,SAAS,CAAC,eAAe;YAC1C,aAAa,EAAE,SAAS,CAAC,aAAa;YACtC,EAAE,EAAE,aAAa,CAAC,EAAE;YACpB,uBAAuB,EAAE,aAAa,CAAC,uBAAuB;YAC9D,yBAAyB,EAAE,aAAa,CAAC,yBAAyB;YAClE,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,cAAc,EAAE,SAAS,CAAC,cAAc;YACxC,aAAa,EAAE,SAAS,CAAC,aAAa;SACvC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,4BAA4B,EAAE;YAC5B,iBAAiB,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC;SAClD;QACD,gBAAgB;QAChB,eAAe,EAAE,gBAAgB,CAAC,eAAe;QACjD,2BAA2B,EAAE,gBAAgB,CAAC,mBAAmB;QACjE,kBAAkB,EAAE,gBAAgB,CAAC,UAAU;QAC/C,yEAAyE;QACzE,wEAAwE;QACxE,kBAAkB,EAAE,aAAa,CAAC,uBAAuB;QACzD,eAAe,EAAE,CAAC,cAAc,CAAC;QACjC,sBAAsB,EAAE,IAAI;KAC7B,CAAC;AACJ,CAAC","sourcesContent":["import type { DocumentSyncRequest } from \"@tearleads/validators/request\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport { importContentKeyMaterial } from \"../../../data/documents/shared/contentRecordKeys\";\nimport { encryptDocumentPendingUpdate } from \"../../../data/documents/shared/crypto\";\nimport { containerPathRefs } from \"../../../data/documents/shared/projection\";\nimport type {\n DocumentCreateAuthor,\n MaterializedDocumentCreatePlan,\n} from \"../../../data/documents/shared/types\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport { signDocumentOutgoingUpdate } from \"../syncPlan/syncPlanIdentity\";\n\n/**\n * Builds the single encrypted initial write for a provisioned document. The\n * server commits it with the organization and document manifest transaction.\n */\nexport async function buildInitialDocumentSyncRequest(input: {\n readonly author: DocumentCreateAuthor;\n readonly containerProjection: ContainerWriterProjectionResponse;\n readonly initialUpdate: Uint8Array;\n readonly materializedDocument: MaterializedDocumentCreatePlan;\n}): Promise<DocumentSyncRequest> {\n const pendingFields = createPendingUpdateFields(input.initialUpdate);\n if (!pendingFields) {\n throw new Error(\"Initial document sync update is empty\");\n }\n\n const documentId = input.materializedDocument.plan.documentId;\n const contentKeyBundle =\n input.materializedDocument.plan.request.contentKeyBundle;\n const pendingUpdate: PendingUpdateRecord = {\n id: crypto.randomUUID(),\n ...pendingFields,\n };\n const encrypted = await encryptDocumentPendingUpdate({\n contentKeyMaterial: await importContentKeyMaterial(\n input.materializedDocument.contentKey,\n ),\n contentKeyEpoch: contentKeyBundle.contentKeyEpoch,\n documentId,\n organizationId: input.containerProjection.organizationId,\n update: pendingUpdate,\n });\n const outgoingUpdate = await signDocumentOutgoingUpdate({\n authorizingContainerPathRefs: [\n containerPathRefs(input.containerProjection.path),\n ],\n author: input.author,\n contentKeyEpoch: contentKeyBundle.contentKeyEpoch,\n documentId,\n expectedLinkSetManifestHash: contentKeyBundle.linkSetManifestHash,\n expectedTargetHash: contentKeyBundle.targetHash,\n organizationId: input.containerProjection.organizationId,\n signedAt: new Date().toISOString(),\n update: {\n contentRecordId: encrypted.contentRecordId,\n encryptedData: encrypted.encryptedData,\n id: pendingUpdate.id,\n partialEndVersionVector: pendingUpdate.partialEndVersionVector,\n partialStartVersionVector: pendingUpdate.partialStartVersionVector,\n metadataHash: encrypted.metadataHash,\n ciphertextHash: encrypted.ciphertextHash,\n plaintextHash: encrypted.plaintextHash,\n },\n });\n\n return {\n authorizingContainerPathRefs: [\n containerPathRefs(input.containerProjection.path),\n ],\n contentKeyBundle,\n contentKeyEpoch: contentKeyBundle.contentKeyEpoch,\n expectedLinkSetManifestHash: contentKeyBundle.linkSetManifestHash,\n expectedTargetHash: contentKeyBundle.targetHash,\n // The provisioning device already holds this exact initialized snapshot,\n // so it does not need the transaction response to echo the update back.\n localVersionVector: pendingUpdate.partialEndVersionVector,\n outgoingUpdates: [outgoingUpdate],\n supportsPullPagination: true,\n };\n}\n"]}
1
+ {"version":3,"file":"initialSync.js","sourceRoot":"","sources":["initialSync.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n emptyVersionVector,\n satisfiesVersionVector,\n versionVectorsEqual,\n} from \"@tearleads/loro\";\nimport type { DocumentSyncRequest } from \"@tearleads/validators/request\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { MAX_DOCUMENT_SYNC_REQUEST_BYTES } from \"@tearleads/validators/util\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport { importContentKeyMaterial } from \"../../../data/documents/shared/contentRecordKeys\";\nimport { encryptDocumentPendingUpdate } from \"../../../data/documents/shared/crypto\";\nimport { containerPathRefs } from \"../../../data/documents/shared/projection\";\nimport type {\n DocumentCreateAuthor,\n MaterializedDocumentCreatePlan,\n} from \"../../../data/documents/shared/types\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport { signDocumentOutgoingUpdate } from \"../syncPlan/syncPlanIdentity\";\n\n/**\n * Builds the single encrypted initial write for a provisioned document. The\n * server commits it with the organization and document manifest transaction.\n */\nexport async function buildInitialDocumentSyncRequest(input: {\n readonly author: DocumentCreateAuthor;\n readonly containerProjection: ContainerWriterProjectionResponse;\n readonly initialUpdate: Uint8Array;\n readonly materializedDocument: MaterializedDocumentCreatePlan;\n}): Promise<DocumentSyncRequest> {\n const pendingFields = createPendingUpdateFields(input.initialUpdate);\n if (!pendingFields) {\n throw new Error(\"Initial document sync update is empty\");\n }\n return buildDocumentCreateSeedRequest({\n ...input,\n pendingUpdate: { id: crypto.randomUUID(), ...pendingFields },\n });\n}\n\n/**\n * Builds a create's seed: the one queued update that holds a new document's\n * whole content, signed against the create plan, so the create commits it and\n * no follow-up sync is needed. The update keeps its queue row id.\n */\nexport async function buildDocumentCreateSeedRequest(input: {\n readonly author: DocumentCreateAuthor;\n readonly containerProjection: ContainerWriterProjectionResponse;\n readonly materializedDocument: MaterializedDocumentCreatePlan;\n readonly pendingUpdate: PendingUpdateRecord;\n}): Promise<DocumentSyncRequest> {\n const { pendingUpdate } = input;\n const documentId = input.materializedDocument.plan.documentId;\n const contentKeyBundle =\n input.materializedDocument.plan.request.contentKeyBundle;\n const encrypted = await encryptDocumentPendingUpdate({\n contentKeyMaterial: await importContentKeyMaterial(\n input.materializedDocument.contentKey,\n ),\n contentKeyEpoch: contentKeyBundle.contentKeyEpoch,\n documentId,\n organizationId: input.containerProjection.organizationId,\n update: pendingUpdate,\n });\n const outgoingUpdate = await signDocumentOutgoingUpdate({\n authorizingContainerPathRefs: [\n containerPathRefs(input.containerProjection.path),\n ],\n author: input.author,\n contentKeyEpoch: contentKeyBundle.contentKeyEpoch,\n documentId,\n expectedLinkSetManifestHash: contentKeyBundle.linkSetManifestHash,\n expectedTargetHash: contentKeyBundle.targetHash,\n organizationId: input.containerProjection.organizationId,\n signedAt: new Date().toISOString(),\n update: {\n contentRecordId: encrypted.contentRecordId,\n encryptedData: encrypted.encryptedData,\n id: pendingUpdate.id,\n partialEndVersionVector: pendingUpdate.partialEndVersionVector,\n partialStartVersionVector: pendingUpdate.partialStartVersionVector,\n metadataHash: encrypted.metadataHash,\n ciphertextHash: encrypted.ciphertextHash,\n plaintextHash: encrypted.plaintextHash,\n },\n });\n\n return {\n authorizingContainerPathRefs: [\n containerPathRefs(input.containerProjection.path),\n ],\n contentKeyBundle,\n contentKeyEpoch: contentKeyBundle.contentKeyEpoch,\n expectedLinkSetManifestHash: contentKeyBundle.linkSetManifestHash,\n expectedTargetHash: contentKeyBundle.targetHash,\n // The creating device already holds this exact content, so it does not\n // need the transaction response to echo the update back.\n localVersionVector: pendingUpdate.partialEndVersionVector,\n outgoingUpdates: [outgoingUpdate],\n supportsPullPagination: true,\n };\n}\n\n/**\n * The queued row that may seed a create: the only row, a plain update (not a\n * rotation baseline) that holds the document's whole content. Anything else\n * syncs after the create as before.\n */\nexport function documentCreateSeedCandidate(input: {\n readonly documentVersion: string;\n readonly pendingUpdates: readonly PendingUpdateRecord[];\n}): PendingUpdateRecord | null {\n const [row, ...rest] = input.pendingUpdates;\n if (!row || rest.length > 0 || row.sourceVersionVector != null) return null;\n // The start may name peers at counter zero; the server checks it the same way.\n return satisfiesVersionVector(\n emptyVersionVector(),\n row.partialStartVersionVector,\n ) && versionVectorsEqual(row.partialEndVersionVector, input.documentVersion)\n ? row\n : null;\n}\n\nconst TEXT_ENCODER = new TextEncoder();\n\n/**\n * A seed is held to the sync request limit (the API refuses a larger one), so\n * a seed that does not fit is left out and the row syncs in ordinary batches.\n */\nexport function documentCreateSeedFits(seed: DocumentSyncRequest): boolean {\n return (\n TEXT_ENCODER.encode(JSON.stringify(seed)).byteLength <=\n MAX_DOCUMENT_SYNC_REQUEST_BYTES\n );\n}\n"]}