@tearleads/client-sdk 0.1.33 → 0.1.35
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.
- package/client/containerContents.js +1 -1
- package/client/containerContents.js.map +1 -1
- package/client/containerContentsTypes.d.ts +2 -0
- package/client/containerContentsTypes.js.map +1 -1
- package/client/documents.js +1 -1
- package/client/documents.js.map +1 -1
- package/data/blobs/transferPool.js +53 -0
- package/data/blobs/transferPool.js.map +1 -0
- package/data/documents/blob/shared/types.d.ts +2 -2
- package/data/documents/blob/shared/types.js.map +1 -1
- package/data/sync/coordinatorLaneRun.js +154 -0
- package/data/sync/coordinatorLaneRun.js.map +1 -0
- package/data/sync/coordinatorPump.js +72 -169
- package/data/sync/coordinatorPump.js.map +1 -1
- package/data/sync/coordinatorState.d.ts +6 -0
- package/data/sync/coordinatorState.js +3 -1
- package/data/sync/coordinatorState.js.map +1 -1
- package/data/sync/syncCoordinator.js +4 -3
- package/data/sync/syncCoordinator.js.map +1 -1
- package/data/sync/syncLaneConfig.d.ts +2 -0
- package/data/sync/syncLaneConfig.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js.map +1 -1
- package/internal/api-client/ApiClient.d.ts +2 -2
- package/internal/api-client/ApiClient.js +4 -4
- package/internal/api-client/ApiClient.js.map +1 -1
- package/internal/api-client/routes/blobs/get.d.ts +2 -2
- package/internal/api-client/routes/blobs/get.js +24 -21
- package/internal/api-client/routes/blobs/get.js.map +1 -1
- package/internal/api-client/routes/blobs/multipartUpload.js +16 -9
- package/internal/api-client/routes/blobs/multipartUpload.js.map +1 -1
- package/internal/api-client/routes/blobs/storageFetchOptions.js +11 -0
- package/internal/api-client/routes/blobs/storageFetchOptions.js.map +1 -0
- package/package.json +1 -1
- package/stores/documents/documentStore/attachmentHydration.js +33 -0
- package/stores/documents/documentStore/attachmentHydration.js.map +1 -1
- package/stores/documents/documentStore/attachmentRemoval.js +136 -0
- package/stores/documents/documentStore/attachmentRemoval.js.map +1 -0
- package/stores/documents/documentStore/attachments.js +31 -135
- package/stores/documents/documentStore/attachments.js.map +1 -1
- package/stores/documents/documentStore/deferredInitialUpdate.js +108 -0
- package/stores/documents/documentStore/deferredInitialUpdate.js.map +1 -0
- package/stores/documents/documentStore/initialization.js +10 -2
- package/stores/documents/documentStore/initialization.js.map +1 -1
- package/stores/documents/documentStore/persistence.js +7 -0
- package/stores/documents/documentStore/persistence.js.map +1 -1
- package/stores/documents/documentStore/remoteWork.js +1 -1
- package/stores/documents/documentStore/remoteWork.js.map +1 -1
- package/stores/documents/documentStore/state.js +1 -0
- package/stores/documents/documentStore/state.js.map +1 -1
- package/stores/documents/documentStore/sync.js +8 -1
- package/stores/documents/documentStore/sync.js.map +1 -1
- package/stores/documents/documentStore.d.ts +4 -4
- package/stores/documents/documentStore.js +14 -11
- package/stores/documents/documentStore.js.map +1 -1
- package/stores/documents/types.d.ts +9 -0
- package/stores/documents/types.js.map +1 -1
- package/sync/reconciliation/documentContentPull.js +7 -3
- package/sync/reconciliation/documentContentPull.js.map +1 -1
- package/sync/reconciliation/idleBackfill.js +14 -2
- package/sync/reconciliation/idleBackfill.js.map +1 -1
- package/sync/reconciliation/knownContainerSweep.js +5 -2
- package/sync/reconciliation/knownContainerSweep.js.map +1 -1
- package/sync/reconciliation/reconcileContainer.js +3 -3
- package/sync/reconciliation/reconcileContainer.js.map +1 -1
- package/sync/reconciliation/service.js +9 -4
- package/sync/reconciliation/service.js.map +1 -1
- package/sync/reconciliation/serviceTypes.d.ts +5 -3
- package/sync/reconciliation/serviceTypes.js.map +1 -1
- package/sync/reconciliation/triggers.d.ts +2 -1
- package/sync/reconciliation/triggers.js +5 -2
- package/sync/reconciliation/triggers.js.map +1 -1
- package/workflows/blobs/hydrate.d.ts +4 -2
- package/workflows/blobs/hydrate.js +21 -7
- package/workflows/blobs/hydrate.js.map +1 -1
- package/workflows/blobs/multipartUpload.js +57 -30
- package/workflows/blobs/multipartUpload.js.map +1 -1
- package/workflows/blobs/readAttachmentTransfer.js +42 -0
- package/workflows/blobs/readAttachmentTransfer.js.map +1 -0
- package/workflows/documents/syncLane.d.ts +1 -0
- package/workflows/documents/syncLane.js +1 -0
- package/workflows/documents/syncLane.js.map +1 -1
- package/workflows/registration/persistRegistrationBootstrap.js +3 -0
- package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
|
@@ -91,7 +91,7 @@ class ContainerContentsService {
|
|
|
91
91
|
const runtime = this.workflowRuntime();
|
|
92
92
|
const resolveProjectionUserKey = createContainerContentsDocumentProjectionUserKeyResolver(runtime);
|
|
93
93
|
const documentRuntime = (containerId) => createContainerContentsDocumentsRuntime(runtime, containerId);
|
|
94
|
-
const openContainerDocument = (input) => openDocumentStore(runtime.state.domainScope, input.localId, documentRuntime(input.containerId), input.documentId ?? null, input.initialText, input.initialDocumentKind);
|
|
94
|
+
const openContainerDocument = (input) => openDocumentStore(runtime.state.domainScope, input.localId, documentRuntime(input.containerId), input.documentId ?? null, input.initialText, input.initialDocumentKind, { deferInitialUpdate: input.deferInitialUpdate });
|
|
95
95
|
const documentLinks = {
|
|
96
96
|
...runtime,
|
|
97
97
|
documentRuntime,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerContents.js","sourceRoot":"","sources":["containerContents.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../data/documents/documentConstants\";\nimport type { DocumentSummary } from \"../data/documents/documentSummary\";\nimport { inheritPrincipalHistoryProtection } from \"../data/principals/principalHistoryRuntime\";\nimport {\n type ContainerContentsStore,\n type ContainerContentsStoreOptions,\n getOrCreateContainerContentsStore,\n} from \"../stores/container-contents\";\nimport { openDocumentStore } from \"../stores/documents\";\nimport { relinkDocumentStoreWithCommitSideEffect } from \"../stores/documents/documentStore/internalRelink\";\nimport {\n type BlobInfoInput,\n type BlobInfoList,\n listBlobInfo,\n} from \"../workflows/container-contents/blobInfo\";\nimport {\n type ContainerInfo,\n loadContainerInfo,\n} from \"../workflows/container-contents/containerInfo\";\nimport {\n type DocumentAttributionRangesInput,\n type DocumentAttributionRangesPage,\n loadDocumentAttributionRanges,\n} from \"../workflows/container-contents/documentAttributionRanges\";\nimport {\n type DocumentInfo,\n loadDocumentInfo,\n} from \"../workflows/container-contents/documentInfo\";\nimport {\n purgeLocalContainerDocument,\n purgeRemoteContainerDocument,\n} from \"../workflows/container-contents/documentPurge\";\nimport {\n type ContainerDocumentQueries,\n createContainerDocumentQueriesFromRuntime,\n} from \"../workflows/container-contents/documentQueries\";\nimport {\n activateDocumentLink,\n addDocumentLink,\n canMutateDocumentLink,\n canMutateLocalDocumentLink,\n type DocumentStructuralMutationHost,\n moveDocumentLink,\n removeDocumentLink,\n} from \"../workflows/container-contents/documentStructure\";\nimport { createContainerContentsDocumentProjectionUserKeyResolver } from \"../workflows/container-contents/projectionKeys\";\nimport {\n type ContainerContentsStoreWorkflowRuntime,\n createContainerContentsDocumentsRuntime,\n createContainerContentsStoreWorkflowRuntime,\n} from \"../workflows/container-contents/runtime\";\nimport { createContainerDocumentObjectSyncState } from \"../workflows/container-contents/syncState\";\nimport type { DocumentsWorkflowRuntime } from \"../workflows/documents\";\nimport type {\n ContainerContents,\n ContainerDocumentLinks,\n ContainerInfoInput,\n DocumentInfoInput,\n MergeDocumentSummary,\n MoveDocumentToContainerInput,\n OpenContainerDocumentInput,\n} from \"./containerContentsTypes\";\nimport { discoverContainerDocumentsForRuntime } from \"./containerDocumentDiscovery\";\nimport {\n createOrganizationReadModelCoordinator,\n type OrganizationReadModelCoordinator,\n} from \"./organizations/organizationReadModels\";\nimport type {\n InternalRuntime,\n InternalWorkflowRuntimeInput,\n} from \"./workflowRuntime\";\n\nexport type {\n ContainerContentsContextValue,\n ContainerContentsStore,\n ContainerContentsStoreOptions,\n ContainerNode,\n} from \"../stores/container-contents\";\nexport type {\n BlobInfo,\n BlobInfoAttachmentKind,\n BlobInfoDocumentReference,\n BlobInfoInput,\n BlobInfoList,\n BlobInfoSort,\n BlobInfoSortDirection,\n BlobInfoSortKey,\n} from \"../workflows/container-contents/blobInfo\";\nexport type {\n ContainerInfo,\n ContainerShareAccessLevel,\n} from \"../workflows/container-contents/containerInfo\";\nexport type {\n DocumentAttributionRangesInput,\n DocumentAttributionRangesPage,\n} from \"../workflows/container-contents/documentAttributionRanges\";\nexport type { DocumentInfo } from \"../workflows/container-contents/documentInfo\";\nexport type {\n ContainerDocumentQueries,\n ContainerDocumentSidebarRow,\n ContainerItemRow,\n ContainerItemSort,\n ContainerItemSortDirection,\n ContainerItemSortKey,\n} from \"../workflows/container-contents/documentQueries\";\nexport type { SetLinkedContainerIdsForDocument } from \"../workflows/container-contents/documentStructure\";\nexport type {\n PendingWriteQueueItem,\n PendingWriteQueueItemStatus,\n PendingWriteQueueObjectKind,\n PendingWriteQueueOperation,\n PendingWriteQueueOperationKind,\n PendingWriteQueueOperationStatus,\n} from \"../workflows/container-contents/pendingWrites\";\nexport type {\n ContainerDocumentObjectSyncState,\n ContainerDocumentObjectSyncStatus,\n} from \"../workflows/container-contents/syncState\";\nexport type {\n ContainerContents,\n ContainerDocumentLinkInput,\n ContainerDocumentLinks,\n ContainerInfoInput,\n DocumentInfoInput,\n LinkDocumentToContainerInput,\n MergeDocumentSummary,\n MoveDocumentToContainerInput,\n OpenContainerDocumentInput,\n PurgeDocumentInput,\n PurgeDocumentResult,\n SetActiveDocumentContainerInput,\n UnlinkDocumentFromContainerInput,\n} from \"./containerContentsTypes\";\n\nexport { createContainerDocumentObjectSyncState };\n\nexport function createContainerContents(\n runtime: InternalRuntime,\n): ContainerContents {\n return new ContainerContentsService(runtime);\n}\n\nfunction createDocumentLinkHost(\n runtime: ContainerDocumentLinks,\n mergeDocumentSummary: MergeDocumentSummary,\n): DocumentStructuralMutationHost<DocumentsWorkflowRuntime> {\n return {\n documentWorkflowRuntime: runtime.documentRuntime,\n mergeDocumentSummary,\n openDocumentStore: (input) => {\n const store = runtime.openDocument({\n containerId: input.containerId,\n documentId: input.documentId,\n localId: input.localId,\n });\n return {\n ...store,\n relink: ({ commitSideEffect, ...relinkInput }) =>\n commitSideEffect\n ? relinkDocumentStoreWithCommitSideEffect(\n store,\n relinkInput,\n commitSideEffect,\n )\n : store.relink(relinkInput),\n };\n },\n };\n}\n\nfunction moveDocumentLinkNote(\n input: Pick<MoveDocumentToContainerInput, \"note\" | \"sourceContainerId\">,\n): DocumentSummary {\n if (\n input.note.documentId &&\n input.sourceContainerId &&\n input.sourceContainerId !== input.note.containerId\n ) {\n return { ...input.note, containerId: input.sourceContainerId };\n }\n\n return input.note;\n}\n\ninterface ContainerInfoOrganizationScope {\n readonly domainScope: InternalWorkflowRuntimeInput[\"state\"][\"domainScope\"];\n readonly organizationId: string;\n readonly userId: string;\n}\n\nfunction readyExecSql(\n runtime: InternalWorkflowRuntimeInput,\n): InternalWorkflowRuntimeInput[\"infra\"][\"execSql\"] | null {\n return runtime.infra.dbStatus === \"ready\" ? runtime.infra.execSql : null;\n}\n\nfunction isActiveContainerInfoOrganizationScope(\n runtime: InternalWorkflowRuntimeInput,\n scope: ContainerInfoOrganizationScope,\n): boolean {\n return (\n runtime.auth.isAuthenticated &&\n runtime.auth.organizationId === scope.organizationId &&\n runtime.auth.userId === scope.userId &&\n runtime.state.domainScope === scope.domainScope\n );\n}\n\nfunction purgeDocumentFromLinks(input: {\n readonly document: Parameters<ContainerDocumentLinks[\"purgeDocument\"]>[0];\n readonly resolveProjectionUserKey: ContainerDocumentLinks[\"resolveProjectionUserKey\"];\n readonly runtime: ContainerDocumentLinks;\n}) {\n const { note } = input.document;\n if (!note.documentId) {\n return purgeLocalContainerDocument({\n noteId: note.id,\n runtime: input.runtime,\n });\n }\n return purgeRemoteContainerDocument({\n documentId: note.documentId,\n documentKind: note.documentKind ?? DEFAULT_DOCUMENT_KIND,\n noteId: note.id,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n runtime: input.runtime,\n });\n}\n\nclass ContainerContentsService implements ContainerContents {\n private readonly organizationReadModels: OrganizationReadModelCoordinator;\n\n constructor(private readonly runtimeService: InternalRuntime) {\n this.organizationReadModels =\n createOrganizationReadModelCoordinator(runtimeService);\n }\n\n openTree(\n options?: ContainerContentsStoreOptions | undefined,\n ): ContainerContentsStore {\n const runtime = this.workflowRuntime();\n const store = getOrCreateContainerContentsStore(\n runtime.state.domainScope,\n runtime,\n options,\n );\n return store;\n }\n\n documentQueries(): ContainerDocumentQueries {\n return createContainerDocumentQueriesFromRuntime(this.workflowRuntime());\n }\n\n documentLinks(): ContainerDocumentLinks {\n const runtime = this.workflowRuntime();\n const resolveProjectionUserKey =\n createContainerContentsDocumentProjectionUserKeyResolver(runtime);\n const documentRuntime = (containerId: string | null) =>\n createContainerContentsDocumentsRuntime(runtime, containerId);\n const openContainerDocument = (input: OpenContainerDocumentInput) =>\n openDocumentStore(\n runtime.state.domainScope,\n input.localId,\n documentRuntime(input.containerId),\n input.documentId ?? null,\n input.initialText,\n input.initialDocumentKind,\n );\n const documentLinks: ContainerDocumentLinks = {\n ...runtime,\n documentRuntime,\n openDocument: openContainerDocument,\n setActiveDocumentContainer: (input) =>\n activateDocumentLink({\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: input.note,\n runtime: documentLinks,\n targetContainerId: input.targetContainerId,\n }),\n canMutateDocumentLinks: canMutateDocumentLink(runtime),\n canMutateUnsyncedDocumentLinks: canMutateLocalDocumentLink(runtime),\n linkDocumentToContainer: (input) =>\n addDocumentLink({\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: input.note,\n runtime: documentLinks,\n scheduleSync: () => this.openTree().requestSync(),\n setLinkedContainerIdsForDocument:\n input.setLinkedContainerIdsForDocument,\n targetContainerId: input.targetContainerId,\n }),\n moveDocumentToContainer: (input) =>\n moveDocumentLink({\n expandNode: input.expandNode,\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: moveDocumentLinkNote(input),\n replaceLinkedContainers: input.replaceLinkedContainers,\n runtime: documentLinks,\n scheduleSync: () => this.openTree().requestSync(),\n setLinkedContainerIdsForDocument:\n input.setLinkedContainerIdsForDocument,\n targetContainerId: input.targetContainerId,\n }),\n purgeDocument: (document) =>\n purgeDocumentFromLinks({\n document,\n resolveProjectionUserKey,\n runtime: documentLinks,\n }),\n resolveProjectionUserKey,\n unlinkDocumentFromContainer: (input) =>\n removeDocumentLink({\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: input.note,\n removedContainerId: input.removedContainerId,\n runtime: documentLinks,\n scheduleSync: () => this.openTree().requestSync(),\n setLinkedContainerIdsForDocument:\n input.setLinkedContainerIdsForDocument,\n }),\n };\n\n return inheritPrincipalHistoryProtection(runtime, documentLinks);\n }\n\n discoverContainerDocuments(\n containerId: string,\n ): Promise<ReadonlyArray<DocumentSummary> | null> {\n return discoverContainerDocumentsForRuntime({\n containerId,\n runtimeService: this.runtimeService,\n });\n }\n\n pullDocumentContent(input: {\n containerId: string;\n localId: string;\n documentId?: string | null | undefined;\n }): void {\n const runtime = this.workflowRuntime();\n const store = openDocumentStore(\n runtime.state.domainScope,\n input.localId,\n createContainerContentsDocumentsRuntime(runtime, input.containerId),\n input.documentId ?? null,\n );\n store.requestRemoteSync();\n }\n\n loadContainerInfo(input: ContainerInfoInput): Promise<ContainerInfo> {\n const runtime = this.runtimeService.workflowInput();\n const organizationScope =\n runtime.auth.isAuthenticated &&\n runtime.auth.organizationId &&\n runtime.auth.userId\n ? {\n domainScope: runtime.state.domainScope,\n organizationId: runtime.auth.organizationId,\n userId: runtime.auth.userId,\n }\n : null;\n const cachedContainerProjection =\n input.remoteInfoMode === \"always\"\n ? null\n : this.openTree().getCachedContainerWriterProjection(input.containerId);\n return loadContainerInfo({\n ...input,\n apiClient: runtime.apiClient,\n containerProjection: cachedContainerProjection,\n execSql: readyExecSql(runtime),\n loadOrganizationGroups: async () => {\n if (\n !organizationScope ||\n !isActiveContainerInfoOrganizationScope(\n this.runtimeService.workflowInput(),\n organizationScope,\n )\n ) {\n return [];\n }\n // Organization groups are disposable presentation data. Container\n // writer projections remain the authority for grants and access.\n const projection = await this.organizationReadModels.loadLocal(\n organizationScope.organizationId,\n );\n return isActiveContainerInfoOrganizationScope(\n this.runtimeService.workflowInput(),\n organizationScope,\n )\n ? (projection?.groups ?? [])\n : [];\n },\n parentId: input.parentId ?? null,\n });\n }\n\n loadDocumentInfo(input: DocumentInfoInput): Promise<DocumentInfo> {\n const runtime = this.runtimeService.workflowInput();\n return loadDocumentInfo({\n ...input,\n apiClient: runtime.apiClient,\n execSql: readyExecSql(runtime),\n reportSecurityIncident: runtime.util.reportSecurityIncident,\n });\n }\n\n loadDocumentEditAttribution(\n documentId: string,\n ): ReturnType<ContainerContents[\"loadDocumentEditAttribution\"]> {\n return this.runtimeService\n .workflowInput()\n .apiClient.getDocumentEditAttribution(documentId);\n }\n\n loadDocumentAttributionRanges(\n input: DocumentAttributionRangesInput,\n ): Promise<DocumentAttributionRangesPage> {\n return loadDocumentAttributionRanges({\n apiClient: this.runtimeService.workflowInput().apiClient,\n query: input,\n });\n }\n\n listBlobInfo(input: BlobInfoInput = {}): Promise<BlobInfoList> {\n const runtime = this.runtimeService.workflowInput();\n return listBlobInfo({\n ...input,\n execSql: readyExecSql(runtime),\n });\n }\n\n workflowRuntime(): ContainerContentsStoreWorkflowRuntime {\n return createContainerContentsStoreWorkflowRuntime(\n this.runtimeService.workflowInput(),\n this.runtimeService.adoptRootContainer,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerContents.js","sourceRoot":"","sources":["containerContents.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../data/documents/documentConstants\";\nimport type { DocumentSummary } from \"../data/documents/documentSummary\";\nimport { inheritPrincipalHistoryProtection } from \"../data/principals/principalHistoryRuntime\";\nimport {\n type ContainerContentsStore,\n type ContainerContentsStoreOptions,\n getOrCreateContainerContentsStore,\n} from \"../stores/container-contents\";\nimport { openDocumentStore } from \"../stores/documents\";\nimport { relinkDocumentStoreWithCommitSideEffect } from \"../stores/documents/documentStore/internalRelink\";\nimport {\n type BlobInfoInput,\n type BlobInfoList,\n listBlobInfo,\n} from \"../workflows/container-contents/blobInfo\";\nimport {\n type ContainerInfo,\n loadContainerInfo,\n} from \"../workflows/container-contents/containerInfo\";\nimport {\n type DocumentAttributionRangesInput,\n type DocumentAttributionRangesPage,\n loadDocumentAttributionRanges,\n} from \"../workflows/container-contents/documentAttributionRanges\";\nimport {\n type DocumentInfo,\n loadDocumentInfo,\n} from \"../workflows/container-contents/documentInfo\";\nimport {\n purgeLocalContainerDocument,\n purgeRemoteContainerDocument,\n} from \"../workflows/container-contents/documentPurge\";\nimport {\n type ContainerDocumentQueries,\n createContainerDocumentQueriesFromRuntime,\n} from \"../workflows/container-contents/documentQueries\";\nimport {\n activateDocumentLink,\n addDocumentLink,\n canMutateDocumentLink,\n canMutateLocalDocumentLink,\n type DocumentStructuralMutationHost,\n moveDocumentLink,\n removeDocumentLink,\n} from \"../workflows/container-contents/documentStructure\";\nimport { createContainerContentsDocumentProjectionUserKeyResolver } from \"../workflows/container-contents/projectionKeys\";\nimport {\n type ContainerContentsStoreWorkflowRuntime,\n createContainerContentsDocumentsRuntime,\n createContainerContentsStoreWorkflowRuntime,\n} from \"../workflows/container-contents/runtime\";\nimport { createContainerDocumentObjectSyncState } from \"../workflows/container-contents/syncState\";\nimport type { DocumentsWorkflowRuntime } from \"../workflows/documents\";\nimport type {\n ContainerContents,\n ContainerDocumentLinks,\n ContainerInfoInput,\n DocumentInfoInput,\n MergeDocumentSummary,\n MoveDocumentToContainerInput,\n OpenContainerDocumentInput,\n} from \"./containerContentsTypes\";\nimport { discoverContainerDocumentsForRuntime } from \"./containerDocumentDiscovery\";\nimport {\n createOrganizationReadModelCoordinator,\n type OrganizationReadModelCoordinator,\n} from \"./organizations/organizationReadModels\";\nimport type {\n InternalRuntime,\n InternalWorkflowRuntimeInput,\n} from \"./workflowRuntime\";\n\nexport type {\n ContainerContentsContextValue,\n ContainerContentsStore,\n ContainerContentsStoreOptions,\n ContainerNode,\n} from \"../stores/container-contents\";\nexport type {\n BlobInfo,\n BlobInfoAttachmentKind,\n BlobInfoDocumentReference,\n BlobInfoInput,\n BlobInfoList,\n BlobInfoSort,\n BlobInfoSortDirection,\n BlobInfoSortKey,\n} from \"../workflows/container-contents/blobInfo\";\nexport type {\n ContainerInfo,\n ContainerShareAccessLevel,\n} from \"../workflows/container-contents/containerInfo\";\nexport type {\n DocumentAttributionRangesInput,\n DocumentAttributionRangesPage,\n} from \"../workflows/container-contents/documentAttributionRanges\";\nexport type { DocumentInfo } from \"../workflows/container-contents/documentInfo\";\nexport type {\n ContainerDocumentQueries,\n ContainerDocumentSidebarRow,\n ContainerItemRow,\n ContainerItemSort,\n ContainerItemSortDirection,\n ContainerItemSortKey,\n} from \"../workflows/container-contents/documentQueries\";\nexport type { SetLinkedContainerIdsForDocument } from \"../workflows/container-contents/documentStructure\";\nexport type {\n PendingWriteQueueItem,\n PendingWriteQueueItemStatus,\n PendingWriteQueueObjectKind,\n PendingWriteQueueOperation,\n PendingWriteQueueOperationKind,\n PendingWriteQueueOperationStatus,\n} from \"../workflows/container-contents/pendingWrites\";\nexport type {\n ContainerDocumentObjectSyncState,\n ContainerDocumentObjectSyncStatus,\n} from \"../workflows/container-contents/syncState\";\nexport type {\n ContainerContents,\n ContainerDocumentLinkInput,\n ContainerDocumentLinks,\n ContainerInfoInput,\n DocumentInfoInput,\n LinkDocumentToContainerInput,\n MergeDocumentSummary,\n MoveDocumentToContainerInput,\n OpenContainerDocumentInput,\n PurgeDocumentInput,\n PurgeDocumentResult,\n SetActiveDocumentContainerInput,\n UnlinkDocumentFromContainerInput,\n} from \"./containerContentsTypes\";\n\nexport { createContainerDocumentObjectSyncState };\n\nexport function createContainerContents(\n runtime: InternalRuntime,\n): ContainerContents {\n return new ContainerContentsService(runtime);\n}\n\nfunction createDocumentLinkHost(\n runtime: ContainerDocumentLinks,\n mergeDocumentSummary: MergeDocumentSummary,\n): DocumentStructuralMutationHost<DocumentsWorkflowRuntime> {\n return {\n documentWorkflowRuntime: runtime.documentRuntime,\n mergeDocumentSummary,\n openDocumentStore: (input) => {\n const store = runtime.openDocument({\n containerId: input.containerId,\n documentId: input.documentId,\n localId: input.localId,\n });\n return {\n ...store,\n relink: ({ commitSideEffect, ...relinkInput }) =>\n commitSideEffect\n ? relinkDocumentStoreWithCommitSideEffect(\n store,\n relinkInput,\n commitSideEffect,\n )\n : store.relink(relinkInput),\n };\n },\n };\n}\n\nfunction moveDocumentLinkNote(\n input: Pick<MoveDocumentToContainerInput, \"note\" | \"sourceContainerId\">,\n): DocumentSummary {\n if (\n input.note.documentId &&\n input.sourceContainerId &&\n input.sourceContainerId !== input.note.containerId\n ) {\n return { ...input.note, containerId: input.sourceContainerId };\n }\n\n return input.note;\n}\n\ninterface ContainerInfoOrganizationScope {\n readonly domainScope: InternalWorkflowRuntimeInput[\"state\"][\"domainScope\"];\n readonly organizationId: string;\n readonly userId: string;\n}\n\nfunction readyExecSql(\n runtime: InternalWorkflowRuntimeInput,\n): InternalWorkflowRuntimeInput[\"infra\"][\"execSql\"] | null {\n return runtime.infra.dbStatus === \"ready\" ? runtime.infra.execSql : null;\n}\n\nfunction isActiveContainerInfoOrganizationScope(\n runtime: InternalWorkflowRuntimeInput,\n scope: ContainerInfoOrganizationScope,\n): boolean {\n return (\n runtime.auth.isAuthenticated &&\n runtime.auth.organizationId === scope.organizationId &&\n runtime.auth.userId === scope.userId &&\n runtime.state.domainScope === scope.domainScope\n );\n}\n\nfunction purgeDocumentFromLinks(input: {\n readonly document: Parameters<ContainerDocumentLinks[\"purgeDocument\"]>[0];\n readonly resolveProjectionUserKey: ContainerDocumentLinks[\"resolveProjectionUserKey\"];\n readonly runtime: ContainerDocumentLinks;\n}) {\n const { note } = input.document;\n if (!note.documentId) {\n return purgeLocalContainerDocument({\n noteId: note.id,\n runtime: input.runtime,\n });\n }\n return purgeRemoteContainerDocument({\n documentId: note.documentId,\n documentKind: note.documentKind ?? DEFAULT_DOCUMENT_KIND,\n noteId: note.id,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n runtime: input.runtime,\n });\n}\n\nclass ContainerContentsService implements ContainerContents {\n private readonly organizationReadModels: OrganizationReadModelCoordinator;\n\n constructor(private readonly runtimeService: InternalRuntime) {\n this.organizationReadModels =\n createOrganizationReadModelCoordinator(runtimeService);\n }\n\n openTree(\n options?: ContainerContentsStoreOptions | undefined,\n ): ContainerContentsStore {\n const runtime = this.workflowRuntime();\n const store = getOrCreateContainerContentsStore(\n runtime.state.domainScope,\n runtime,\n options,\n );\n return store;\n }\n\n documentQueries(): ContainerDocumentQueries {\n return createContainerDocumentQueriesFromRuntime(this.workflowRuntime());\n }\n\n documentLinks(): ContainerDocumentLinks {\n const runtime = this.workflowRuntime();\n const resolveProjectionUserKey =\n createContainerContentsDocumentProjectionUserKeyResolver(runtime);\n const documentRuntime = (containerId: string | null) =>\n createContainerContentsDocumentsRuntime(runtime, containerId);\n const openContainerDocument = (input: OpenContainerDocumentInput) =>\n openDocumentStore(\n runtime.state.domainScope,\n input.localId,\n documentRuntime(input.containerId),\n input.documentId ?? null,\n input.initialText,\n input.initialDocumentKind,\n { deferInitialUpdate: input.deferInitialUpdate },\n );\n const documentLinks: ContainerDocumentLinks = {\n ...runtime,\n documentRuntime,\n openDocument: openContainerDocument,\n setActiveDocumentContainer: (input) =>\n activateDocumentLink({\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: input.note,\n runtime: documentLinks,\n targetContainerId: input.targetContainerId,\n }),\n canMutateDocumentLinks: canMutateDocumentLink(runtime),\n canMutateUnsyncedDocumentLinks: canMutateLocalDocumentLink(runtime),\n linkDocumentToContainer: (input) =>\n addDocumentLink({\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: input.note,\n runtime: documentLinks,\n scheduleSync: () => this.openTree().requestSync(),\n setLinkedContainerIdsForDocument:\n input.setLinkedContainerIdsForDocument,\n targetContainerId: input.targetContainerId,\n }),\n moveDocumentToContainer: (input) =>\n moveDocumentLink({\n expandNode: input.expandNode,\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: moveDocumentLinkNote(input),\n replaceLinkedContainers: input.replaceLinkedContainers,\n runtime: documentLinks,\n scheduleSync: () => this.openTree().requestSync(),\n setLinkedContainerIdsForDocument:\n input.setLinkedContainerIdsForDocument,\n targetContainerId: input.targetContainerId,\n }),\n purgeDocument: (document) =>\n purgeDocumentFromLinks({\n document,\n resolveProjectionUserKey,\n runtime: documentLinks,\n }),\n resolveProjectionUserKey,\n unlinkDocumentFromContainer: (input) =>\n removeDocumentLink({\n host: createDocumentLinkHost(\n documentLinks,\n input.mergeDocumentSummary,\n ),\n note: input.note,\n removedContainerId: input.removedContainerId,\n runtime: documentLinks,\n scheduleSync: () => this.openTree().requestSync(),\n setLinkedContainerIdsForDocument:\n input.setLinkedContainerIdsForDocument,\n }),\n };\n\n return inheritPrincipalHistoryProtection(runtime, documentLinks);\n }\n\n discoverContainerDocuments(\n containerId: string,\n ): Promise<ReadonlyArray<DocumentSummary> | null> {\n return discoverContainerDocumentsForRuntime({\n containerId,\n runtimeService: this.runtimeService,\n });\n }\n\n pullDocumentContent(input: {\n containerId: string;\n localId: string;\n documentId?: string | null | undefined;\n }): void {\n const runtime = this.workflowRuntime();\n const store = openDocumentStore(\n runtime.state.domainScope,\n input.localId,\n createContainerContentsDocumentsRuntime(runtime, input.containerId),\n input.documentId ?? null,\n );\n store.requestRemoteSync();\n }\n\n loadContainerInfo(input: ContainerInfoInput): Promise<ContainerInfo> {\n const runtime = this.runtimeService.workflowInput();\n const organizationScope =\n runtime.auth.isAuthenticated &&\n runtime.auth.organizationId &&\n runtime.auth.userId\n ? {\n domainScope: runtime.state.domainScope,\n organizationId: runtime.auth.organizationId,\n userId: runtime.auth.userId,\n }\n : null;\n const cachedContainerProjection =\n input.remoteInfoMode === \"always\"\n ? null\n : this.openTree().getCachedContainerWriterProjection(input.containerId);\n return loadContainerInfo({\n ...input,\n apiClient: runtime.apiClient,\n containerProjection: cachedContainerProjection,\n execSql: readyExecSql(runtime),\n loadOrganizationGroups: async () => {\n if (\n !organizationScope ||\n !isActiveContainerInfoOrganizationScope(\n this.runtimeService.workflowInput(),\n organizationScope,\n )\n ) {\n return [];\n }\n // Organization groups are disposable presentation data. Container\n // writer projections remain the authority for grants and access.\n const projection = await this.organizationReadModels.loadLocal(\n organizationScope.organizationId,\n );\n return isActiveContainerInfoOrganizationScope(\n this.runtimeService.workflowInput(),\n organizationScope,\n )\n ? (projection?.groups ?? [])\n : [];\n },\n parentId: input.parentId ?? null,\n });\n }\n\n loadDocumentInfo(input: DocumentInfoInput): Promise<DocumentInfo> {\n const runtime = this.runtimeService.workflowInput();\n return loadDocumentInfo({\n ...input,\n apiClient: runtime.apiClient,\n execSql: readyExecSql(runtime),\n reportSecurityIncident: runtime.util.reportSecurityIncident,\n });\n }\n\n loadDocumentEditAttribution(\n documentId: string,\n ): ReturnType<ContainerContents[\"loadDocumentEditAttribution\"]> {\n return this.runtimeService\n .workflowInput()\n .apiClient.getDocumentEditAttribution(documentId);\n }\n\n loadDocumentAttributionRanges(\n input: DocumentAttributionRangesInput,\n ): Promise<DocumentAttributionRangesPage> {\n return loadDocumentAttributionRanges({\n apiClient: this.runtimeService.workflowInput().apiClient,\n query: input,\n });\n }\n\n listBlobInfo(input: BlobInfoInput = {}): Promise<BlobInfoList> {\n const runtime = this.runtimeService.workflowInput();\n return listBlobInfo({\n ...input,\n execSql: readyExecSql(runtime),\n });\n }\n\n workflowRuntime(): ContainerContentsStoreWorkflowRuntime {\n return createContainerContentsStoreWorkflowRuntime(\n this.runtimeService.workflowInput(),\n this.runtimeService.adoptRootContainer,\n );\n }\n}\n"]}
|
|
@@ -51,6 +51,8 @@ export interface DocumentInfoInput {
|
|
|
51
51
|
export type MergeDocumentSummary = (nextDocument: DocumentSummary) => void;
|
|
52
52
|
export interface OpenContainerDocumentInput {
|
|
53
53
|
readonly containerId: string | null;
|
|
54
|
+
/** A file attach follows creation and carries the birth; see the store. */
|
|
55
|
+
readonly deferInitialUpdate?: boolean | undefined;
|
|
54
56
|
readonly documentId?: string | null | undefined;
|
|
55
57
|
readonly initialDocumentKind?: StoredDocumentKind | undefined;
|
|
56
58
|
readonly initialText?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerContentsTypes.js","sourceRoot":"","sources":["containerContentsTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentEditAttributionResponse } from \"@tearleads/validators/response\";\nimport type { StoredDocumentKind } from \"../data/documents/documentKinds\";\nimport type { DocumentSummary } from \"../data/documents/documentSummary\";\nimport type {\n ContainerContentsStore,\n ContainerContentsStoreOptions,\n ContainerContentsStoreRuntime,\n} from \"../stores/container-contents\";\nimport type { DocumentStore } from \"../stores/documents\";\nimport type {\n BlobInfoInput,\n BlobInfoList,\n} from \"../workflows/container-contents/blobInfo\";\nimport type {\n ContainerInfo,\n ContainerInfoRemoteMode,\n} from \"../workflows/container-contents/containerInfo\";\nimport type {\n DocumentAttributionRangesInput,\n DocumentAttributionRangesPage,\n} from \"../workflows/container-contents/documentAttributionRanges\";\nimport type {\n DocumentInfo,\n DocumentInfoRemoteMode,\n} from \"../workflows/container-contents/documentInfo\";\nimport type { ContainerDocumentQueries } from \"../workflows/container-contents/documentQueries\";\nimport type { SetLinkedContainerIdsForDocument } from \"../workflows/container-contents/documentStructure\";\nimport type { ContainerContentsProjectionUserKeyResolver } from \"../workflows/container-contents/projectionKeys\";\nimport type { ContainerContentsWorkflowRuntime } from \"../workflows/container-contents/runtime\";\nimport type { DocumentsWorkflowRuntime } from \"../workflows/documents\";\n\n/**\n * Selects the container to inspect.\n *\n * Container info combines local SQLite timestamps with optional remote writer\n * projection details. Remote details include direct and inherited grants,\n * organization groups, security-path metadata, and sync watermarks for the\n * parent, child-container, and document lanes.\n *\n * Fields:\n * - `containerId`: Container id to inspect.\n * - `parentId`: Known parent id used when the container has not been synced\n * locally yet. Synced local state wins when available.\n * - `remoteInfoMode`: Controls whether remote projection details are fetched.\n */\nexport interface ContainerInfoInput {\n containerId: string;\n parentId?: string | null | undefined;\n remoteInfoMode?: ContainerInfoRemoteMode | undefined;\n}\n\n/**\n * Selects the document to inspect.\n *\n * Document info combines local document state, local and pending attachment\n * rows, and optional remote writer projection details.\n *\n * Fields:\n * - `attributionRequestKey`: Optional freshness generation used to coalesce\n * duplicate attribution reads without joining requests across invalidation.\n * - `localId`: Local document id stored in the client database.\n * - `remoteInfoMode`: Controls whether remote projection details are fetched.\n */\nexport interface DocumentInfoInput {\n attributionRequestKey?: string | undefined;\n localId: string;\n remoteInfoMode?: DocumentInfoRemoteMode | undefined;\n}\n\nexport type MergeDocumentSummary = (nextDocument: DocumentSummary) => void;\n\nexport interface OpenContainerDocumentInput {\n readonly containerId: string | null;\n readonly documentId?: string | null | undefined;\n readonly initialDocumentKind?: StoredDocumentKind | undefined;\n readonly initialText?: string | undefined;\n readonly localId: string;\n}\n\nexport interface ContainerDocumentLinkInput {\n readonly mergeDocumentSummary: MergeDocumentSummary;\n readonly note: DocumentSummary;\n}\n\nexport interface MoveDocumentToContainerInput\n extends ContainerDocumentLinkInput {\n readonly expandNode: (nodeId: string) => void;\n readonly replaceLinkedContainers?: boolean | undefined;\n readonly setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n readonly sourceContainerId?: string | null | undefined;\n readonly targetContainerId: string;\n}\n\nexport interface LinkDocumentToContainerInput\n extends ContainerDocumentLinkInput {\n readonly setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n readonly targetContainerId: string;\n}\n\nexport interface UnlinkDocumentFromContainerInput\n extends ContainerDocumentLinkInput {\n readonly removedContainerId: string;\n readonly setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n}\n\nexport interface SetActiveDocumentContainerInput\n extends ContainerDocumentLinkInput {\n readonly targetContainerId: string;\n}\n\nexport interface PurgeDocumentInput {\n /** The current local summary of the document to destroy. */\n readonly note: DocumentSummary;\n}\n\nexport interface PurgeDocumentResult {\n readonly documentId: string;\n readonly purgedAt: string;\n readonly reclaimedBlobStorageKeys: ReadonlyArray<string>;\n}\n\nexport interface ContainerDocumentLinks\n extends ContainerContentsWorkflowRuntime {\n documentRuntime(containerId: string | null): DocumentsWorkflowRuntime;\n openDocument(input: OpenContainerDocumentInput): DocumentStore;\n setActiveDocumentContainer(\n input: SetActiveDocumentContainerInput,\n ): Promise<DocumentSummary | null>;\n readonly canMutateDocumentLinks: boolean;\n readonly canMutateUnsyncedDocumentLinks: boolean;\n linkDocumentToContainer(\n input: LinkDocumentToContainerInput,\n ): Promise<DocumentSummary | null>;\n moveDocumentToContainer(\n input: MoveDocumentToContainerInput,\n ): Promise<{ linksChanged: boolean; note: DocumentSummary | null }>;\n /**\n * Permanently destroy a local-only document, or submit and verify a signed\n * terminal purge for a remote document. Remote purge requires exactly one\n * remaining container link and returns null on refusal or verification\n * failure.\n */\n purgeDocument(input: PurgeDocumentInput): Promise<PurgeDocumentResult | null>;\n readonly resolveProjectionUserKey: ContainerContentsProjectionUserKeyResolver;\n unlinkDocumentFromContainer(\n input: UnlinkDocumentFromContainerInput,\n ): Promise<DocumentSummary | null>;\n}\n\n/**\n * High-level container-content service for tree state, document lists, document\n * links, discovery, and diagnostics.\n *\n * The facade owns the normal SDK protocol: it supplies the API client,\n * referenced-principal policy cache, local document query helpers, link\n * projection, tombstone handling, and sync watermarks. Consumers that need a\n * custom persistence protocol can call the lower-level workflows directly from\n * `@tearleads/client-sdk`.\n */\nexport interface ContainerContents {\n /**\n * Open the container tree state store for the current SDK runtime.\n *\n * The store is cached per domain scope and created from the current runtime\n * snapshot. Long-lived hosts should call `updateRuntime` after runtime\n * changes, such as from a React effect.\n */\n openTree(\n options?: ContainerContentsStoreOptions | undefined,\n ): ContainerContentsStore;\n\n /**\n * Create local document query helpers for container contents.\n *\n * The facade is bound to the current SDK runtime snapshot, including the\n * active SQLite executor. Recreate it when the SDK runtime version changes.\n */\n documentQueries(): ContainerDocumentQueries;\n\n /**\n * Create the default document-link workflow helper.\n *\n * The returned object includes the current container-contents runtime,\n * the document projection-key resolver, mutation readiness, document store\n * priming, and container document-link mutations. Product stores can pass\n * this bundle around without rebuilding SDK runtime plumbing themselves.\n */\n documentLinks(): ContainerDocumentLinks;\n\n /**\n * Discover remote documents linked to one container.\n *\n * The method pages the remote container-document lane, writes discovered\n * document summaries into local SQLite, replaces the local link projection for\n * each discovered document, applies applicable tombstones, caches referenced\n * principal policies needed by newly visible documents, and advances the\n * container-document watermark after the local apply completes.\n *\n * One call verifies a bounded batch. Pending evidence is durable; a later\n * explicit call or background reconciliation resumes it.\n *\n * Returns the summaries touched by the apply, or `null` when the database or\n * listing is unavailable, a trust reset cancels the pass, or all evidence is\n * pending. Pending evidence may advance the watermark after durable staging.\n *\n * Parameters:\n * - `containerId`: Remote container id whose document lane should be listed.\n */\n discoverContainerDocuments(\n containerId: string,\n ): Promise<ReadonlyArray<DocumentSummary> | null>;\n\n /**\n * Sync the content of a single document that no mini-app has opened.\n *\n * Discovery only records a document's metadata + an empty content shell, and a\n * document's locally authored content is only pushed once its store syncs; both\n * normally happen lazily when a mini-app opens the document. Some documents are\n * never opened yet still need to sync — notably the organization profile\n * document, which lives in an org's Members-granted metadata container and\n * holds the org display name. This opens a transient document store (registered\n * under the container's keys, so it can decrypt) and schedules a remote sync\n * pass. The pass both pushes the store's pending updates and merges + persists\n * any remote body, so the same call lets an owning device publish its profile\n * content and a member device pull it. `documentId` may be omitted; the store\n * then resolves it from the persisted record (the owning device keys the\n * document under a local alias, not its server id).\n */\n pullDocumentContent(input: {\n containerId: string;\n localId: string;\n documentId?: string | null | undefined;\n }): void;\n\n /**\n * Load diagnostic information for one local document.\n *\n * Local details are available when SQLite is ready. Remote details are loaded\n * from the document writer projection according to `remoteInfoMode`; the\n * default is `\"if-synced\"`.\n */\n loadDocumentInfo(input: DocumentInfoInput): Promise<DocumentInfo>;\n\n /**\n * Fetch a synced document's compact edit-attribution segments (peer -> writer\n * intervals) on their own, without the writer-projection/attachment work\n * `loadDocumentInfo` also does. Resolves to `null` on any request failure.\n * Callers must ignore the segments when `truncated` is set — a truncated\n * interval list can drop a peer's segments and mis-resolve it.\n */\n loadDocumentEditAttribution(\n documentId: string,\n ): Promise<DocumentEditAttributionResponse | null>;\n\n /** Load one revision-bound page of detailed per-upload edit attribution. */\n loadDocumentAttributionRanges(\n input: DocumentAttributionRangesInput,\n ): Promise<DocumentAttributionRangesPage>;\n\n /**\n * List local blob projections and pending attachment bytes grouped by blob.\n *\n * This is a reverse lookup query: callers can search by server blob id,\n * local storage key, document id/title, attachment slot, or MIME metadata and\n * then traverse matching blobs back to their owning local documents.\n */\n listBlobInfo(input?: BlobInfoInput | undefined): Promise<BlobInfoList>;\n\n /**\n * Load diagnostic information for one container.\n *\n * Local details include synced timestamps. Remote details are loaded from the\n * container writer projection according to `remoteInfoMode`; the default is\n * `\"always\"`. Pass `parentId` when inspecting a container before its local row\n * has been synced.\n */\n loadContainerInfo(input: ContainerInfoInput): Promise<ContainerInfo>;\n\n /**\n * Create a workflow runtime for advanced container-content workflows.\n *\n * Prefer the high-level methods on this service for the default SDK protocol.\n * Use this when constructing lower-level stores or custom workflows that need\n * access to the current runtime snapshot.\n */\n workflowRuntime(): ContainerContentsStoreRuntime;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerContentsTypes.js","sourceRoot":"","sources":["containerContentsTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentEditAttributionResponse } from \"@tearleads/validators/response\";\nimport type { StoredDocumentKind } from \"../data/documents/documentKinds\";\nimport type { DocumentSummary } from \"../data/documents/documentSummary\";\nimport type {\n ContainerContentsStore,\n ContainerContentsStoreOptions,\n ContainerContentsStoreRuntime,\n} from \"../stores/container-contents\";\nimport type { DocumentStore } from \"../stores/documents\";\nimport type {\n BlobInfoInput,\n BlobInfoList,\n} from \"../workflows/container-contents/blobInfo\";\nimport type {\n ContainerInfo,\n ContainerInfoRemoteMode,\n} from \"../workflows/container-contents/containerInfo\";\nimport type {\n DocumentAttributionRangesInput,\n DocumentAttributionRangesPage,\n} from \"../workflows/container-contents/documentAttributionRanges\";\nimport type {\n DocumentInfo,\n DocumentInfoRemoteMode,\n} from \"../workflows/container-contents/documentInfo\";\nimport type { ContainerDocumentQueries } from \"../workflows/container-contents/documentQueries\";\nimport type { SetLinkedContainerIdsForDocument } from \"../workflows/container-contents/documentStructure\";\nimport type { ContainerContentsProjectionUserKeyResolver } from \"../workflows/container-contents/projectionKeys\";\nimport type { ContainerContentsWorkflowRuntime } from \"../workflows/container-contents/runtime\";\nimport type { DocumentsWorkflowRuntime } from \"../workflows/documents\";\n\n/**\n * Selects the container to inspect.\n *\n * Container info combines local SQLite timestamps with optional remote writer\n * projection details. Remote details include direct and inherited grants,\n * organization groups, security-path metadata, and sync watermarks for the\n * parent, child-container, and document lanes.\n *\n * Fields:\n * - `containerId`: Container id to inspect.\n * - `parentId`: Known parent id used when the container has not been synced\n * locally yet. Synced local state wins when available.\n * - `remoteInfoMode`: Controls whether remote projection details are fetched.\n */\nexport interface ContainerInfoInput {\n containerId: string;\n parentId?: string | null | undefined;\n remoteInfoMode?: ContainerInfoRemoteMode | undefined;\n}\n\n/**\n * Selects the document to inspect.\n *\n * Document info combines local document state, local and pending attachment\n * rows, and optional remote writer projection details.\n *\n * Fields:\n * - `attributionRequestKey`: Optional freshness generation used to coalesce\n * duplicate attribution reads without joining requests across invalidation.\n * - `localId`: Local document id stored in the client database.\n * - `remoteInfoMode`: Controls whether remote projection details are fetched.\n */\nexport interface DocumentInfoInput {\n attributionRequestKey?: string | undefined;\n localId: string;\n remoteInfoMode?: DocumentInfoRemoteMode | undefined;\n}\n\nexport type MergeDocumentSummary = (nextDocument: DocumentSummary) => void;\n\nexport interface OpenContainerDocumentInput {\n readonly containerId: string | null;\n /** A file attach follows creation and carries the birth; see the store. */\n readonly deferInitialUpdate?: boolean | undefined;\n readonly documentId?: string | null | undefined;\n readonly initialDocumentKind?: StoredDocumentKind | undefined;\n readonly initialText?: string | undefined;\n readonly localId: string;\n}\n\nexport interface ContainerDocumentLinkInput {\n readonly mergeDocumentSummary: MergeDocumentSummary;\n readonly note: DocumentSummary;\n}\n\nexport interface MoveDocumentToContainerInput\n extends ContainerDocumentLinkInput {\n readonly expandNode: (nodeId: string) => void;\n readonly replaceLinkedContainers?: boolean | undefined;\n readonly setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n readonly sourceContainerId?: string | null | undefined;\n readonly targetContainerId: string;\n}\n\nexport interface LinkDocumentToContainerInput\n extends ContainerDocumentLinkInput {\n readonly setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n readonly targetContainerId: string;\n}\n\nexport interface UnlinkDocumentFromContainerInput\n extends ContainerDocumentLinkInput {\n readonly removedContainerId: string;\n readonly setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n}\n\nexport interface SetActiveDocumentContainerInput\n extends ContainerDocumentLinkInput {\n readonly targetContainerId: string;\n}\n\nexport interface PurgeDocumentInput {\n /** The current local summary of the document to destroy. */\n readonly note: DocumentSummary;\n}\n\nexport interface PurgeDocumentResult {\n readonly documentId: string;\n readonly purgedAt: string;\n readonly reclaimedBlobStorageKeys: ReadonlyArray<string>;\n}\n\nexport interface ContainerDocumentLinks\n extends ContainerContentsWorkflowRuntime {\n documentRuntime(containerId: string | null): DocumentsWorkflowRuntime;\n openDocument(input: OpenContainerDocumentInput): DocumentStore;\n setActiveDocumentContainer(\n input: SetActiveDocumentContainerInput,\n ): Promise<DocumentSummary | null>;\n readonly canMutateDocumentLinks: boolean;\n readonly canMutateUnsyncedDocumentLinks: boolean;\n linkDocumentToContainer(\n input: LinkDocumentToContainerInput,\n ): Promise<DocumentSummary | null>;\n moveDocumentToContainer(\n input: MoveDocumentToContainerInput,\n ): Promise<{ linksChanged: boolean; note: DocumentSummary | null }>;\n /**\n * Permanently destroy a local-only document, or submit and verify a signed\n * terminal purge for a remote document. Remote purge requires exactly one\n * remaining container link and returns null on refusal or verification\n * failure.\n */\n purgeDocument(input: PurgeDocumentInput): Promise<PurgeDocumentResult | null>;\n readonly resolveProjectionUserKey: ContainerContentsProjectionUserKeyResolver;\n unlinkDocumentFromContainer(\n input: UnlinkDocumentFromContainerInput,\n ): Promise<DocumentSummary | null>;\n}\n\n/**\n * High-level container-content service for tree state, document lists, document\n * links, discovery, and diagnostics.\n *\n * The facade owns the normal SDK protocol: it supplies the API client,\n * referenced-principal policy cache, local document query helpers, link\n * projection, tombstone handling, and sync watermarks. Consumers that need a\n * custom persistence protocol can call the lower-level workflows directly from\n * `@tearleads/client-sdk`.\n */\nexport interface ContainerContents {\n /**\n * Open the container tree state store for the current SDK runtime.\n *\n * The store is cached per domain scope and created from the current runtime\n * snapshot. Long-lived hosts should call `updateRuntime` after runtime\n * changes, such as from a React effect.\n */\n openTree(\n options?: ContainerContentsStoreOptions | undefined,\n ): ContainerContentsStore;\n\n /**\n * Create local document query helpers for container contents.\n *\n * The facade is bound to the current SDK runtime snapshot, including the\n * active SQLite executor. Recreate it when the SDK runtime version changes.\n */\n documentQueries(): ContainerDocumentQueries;\n\n /**\n * Create the default document-link workflow helper.\n *\n * The returned object includes the current container-contents runtime,\n * the document projection-key resolver, mutation readiness, document store\n * priming, and container document-link mutations. Product stores can pass\n * this bundle around without rebuilding SDK runtime plumbing themselves.\n */\n documentLinks(): ContainerDocumentLinks;\n\n /**\n * Discover remote documents linked to one container.\n *\n * The method pages the remote container-document lane, writes discovered\n * document summaries into local SQLite, replaces the local link projection for\n * each discovered document, applies applicable tombstones, caches referenced\n * principal policies needed by newly visible documents, and advances the\n * container-document watermark after the local apply completes.\n *\n * One call verifies a bounded batch. Pending evidence is durable; a later\n * explicit call or background reconciliation resumes it.\n *\n * Returns the summaries touched by the apply, or `null` when the database or\n * listing is unavailable, a trust reset cancels the pass, or all evidence is\n * pending. Pending evidence may advance the watermark after durable staging.\n *\n * Parameters:\n * - `containerId`: Remote container id whose document lane should be listed.\n */\n discoverContainerDocuments(\n containerId: string,\n ): Promise<ReadonlyArray<DocumentSummary> | null>;\n\n /**\n * Sync the content of a single document that no mini-app has opened.\n *\n * Discovery only records a document's metadata + an empty content shell, and a\n * document's locally authored content is only pushed once its store syncs; both\n * normally happen lazily when a mini-app opens the document. Some documents are\n * never opened yet still need to sync — notably the organization profile\n * document, which lives in an org's Members-granted metadata container and\n * holds the org display name. This opens a transient document store (registered\n * under the container's keys, so it can decrypt) and schedules a remote sync\n * pass. The pass both pushes the store's pending updates and merges + persists\n * any remote body, so the same call lets an owning device publish its profile\n * content and a member device pull it. `documentId` may be omitted; the store\n * then resolves it from the persisted record (the owning device keys the\n * document under a local alias, not its server id).\n */\n pullDocumentContent(input: {\n containerId: string;\n localId: string;\n documentId?: string | null | undefined;\n }): void;\n\n /**\n * Load diagnostic information for one local document.\n *\n * Local details are available when SQLite is ready. Remote details are loaded\n * from the document writer projection according to `remoteInfoMode`; the\n * default is `\"if-synced\"`.\n */\n loadDocumentInfo(input: DocumentInfoInput): Promise<DocumentInfo>;\n\n /**\n * Fetch a synced document's compact edit-attribution segments (peer -> writer\n * intervals) on their own, without the writer-projection/attachment work\n * `loadDocumentInfo` also does. Resolves to `null` on any request failure.\n * Callers must ignore the segments when `truncated` is set — a truncated\n * interval list can drop a peer's segments and mis-resolve it.\n */\n loadDocumentEditAttribution(\n documentId: string,\n ): Promise<DocumentEditAttributionResponse | null>;\n\n /** Load one revision-bound page of detailed per-upload edit attribution. */\n loadDocumentAttributionRanges(\n input: DocumentAttributionRangesInput,\n ): Promise<DocumentAttributionRangesPage>;\n\n /**\n * List local blob projections and pending attachment bytes grouped by blob.\n *\n * This is a reverse lookup query: callers can search by server blob id,\n * local storage key, document id/title, attachment slot, or MIME metadata and\n * then traverse matching blobs back to their owning local documents.\n */\n listBlobInfo(input?: BlobInfoInput | undefined): Promise<BlobInfoList>;\n\n /**\n * Load diagnostic information for one container.\n *\n * Local details include synced timestamps. Remote details are loaded from the\n * container writer projection according to `remoteInfoMode`; the default is\n * `\"always\"`. Pass `parentId` when inspecting a container before its local row\n * has been synced.\n */\n loadContainerInfo(input: ContainerInfoInput): Promise<ContainerInfo>;\n\n /**\n * Create a workflow runtime for advanced container-content workflows.\n *\n * Prefer the high-level methods on this service for the default SDK protocol.\n * Use this when constructing lower-level stores or custom workflows that need\n * access to the current runtime snapshot.\n */\n workflowRuntime(): ContainerContentsStoreRuntime;\n}\n"]}
|
package/client/documents.js
CHANGED
|
@@ -52,7 +52,7 @@ class DocumentsService {
|
|
|
52
52
|
open(input = {}, options = {}) {
|
|
53
53
|
const { containerId, documentId = null, initialDocumentKind = DEFAULT_DOCUMENT_KIND, initialText = "", localId = DEFAULT_LOCAL_DOCUMENT_ID, } = input;
|
|
54
54
|
const runtime = options.workflowRuntime ?? this.workflowRuntime(containerId);
|
|
55
|
-
return openDocumentStore(runtime.state.domainScope, localId, runtime, documentId, initialText, initialDocumentKind, options.remoteSyncMode
|
|
55
|
+
return openDocumentStore(runtime.state.domainScope, localId, runtime, documentId, initialText, initialDocumentKind, { remoteSyncMode: options.remoteSyncMode });
|
|
56
56
|
}
|
|
57
57
|
subscribe(listener, options = {}) {
|
|
58
58
|
return subscribeToPersistedDocuments(this.dependencies.runtime.workflowInput(options.containerId).state
|
package/client/documents.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.js","sourceRoot":"","sources":["documents.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"documents.js","sourceRoot":"","sources":["documents.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../data/documents/documentConstants\";\nimport type { StoredDocumentKind } from \"../data/documents/documentKinds\";\nimport type {\n DocumentSummaryList,\n DocumentSummarySort,\n DocumentSummarySortDirection,\n DocumentSummarySortKey,\n ListDocumentSummariesInput,\n} from \"../data/persistence/documents/types\";\nimport type { ExecSql } from \"../data/sqlite/sqlSchema\";\nimport {\n DEFAULT_DOCUMENT_ID as DEFAULT_LOCAL_DOCUMENT_ID,\n type DocumentStore,\n type DocumentsRuntime,\n openDocumentStore,\n type PersistedDocumentListener,\n subscribeToPersistedDocuments,\n} from \"../stores/documents\";\nimport { emitPersistedDocumentDeletion } from \"../stores/documents/registry\";\nimport {\n createDocumentsWorkflowRuntime,\n defaultDocumentsPersistence,\n deletePersistedDocument,\n reclaimDocumentOrphanBlobs,\n} from \"../workflows/documents\";\nimport type { InternalRuntime } from \"./workflowRuntime\";\n\nexport type {\n DocumentAttachmentStatus,\n DocumentAttachmentUpload,\n DocumentContextValue,\n DocumentStore,\n DocumentsRuntime,\n PersistedDocumentListener,\n} from \"../stores/documents\";\n\nexport type DocumentSortDirection = DocumentSummarySortDirection;\nexport type DocumentSortKey = DocumentSummarySortKey;\n\nexport type DocumentSort = DocumentSummarySort;\n\nexport interface ListDocumentsInput extends ListDocumentSummariesInput {}\n\nexport type DocumentList = DocumentSummaryList;\n\nexport { DEFAULT_LOCAL_DOCUMENT_ID as DEFAULT_DOCUMENT_ID };\n\nexport interface OpenDocumentInput {\n readonly containerId?: string | null | undefined;\n readonly documentId?: string | null | undefined;\n readonly initialDocumentKind?: StoredDocumentKind | undefined;\n readonly initialText?: string | undefined;\n readonly localId?: string | undefined;\n}\n\nexport interface OpenDocumentOptions {\n readonly remoteSyncMode?: \"on-demand\" | \"startup\" | undefined;\n readonly workflowRuntime?: DocumentsRuntime | undefined;\n}\n\nexport interface DocumentSubscriptionOptions {\n readonly containerId?: string | null | undefined;\n}\n\nexport interface Documents {\n delete(localId: string): Promise<boolean>;\n findLocalIdByDocumentId(documentId: string): Promise<string | null>;\n list(input?: ListDocumentsInput | undefined): Promise<DocumentList | null>;\n open(\n input?: OpenDocumentInput | undefined,\n options?: OpenDocumentOptions | undefined,\n ): DocumentStore;\n subscribe(\n listener: PersistedDocumentListener,\n options?: DocumentSubscriptionOptions | undefined,\n ): () => void;\n workflowRuntime(containerId?: string | null | undefined): DocumentsRuntime;\n}\n\ninterface DocumentsDependencies {\n getDefaultContainerId: () => string | null;\n runtime: InternalRuntime;\n}\n\nexport function createDocuments(\n dependencies: DocumentsDependencies,\n): Documents {\n return new DocumentsService(dependencies);\n}\n\nclass DocumentsService implements Documents {\n private readonly schemaEnsuresByExecSql = new WeakMap<\n ExecSql,\n Promise<void>\n >();\n\n constructor(private readonly dependencies: DocumentsDependencies) {}\n\n async delete(localId: string): Promise<boolean> {\n const runtime = this.workflowRuntime();\n if (runtime.infra.dbStatus !== \"ready\") {\n return false;\n }\n\n const deleted = await deletePersistedDocument({\n documentProjectors: runtime.infra.documentProjectors,\n execSql: runtime.infra.execSql,\n localId,\n persistence: defaultDocumentsPersistence,\n });\n if (!deleted) return false;\n void reclaimDocumentOrphanBlobs(runtime);\n emitPersistedDocumentDeletion(runtime.state.domainScope, localId);\n return true;\n }\n\n async findLocalIdByDocumentId(documentId: string): Promise<string | null> {\n const runtime = this.dependencies.runtime.workflowInput();\n if (runtime.infra.dbStatus !== \"ready\") {\n return null;\n }\n\n await this.ensureSchema(runtime.infra.execSql);\n return defaultDocumentsPersistence.findLocalIdByDocumentId(\n runtime.infra.execSql,\n documentId,\n );\n }\n\n async list(input: ListDocumentsInput = {}): Promise<DocumentList | null> {\n const runtime = this.dependencies.runtime.workflowInput();\n if (runtime.infra.dbStatus !== \"ready\") {\n return null;\n }\n\n await this.ensureSchema(runtime.infra.execSql);\n return defaultDocumentsPersistence.listDocumentSummaries(\n runtime.infra.execSql,\n input,\n );\n }\n\n workflowRuntime(\n containerId = this.dependencies.getDefaultContainerId(),\n ): DocumentsRuntime {\n const input = this.dependencies.runtime.workflowInput(containerId);\n return createDocumentsWorkflowRuntime(input);\n }\n\n open(\n input: OpenDocumentInput = {},\n options: OpenDocumentOptions = {},\n ): DocumentStore {\n const {\n containerId,\n documentId = null,\n initialDocumentKind = DEFAULT_DOCUMENT_KIND,\n initialText = \"\",\n localId = DEFAULT_LOCAL_DOCUMENT_ID,\n } = input;\n const runtime =\n options.workflowRuntime ?? this.workflowRuntime(containerId);\n return openDocumentStore(\n runtime.state.domainScope,\n localId,\n runtime,\n documentId,\n initialText,\n initialDocumentKind,\n { remoteSyncMode: options.remoteSyncMode },\n );\n }\n\n subscribe(\n listener: PersistedDocumentListener,\n options: DocumentSubscriptionOptions = {},\n ): () => void {\n return subscribeToPersistedDocuments(\n this.dependencies.runtime.workflowInput(options.containerId).state\n .domainScope,\n listener,\n );\n }\n\n private ensureSchema(execSql: ExecSql): Promise<void> {\n const existing = this.schemaEnsuresByExecSql.get(execSql);\n if (existing) {\n return existing;\n }\n\n const ensure = defaultDocumentsPersistence\n .ensureSchema(execSql)\n .catch((error: unknown) => {\n this.schemaEnsuresByExecSql.delete(execSql);\n throw error;\n });\n this.schemaEnsuresByExecSql.set(execSql, ensure);\n return ensure;\n }\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Bound byte I/O across documents sharing a client, including multipart parts. */
|
|
2
|
+
export const BLOB_TRANSFER_CONCURRENCY = 4;
|
|
3
|
+
const TRANSFER_IDLE_TIMEOUT_MS = 120_000;
|
|
4
|
+
const pools = new WeakMap();
|
|
5
|
+
export async function runBlobTransfer(client, transfer, timeoutMs = TRANSFER_IDLE_TIMEOUT_MS) {
|
|
6
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
7
|
+
throw new RangeError("Blob transfer timeout must be positive and finite");
|
|
8
|
+
let pool = pools.get(client);
|
|
9
|
+
if (!pool) {
|
|
10
|
+
pool = { active: 0, waiting: [] };
|
|
11
|
+
pools.set(client, pool);
|
|
12
|
+
}
|
|
13
|
+
if (pool.active >= BLOB_TRANSFER_CONCURRENCY) {
|
|
14
|
+
await new Promise((resolve) => pool.waiting.push(resolve));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
pool.active += 1;
|
|
18
|
+
}
|
|
19
|
+
const controller = new AbortController();
|
|
20
|
+
let timer;
|
|
21
|
+
const progress = () => {
|
|
22
|
+
controller.signal.throwIfAborted();
|
|
23
|
+
clearTimeout(timer);
|
|
24
|
+
timer = setTimeout(() => controller.abort(new Error("Blob transfer timed out")), timeoutMs);
|
|
25
|
+
};
|
|
26
|
+
progress();
|
|
27
|
+
try {
|
|
28
|
+
// A native bridge or custom transport may ignore abort. Bound its logical
|
|
29
|
+
// ownership anyway; callers must check the signal before accepting results.
|
|
30
|
+
return await new Promise((resolve, reject) => {
|
|
31
|
+
const aborted = () => reject(controller.signal.reason);
|
|
32
|
+
controller.signal.addEventListener("abort", aborted, { once: true });
|
|
33
|
+
void Promise.resolve()
|
|
34
|
+
.then(() => transfer(controller.signal, progress))
|
|
35
|
+
.then((value) => {
|
|
36
|
+
controller.signal.removeEventListener("abort", aborted);
|
|
37
|
+
resolve(value);
|
|
38
|
+
}, (error) => {
|
|
39
|
+
controller.signal.removeEventListener("abort", aborted);
|
|
40
|
+
reject(error);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
const next = pool.waiting.shift();
|
|
47
|
+
if (next)
|
|
48
|
+
next();
|
|
49
|
+
else
|
|
50
|
+
pool.active -= 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=transferPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transferPool.js","sourceRoot":"","sources":["transferPool.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAKzC,MAAM,KAAK,GAAG,IAAI,OAAO,EAAwB,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,QAAmE,EACnE,SAAS,GAAG,wBAAwB;IAEpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC;QAC/C,MAAM,IAAI,UAAU,CAAC,mDAAmD,CAAC,CAAC;IAC5E,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAClC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC;QAC7C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACnE,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,KAAgD,CAAC;IACrD,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACnC,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,KAAK,GAAG,UAAU,CAChB,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAC5D,SAAS,CACV,CAAC;IACJ,CAAC,CAAC;IACF,QAAQ,EAAE,CAAC;IACX,IAAI,CAAC;QACH,0EAA0E;QAC1E,4EAA4E;QAC5E,OAAO,MAAM,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvD,UAAU,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACrE,KAAK,OAAO,CAAC,OAAO,EAAE;iBACnB,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;iBACjD,IAAI,CACH,CAAC,KAAK,EAAE,EAAE;gBACR,UAAU,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACxD,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;gBACjB,UAAU,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACxD,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CACF,CAAC;QACN,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI;YAAE,IAAI,EAAE,CAAC;;YACZ,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IACxB,CAAC;AACH,CAAC","sourcesContent":["/** Bound byte I/O across documents sharing a client, including multipart parts. */\nexport const BLOB_TRANSFER_CONCURRENCY = 4;\nconst TRANSFER_IDLE_TIMEOUT_MS = 120_000;\ninterface TransferPool {\n active: number;\n waiting: Array<() => void>;\n}\nconst pools = new WeakMap<object, TransferPool>();\n\nexport async function runBlobTransfer<T>(\n client: object,\n transfer: (signal: AbortSignal, progress: () => void) => Promise<T>,\n timeoutMs = TRANSFER_IDLE_TIMEOUT_MS,\n): Promise<T> {\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)\n throw new RangeError(\"Blob transfer timeout must be positive and finite\");\n let pool = pools.get(client);\n if (!pool) {\n pool = { active: 0, waiting: [] };\n pools.set(client, pool);\n }\n if (pool.active >= BLOB_TRANSFER_CONCURRENCY) {\n await new Promise<void>((resolve) => pool.waiting.push(resolve));\n } else {\n pool.active += 1;\n }\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const progress = () => {\n controller.signal.throwIfAborted();\n clearTimeout(timer);\n timer = setTimeout(\n () => controller.abort(new Error(\"Blob transfer timed out\")),\n timeoutMs,\n );\n };\n progress();\n try {\n // A native bridge or custom transport may ignore abort. Bound its logical\n // ownership anyway; callers must check the signal before accepting results.\n return await new Promise<T>((resolve, reject) => {\n const aborted = () => reject(controller.signal.reason);\n controller.signal.addEventListener(\"abort\", aborted, { once: true });\n void Promise.resolve()\n .then(() => transfer(controller.signal, progress))\n .then(\n (value) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n resolve(value);\n },\n (error: unknown) => {\n controller.signal.removeEventListener(\"abort\", aborted);\n reject(error);\n },\n );\n });\n } finally {\n clearTimeout(timer);\n const next = pool.waiting.shift();\n if (next) next();\n else pool.active -= 1;\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RequestFailureKind, UploadMultipartBlobPartBytesRequest } from "../../../../internal/api-client/index.js";
|
|
1
|
+
import type { RequestFailureKind, RequestResultOptions, UploadMultipartBlobPartBytesRequest } from "../../../../internal/api-client/index.js";
|
|
2
2
|
import type { BlobContentKeyTarget, BlobEnvelopeHeaderRecord, BlobEnvelopeRecord, WriteHeader } from "../../../../internal/crypto/index.js";
|
|
3
3
|
import type { BlobAttachmentBindRequest, BlobAttachmentDetachRequest, BlobContentKeyBundleRequest, CompleteMultipartBlobStageRequest, InitiateMultipartBlobStageRequest } from "../../../../internal/validators/request/index.js";
|
|
4
4
|
import type { BlobAttachmentBindResponse, BlobAttachmentDetachResponse, BlobAttachmentSummary, CompleteMultipartBlobStageResponse, DocumentWriterProjectionResponse, InitiateMultipartBlobStageResponse, MultipartBlobStageStatusResponse, UploadMultipartBlobPartResponse } from "../../../../internal/validators/response/index.js";
|
|
@@ -31,7 +31,7 @@ export interface BlobAttachmentApi {
|
|
|
31
31
|
getDocumentWriterProjection(documentId: string): Promise<DocumentWriterProjectionResponse | null>;
|
|
32
32
|
getMultipartBlobStage(stageId: string): Promise<MultipartBlobStageStatusResponse | null>;
|
|
33
33
|
initiateMultipartBlobStage(input: InitiateMultipartBlobStageRequest): Promise<InitiateMultipartBlobStageResponse | null>;
|
|
34
|
-
uploadMultipartBlobPartBytes(stageId: string, partNumber: number, input: UploadMultipartBlobPartBytesRequest): Promise<UploadMultipartBlobPartResponse | null>;
|
|
34
|
+
uploadMultipartBlobPartBytes(stageId: string, partNumber: number, input: UploadMultipartBlobPartBytesRequest, options?: RequestResultOptions): Promise<UploadMultipartBlobPartResponse | null>;
|
|
35
35
|
}
|
|
36
36
|
export interface BlobAttachmentDetachApi {
|
|
37
37
|
detachBlobAttachment(blobId: string, bindingId: string, input: BlobAttachmentDetachRequest, options?: BlobAttachmentRequestOptions): Promise<BlobAttachmentDetachResponse | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAoCA,MAAM,CAAC,MAAM,mCAAmC,GAC9C,wCAAwC,CAAC;AAC3C,MAAM,CAAC,MAAM,8BAA8B,GACzC,mCAAmC,CAAC;AACtC,MAAM,CAAC,MAAM,gCAAgC,GAC3C,qCAAqC,CAAC;AACxC,MAAM,CAAC,MAAM,6BAA6B,GACxC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,yCAAyC,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC","sourcesContent":["import type {\n RequestFailureKind,\n RequestResultOptions,\n UploadMultipartBlobPartBytesRequest,\n} from \"@tearleads/api-client\";\nimport type {\n BlobContentKeyTarget,\n BlobEnvelopeHeaderRecord,\n BlobEnvelopeRecord,\n WriteHeader,\n} from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentBindRequest,\n BlobAttachmentDetachRequest,\n BlobContentKeyBundleRequest,\n CompleteMultipartBlobStageRequest,\n InitiateMultipartBlobStageRequest,\n} from \"@tearleads/validators/request\";\nimport type {\n BlobAttachmentBindResponse,\n BlobAttachmentDetachResponse,\n BlobAttachmentSummary,\n CompleteMultipartBlobStageResponse,\n DocumentWriterProjectionResponse,\n InitiateMultipartBlobStageResponse,\n MultipartBlobStageStatusResponse,\n UploadMultipartBlobPartResponse,\n} from \"@tearleads/validators/response\";\nimport type { BlobByteSourceInput, BlobBytes } from \"../../../blobContracts\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../keyingProjectionVerification\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentCreateAuthor } from \"../../shared/types\";\n\nexport const BLOB_CONTENT_RECORD_KEY_INFO_DOMAIN =\n \"tearleads.blob.content-record-key-info\";\nexport const BLOB_CONTENT_RECORD_AAD_DOMAIN =\n \"tearleads.blob.content-record-aad\";\nexport const BLOB_CONTENT_RECORD_NONCE_DOMAIN =\n \"tearleads.blob.content-record-nonce\";\nexport const BLOB_CONTENT_RECORD_HKDF_SALT: Uint8Array<ArrayBuffer> =\n new TextEncoder().encode(\"tearleads.blob.content-record-hkdf-salt\");\nexport const TEXT_ENCODER = new TextEncoder();\n\nexport interface BlobAttachmentRequestOptions {\n readonly expectedPaymentRequiredOrganizationId?: string | undefined;\n}\n\nexport interface BlobAttachmentApi {\n bindBlobAttachment(\n blobId: string,\n input: BlobAttachmentBindRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentBindResponse | null>;\n clearWriterProjectionCaches?(): void;\n evictDocumentWriterProjection?(documentId: string): void;\n getRequestFailure?(input: {\n method: \"DELETE\" | \"GET\" | \"POST\" | \"PUT\";\n path: string;\n }): {\n readonly code?: string | undefined;\n readonly kind: RequestFailureKind;\n readonly message: string;\n readonly status: number | null;\n } | null;\n completeMultipartBlobStage(\n stageId: string,\n input: CompleteMultipartBlobStageRequest,\n ): Promise<CompleteMultipartBlobStageResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n getMultipartBlobStage(\n stageId: string,\n ): Promise<MultipartBlobStageStatusResponse | null>;\n initiateMultipartBlobStage(\n input: InitiateMultipartBlobStageRequest,\n ): Promise<InitiateMultipartBlobStageResponse | null>;\n uploadMultipartBlobPartBytes(\n stageId: string,\n partNumber: number,\n input: UploadMultipartBlobPartBytesRequest,\n options?: RequestResultOptions,\n ): Promise<UploadMultipartBlobPartResponse | null>;\n}\n\nexport interface BlobAttachmentDetachApi {\n detachBlobAttachment(\n blobId: string,\n bindingId: string,\n input: BlobAttachmentDetachRequest,\n options?: BlobAttachmentRequestOptions,\n ): Promise<BlobAttachmentDetachResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n}\n\nexport type { BlobContentKeyTarget };\n\n/**\n * Aliases of the crypto parser's own types. The parser is shared with the API,\n * so restating these shapes here would let the two drift apart silently.\n */\nexport type BlobEncryptedBytesRecord = BlobEnvelopeRecord;\n\n/**\n * The envelope as the header establishes it. Streaming readers hold this\n * before any ciphertext is read, so it has no `chunks`: an empty array there\n * would read as an empty object rather than an unread one.\n */\nexport type BlobEncryptedBytesHeader = BlobEnvelopeHeaderRecord;\n\nexport type BlobEncryptedChunk = BlobEnvelopeRecord[\"chunks\"][number];\n\nexport interface BlobSourceSnapshot {\n readonly byteLength: number;\n readonly chunkSha256: readonly string[];\n readonly chunkSize: number;\n readonly sha256: string;\n}\n\nexport interface BlobEncryptionPlan {\n readonly byteLength: number;\n readonly chunkSize: number;\n readonly metadataHash: string;\n readonly partCount: number;\n readonly plaintextByteLength: number;\n readonly plaintextSha256: string;\n readonly sha256: string;\n encryptPart(index: number): Promise<BlobBytes>;\n getPartByteLength(index: number): number;\n}\n\nexport interface DocumentManifestIdentity {\n documentId: string;\n manifestHash: string;\n organizationId: string;\n}\n\nexport interface BlobAttachmentMaterial {\n blobAccessManifestHash: string;\n contentKeyBundle: BlobContentKeyBundleRequest;\n encrypted: BlobEncryptionPlan;\n manifestIdentity: DocumentManifestIdentity;\n targetHash: string;\n targets: BlobContentKeyTarget[];\n writerProjection: DocumentWriterProjectionResponse;\n}\n\n/**\n * Progress for an in-flight multipart blob upload.\n */\nexport interface MultipartUploadProgress {\n readonly bytesTotal: number;\n readonly bytesUploaded: number;\n readonly partsCompleted: number;\n readonly partsTotal: number;\n}\n\nexport type MultipartUploadProgressListener = (\n progress: MultipartUploadProgress,\n) => void;\n\n/**\n * Fires once a multipart stage has been opened (or resumed), with its id and\n * plaintext chunk size. Callers persist both so a later attempt can reproduce\n * the same encrypted parts and resume instead of orphaning the partial upload.\n */\nexport type MultipartStageResolvedListener = (input: {\n readonly partSize: number;\n readonly stageId: string;\n}) => void | Promise<void>;\n\nexport interface UploadDocumentAttachmentInput {\n apiClient: BlobAttachmentApi;\n author: DocumentCreateAuthor;\n blobId?: string | undefined;\n bindingId?: string | undefined;\n bytes: BlobByteSourceInput;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedBindingId: string | null;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n // A persisted nonce seed. The plaintext digest derives the envelope IV from\n // it, then each chunk derives a unique IV. Same-source retries reproduce the\n // encrypted parts; changed bytes cannot reuse their AES-GCM nonces.\n nonceSeed?: Uint8Array | undefined;\n multipart?: MultipartBlobUploadOptions | undefined;\n onMultipartProgress?: MultipartUploadProgressListener | undefined;\n onStageResolved?: MultipartStageResolvedListener | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface MultipartBlobUploadOptions {\n /** Exactly 5 MiB per plaintext encryption chunk; transport parts include envelope overhead. */\n readonly partSize: number;\n // The id of a previously opened stage to resume. When set, the upload refetches\n // that stage and skips parts the server already has instead of opening a new\n // one; if the stage is gone (expired), it falls back to a fresh stage.\n readonly resumeStageId?: string | undefined;\n readonly uploadConcurrency?: number | undefined;\n}\n\nexport interface UploadDocumentAttachmentResult {\n blobId: string;\n bindingId: string;\n request: BlobAttachmentBindRequest;\n response: BlobAttachmentBindResponse;\n sha256: string;\n byteLength: number;\n writeHeader: WriteHeader;\n writeHeaderHash: string;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DetachDocumentAttachmentInput {\n apiClient: BlobAttachmentDetachApi;\n author: DocumentCreateAuthor;\n bindingId: string;\n blobId: string;\n documentId: string;\n eventId?: string | undefined;\n execSql: ExecSql;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n slotId: string;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport interface DetachDocumentAttachmentResult {\n request: BlobAttachmentDetachRequest;\n response: BlobAttachmentDetachResponse;\n writerProjection: DocumentWriterProjectionResponse;\n}\n\nexport interface DecryptDocumentAttachmentBlobInput {\n binding: BlobAttachmentSummary;\n encryptedBytes: BlobBytes;\n expectedDocumentId: string;\n expectedSlotId: string;\n execSql: ExecSql;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n targetSecretKey: Uint8Array;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}\n"]}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { describeSyncLaneError, publishSyncCoordinatorSnapshot, } from "./coordinatorState.js";
|
|
2
|
+
import { createSyncTimestamp } from "./syncTelemetry.js";
|
|
3
|
+
const SYNC_LANE_WATCHDOG_MS = 120_000;
|
|
4
|
+
const FAILED_LANE_REARM_BACKOFF_MS = 1000;
|
|
5
|
+
// Keyed on the registered config so a discarded lane is collectable.
|
|
6
|
+
const lastReportedFailureByConfig = new WeakMap();
|
|
7
|
+
// Local-only dedup key. describeSyncLaneError joins messages without their
|
|
8
|
+
// types, so the name keeps a swallowed DatabaseUnavailableError distinct from
|
|
9
|
+
// a plain Error carrying the same text; the cause chain keeps a re-wrapped
|
|
10
|
+
// failure distinct from its origin.
|
|
11
|
+
function describeSyncLaneFailureSignature(error) {
|
|
12
|
+
const name = error instanceof Error ? error.name : typeof error;
|
|
13
|
+
return JSON.stringify([name, describeSyncLaneError(error)]);
|
|
14
|
+
}
|
|
15
|
+
// Observability only: a failing lane re-arms every FAILED_LANE_REARM_BACKOFF_MS
|
|
16
|
+
// for the rest of the session, and mobile WebViews are never reloaded, so an
|
|
17
|
+
// unrecoverable lane would report once a second. The signature is deliberately
|
|
18
|
+
// never cleared on a completed run: alternating success and failure would
|
|
19
|
+
// re-admit the same report every pass and evict the surrounding diagnostic
|
|
20
|
+
// trail from the host's bounded log.
|
|
21
|
+
function reportUnexpectedSyncLaneFailure(state, error) {
|
|
22
|
+
const report = state.config.reportUnexpectedError;
|
|
23
|
+
if (!report)
|
|
24
|
+
return;
|
|
25
|
+
const signature = describeSyncLaneFailureSignature(error);
|
|
26
|
+
if (lastReportedFailureByConfig.get(state.config) === signature)
|
|
27
|
+
return;
|
|
28
|
+
lastReportedFailureByConfig.set(state.config, signature);
|
|
29
|
+
try {
|
|
30
|
+
void Promise.resolve(report(error)).catch(() => undefined);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Hosts may throw synchronously or return a rejected promise.
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function runSyncLane(state) {
|
|
37
|
+
try {
|
|
38
|
+
await state.config.run();
|
|
39
|
+
return { status: "completed" };
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (state.config.shouldIgnoreError?.(error)) {
|
|
43
|
+
return { status: "completed" };
|
|
44
|
+
}
|
|
45
|
+
reportUnexpectedSyncLaneFailure(state, error);
|
|
46
|
+
if (state.config.onUnexpectedError) {
|
|
47
|
+
state.config.onUnexpectedError(error);
|
|
48
|
+
return { status: "failed", error };
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Console-only on purpose. This runs only when the lane's OWN error handler
|
|
54
|
+
// already threw, so it must never route through reportUnexpectedSyncLaneFailure
|
|
55
|
+
// as well: re-entering a handler that just threw would reject runResultPromise
|
|
56
|
+
// from inside its own onRejected callback, leaving `running` true and
|
|
57
|
+
// `activeRunToken` set, which wedges the lane for the rest of the session.
|
|
58
|
+
function reportUnexpectedSyncLaneError(state, error) {
|
|
59
|
+
console.error(`Failed to run sync lane ${state.key}:`, error);
|
|
60
|
+
}
|
|
61
|
+
function recordSyncLaneRunResult(lane, runResult) {
|
|
62
|
+
lane.lastActionAt = createSyncTimestamp();
|
|
63
|
+
if (runResult.status === "failed") {
|
|
64
|
+
lane.errorCount += 1;
|
|
65
|
+
lane.lastAction = "failed";
|
|
66
|
+
lane.lastError = describeSyncLaneError(runResult.error);
|
|
67
|
+
lane.lastFailedAt = lane.lastActionAt;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
lane.lastAction = "completed";
|
|
71
|
+
lane.lastCompletedAt = lane.lastActionAt;
|
|
72
|
+
lane.lastError = null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Replace the watchdog failure with the late result, then release queued work.
|
|
76
|
+
function settleAbandonedSyncLaneRun(coordinatorState, lane, runToken, runResult, wake) {
|
|
77
|
+
if (lane.activeRunToken !== runToken) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
lane.activeRunToken = null;
|
|
81
|
+
lane.runAbandoned = false;
|
|
82
|
+
recordSyncLaneRunResult(lane, runResult);
|
|
83
|
+
publishSyncCoordinatorSnapshot(coordinatorState);
|
|
84
|
+
if (!coordinatorState.disposed && lane.requested) {
|
|
85
|
+
wake();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function startSyncLaneRun(coordinatorState, lane) {
|
|
89
|
+
lane.requested = false;
|
|
90
|
+
lane.notBeforeAtMs = null;
|
|
91
|
+
lane.running = true;
|
|
92
|
+
lane.runCount += 1;
|
|
93
|
+
lane.lastAction = "started";
|
|
94
|
+
lane.lastActionAt = createSyncTimestamp();
|
|
95
|
+
lane.lastStartedAt = lane.lastActionAt;
|
|
96
|
+
lane.runAbandoned = false;
|
|
97
|
+
const runToken = {};
|
|
98
|
+
lane.activeRunToken = runToken;
|
|
99
|
+
publishSyncCoordinatorSnapshot(coordinatorState);
|
|
100
|
+
// Keep follow-up requests even on failure to preserve phase ordering; see
|
|
101
|
+
// docs/client-sync-ordering.md.
|
|
102
|
+
// The fallback also catches errors thrown by the lane's error handlers.
|
|
103
|
+
const runResultPromise = runSyncLane(lane).then((result) => result, (error) => {
|
|
104
|
+
reportUnexpectedSyncLaneError(lane, error);
|
|
105
|
+
return { status: "failed", error };
|
|
106
|
+
});
|
|
107
|
+
return { runToken, runResultPromise };
|
|
108
|
+
}
|
|
109
|
+
export async function runCoordinatorLane(coordinatorState, lane, wake) {
|
|
110
|
+
const { runToken, runResultPromise } = startSyncLaneRun(coordinatorState, lane);
|
|
111
|
+
// Clamp overrides to at least 1ms so every run has a chance to complete.
|
|
112
|
+
const watchdogMs = Math.max(1, lane.config.watchdogMs ?? SYNC_LANE_WATCHDOG_MS);
|
|
113
|
+
let watchdogTimer = null;
|
|
114
|
+
const raceOutcome = await Promise.race([
|
|
115
|
+
runResultPromise.then((result) => ({
|
|
116
|
+
kind: "settled",
|
|
117
|
+
result,
|
|
118
|
+
})),
|
|
119
|
+
new Promise((resolve) => {
|
|
120
|
+
watchdogTimer = setTimeout(() => resolve({ kind: "timed-out" }), watchdogMs);
|
|
121
|
+
}),
|
|
122
|
+
]);
|
|
123
|
+
if (watchdogTimer !== null) {
|
|
124
|
+
clearTimeout(watchdogTimer);
|
|
125
|
+
}
|
|
126
|
+
lane.running = false;
|
|
127
|
+
let runResult;
|
|
128
|
+
if (raceOutcome.kind === "settled") {
|
|
129
|
+
lane.activeRunToken = null;
|
|
130
|
+
runResult = raceOutcome.result;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
lane.runAbandoned = true;
|
|
134
|
+
runResult = {
|
|
135
|
+
status: "failed",
|
|
136
|
+
error: new Error(`Sync lane watchdog: run exceeded ${watchdogMs}ms; continuing with other lanes`),
|
|
137
|
+
};
|
|
138
|
+
void runResultPromise.then((result) => settleAbandonedSyncLaneRun(coordinatorState, lane, runToken, result, wake));
|
|
139
|
+
}
|
|
140
|
+
recordSyncLaneRunResult(lane, runResult);
|
|
141
|
+
publishSyncCoordinatorSnapshot(coordinatorState);
|
|
142
|
+
if (runResult.status === "failed" &&
|
|
143
|
+
lane.requested &&
|
|
144
|
+
raceOutcome.kind === "settled") {
|
|
145
|
+
// A fresh hint cannot bypass a failed lane's cooldown. Other document
|
|
146
|
+
// lanes remain runnable; structural retries still preserve the barrier.
|
|
147
|
+
lane.backingOff = true;
|
|
148
|
+
setTimeout(() => {
|
|
149
|
+
lane.backingOff = false;
|
|
150
|
+
wake();
|
|
151
|
+
}, FAILED_LANE_REARM_BACKOFF_MS);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=coordinatorLaneRun.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinatorLaneRun.js","sourceRoot":"","sources":["coordinatorLaneRun.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DomainSyncCoordinatorState,\n SyncLaneState,\n} from \"./coordinatorState\";\nimport {\n describeSyncLaneError,\n publishSyncCoordinatorSnapshot,\n} from \"./coordinatorState\";\nimport type { SyncLaneConfig } from \"./syncLaneConfig\";\nimport { createSyncTimestamp } from \"./syncTelemetry\";\n\nconst SYNC_LANE_WATCHDOG_MS = 120_000;\nconst FAILED_LANE_REARM_BACKOFF_MS = 1000;\n\ntype SyncLaneRunResult =\n | { status: \"completed\" }\n | { status: \"failed\"; error: unknown };\n\n// Keyed on the registered config so a discarded lane is collectable.\nconst lastReportedFailureByConfig = new WeakMap<SyncLaneConfig, string>();\n\n// Local-only dedup key. describeSyncLaneError joins messages without their\n// types, so the name keeps a swallowed DatabaseUnavailableError distinct from\n// a plain Error carrying the same text; the cause chain keeps a re-wrapped\n// failure distinct from its origin.\nfunction describeSyncLaneFailureSignature(error: unknown): string {\n const name = error instanceof Error ? error.name : typeof error;\n return JSON.stringify([name, describeSyncLaneError(error)]);\n}\n\n// Observability only: a failing lane re-arms every FAILED_LANE_REARM_BACKOFF_MS\n// for the rest of the session, and mobile WebViews are never reloaded, so an\n// unrecoverable lane would report once a second. The signature is deliberately\n// never cleared on a completed run: alternating success and failure would\n// re-admit the same report every pass and evict the surrounding diagnostic\n// trail from the host's bounded log.\nfunction reportUnexpectedSyncLaneFailure(\n state: SyncLaneState,\n error: unknown,\n): void {\n const report = state.config.reportUnexpectedError;\n if (!report) return;\n const signature = describeSyncLaneFailureSignature(error);\n if (lastReportedFailureByConfig.get(state.config) === signature) return;\n lastReportedFailureByConfig.set(state.config, signature);\n try {\n void Promise.resolve(report(error)).catch(() => undefined);\n } catch {\n // Hosts may throw synchronously or return a rejected promise.\n }\n}\n\nasync function runSyncLane(state: SyncLaneState): Promise<SyncLaneRunResult> {\n try {\n await state.config.run();\n return { status: \"completed\" };\n } catch (error: unknown) {\n if (state.config.shouldIgnoreError?.(error)) {\n return { status: \"completed\" };\n }\n reportUnexpectedSyncLaneFailure(state, error);\n\n if (state.config.onUnexpectedError) {\n state.config.onUnexpectedError(error);\n return { status: \"failed\", error };\n }\n\n throw error;\n }\n}\n\n// Console-only on purpose. This runs only when the lane's OWN error handler\n// already threw, so it must never route through reportUnexpectedSyncLaneFailure\n// as well: re-entering a handler that just threw would reject runResultPromise\n// from inside its own onRejected callback, leaving `running` true and\n// `activeRunToken` set, which wedges the lane for the rest of the session.\nfunction reportUnexpectedSyncLaneError(state: SyncLaneState, error: unknown) {\n console.error(`Failed to run sync lane ${state.key}:`, error);\n}\n\nfunction recordSyncLaneRunResult(\n lane: SyncLaneState,\n runResult: SyncLaneRunResult,\n): void {\n lane.lastActionAt = createSyncTimestamp();\n if (runResult.status === \"failed\") {\n lane.errorCount += 1;\n lane.lastAction = \"failed\";\n lane.lastError = describeSyncLaneError(runResult.error);\n lane.lastFailedAt = lane.lastActionAt;\n } else {\n lane.lastAction = \"completed\";\n lane.lastCompletedAt = lane.lastActionAt;\n lane.lastError = null;\n }\n}\n\n// Replace the watchdog failure with the late result, then release queued work.\nfunction settleAbandonedSyncLaneRun(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n runToken: object,\n runResult: SyncLaneRunResult,\n wake: () => void,\n): void {\n if (lane.activeRunToken !== runToken) {\n return;\n }\n lane.activeRunToken = null;\n lane.runAbandoned = false;\n recordSyncLaneRunResult(lane, runResult);\n publishSyncCoordinatorSnapshot(coordinatorState);\n if (!coordinatorState.disposed && lane.requested) {\n wake();\n }\n}\n\nfunction startSyncLaneRun(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n) {\n lane.requested = false;\n lane.notBeforeAtMs = null;\n lane.running = true;\n lane.runCount += 1;\n lane.lastAction = \"started\";\n lane.lastActionAt = createSyncTimestamp();\n lane.lastStartedAt = lane.lastActionAt;\n lane.runAbandoned = false;\n const runToken = {};\n lane.activeRunToken = runToken;\n publishSyncCoordinatorSnapshot(coordinatorState);\n\n // Keep follow-up requests even on failure to preserve phase ordering; see\n // docs/client-sync-ordering.md.\n // The fallback also catches errors thrown by the lane's error handlers.\n const runResultPromise: Promise<SyncLaneRunResult> = runSyncLane(lane).then(\n (result) => result,\n (error: unknown) => {\n reportUnexpectedSyncLaneError(lane, error);\n return { status: \"failed\", error };\n },\n );\n\n return { runToken, runResultPromise };\n}\n\nexport async function runCoordinatorLane(\n coordinatorState: DomainSyncCoordinatorState,\n lane: SyncLaneState,\n wake: () => void,\n): Promise<void> {\n const { runToken, runResultPromise } = startSyncLaneRun(\n coordinatorState,\n lane,\n );\n // Clamp overrides to at least 1ms so every run has a chance to complete.\n const watchdogMs = Math.max(\n 1,\n lane.config.watchdogMs ?? SYNC_LANE_WATCHDOG_MS,\n );\n let watchdogTimer: ReturnType<typeof setTimeout> | null = null;\n const raceOutcome = await Promise.race([\n runResultPromise.then((result) => ({\n kind: \"settled\" as const,\n result,\n })),\n new Promise<{ kind: \"timed-out\" }>((resolve) => {\n watchdogTimer = setTimeout(\n () => resolve({ kind: \"timed-out\" }),\n watchdogMs,\n );\n }),\n ]);\n if (watchdogTimer !== null) {\n clearTimeout(watchdogTimer);\n }\n\n lane.running = false;\n let runResult: SyncLaneRunResult;\n if (raceOutcome.kind === \"settled\") {\n lane.activeRunToken = null;\n runResult = raceOutcome.result;\n } else {\n lane.runAbandoned = true;\n runResult = {\n status: \"failed\",\n error: new Error(\n `Sync lane watchdog: run exceeded ${watchdogMs}ms; continuing with other lanes`,\n ),\n };\n void runResultPromise.then((result) =>\n settleAbandonedSyncLaneRun(\n coordinatorState,\n lane,\n runToken,\n result,\n wake,\n ),\n );\n }\n recordSyncLaneRunResult(lane, runResult);\n publishSyncCoordinatorSnapshot(coordinatorState);\n\n if (\n runResult.status === \"failed\" &&\n lane.requested &&\n raceOutcome.kind === \"settled\"\n ) {\n // A fresh hint cannot bypass a failed lane's cooldown. Other document\n // lanes remain runnable; structural retries still preserve the barrier.\n lane.backingOff = true;\n setTimeout(() => {\n lane.backingOff = false;\n wake();\n }, FAILED_LANE_REARM_BACKOFF_MS);\n }\n}\n"]}
|