@tearleads/client-sdk 0.1.87 → 0.1.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Tearleads.js +1 -1
- package/Tearleads.js.map +1 -1
- package/client/containerContents/documentDiscovery.js +16 -2
- package/client/containerContents/documentDiscovery.js.map +1 -1
- package/client/containerContents/index.d.ts +1 -1
- package/client/containerContents/index.js +1 -0
- package/client/containerContents/index.js.map +1 -1
- package/client/index.d.ts +1 -1
- package/client/index.js.map +1 -1
- package/client/organizations/index.d.ts +4 -2
- package/client/organizations/index.js +15 -8
- package/client/organizations/index.js.map +1 -1
- package/client/organizations/organizationMemberships.d.ts +41 -0
- package/client/organizations/organizationMemberships.js +166 -0
- package/client/organizations/organizationMemberships.js.map +1 -0
- package/client/organizations/organizationReadModels.d.ts +7 -1
- package/client/organizations/organizationReadModels.js +15 -6
- package/client/organizations/organizationReadModels.js.map +1 -1
- package/client/organizations/organizationsTypes.d.ts +3 -0
- package/client/organizations/organizationsTypes.js.map +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js +19 -14
- package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
- package/data/persistence/container-contents/exclusiveDocumentPlacements.js +60 -0
- package/data/persistence/container-contents/exclusiveDocumentPlacements.js.map +1 -0
- package/data/persistence/organizations/organizationReadModelPersistence.js +14 -0
- package/data/persistence/organizations/organizationReadModelPersistence.js.map +1 -1
- package/data/persistence/organizations/organizationReadModelProjection.js +12 -0
- package/data/persistence/organizations/organizationReadModelProjection.js.map +1 -1
- package/data/sqlite/schema/index.d.ts +90 -0
- package/data/sqlite/schema/index.js +3 -0
- package/data/sqlite/schema/index.js.map +1 -1
- package/data/sqlite/schema/organizationReadModelSchema.js +2 -0
- package/data/sqlite/schema/organizationReadModelSchema.js.map +1 -1
- package/data/sqlite/schema/organizationReadModelTableRegistry.d.ts +19 -0
- package/data/sqlite/schema/organizationSyncPauseSchema.js +32 -0
- package/data/sqlite/schema/organizationSyncPauseSchema.js.map +1 -0
- package/data/sync/organizationSyncPauses.d.ts +59 -0
- package/data/sync/organizationSyncPauses.js +149 -0
- package/data/sync/organizationSyncPauses.js.map +1 -0
- package/index.d.ts +2 -2
- package/index.js.map +1 -1
- package/internal/api-client/ApiClient.d.ts +21 -2
- package/internal/api-client/ApiClient.js +15 -1
- package/internal/api-client/ApiClient.js.map +1 -1
- package/internal/api-client/routes/organizations/memberships.js +36 -0
- package/internal/api-client/routes/organizations/memberships.js.map +1 -0
- package/internal/crypto/index.d.ts +1 -0
- package/internal/crypto/index.js +1 -0
- package/internal/crypto/index.js.map +1 -1
- package/internal/crypto/organizationLeaveRequest.d.ts +13 -0
- package/internal/crypto/organizationLeaveRequest.js +39 -0
- package/internal/crypto/organizationLeaveRequest.js.map +1 -0
- package/internal/validators/operation/index.d.ts +1 -0
- package/internal/validators/operation/index.js +1 -0
- package/internal/validators/operation/index.js.map +1 -1
- package/internal/validators/operation/organizationMemberships.d.ts +503 -0
- package/internal/validators/operation/organizationMemberships.js +93 -0
- package/internal/validators/operation/organizationMemberships.js.map +1 -0
- package/internal/validators/operation/organizations.d.ts +48 -0
- package/internal/validators/operation/registry.d.ts +5 -0
- package/internal/validators/operation/registry.js +5 -0
- package/internal/validators/operation/registry.js.map +1 -1
- package/internal/validators/realtime/index.js +1 -1
- package/internal/validators/realtime/index.js.map +1 -1
- package/internal/validators/realtime/wsInvalidationHints.js +8 -0
- package/internal/validators/realtime/wsInvalidationHints.js.map +1 -1
- package/internal/validators/request/index.d.ts +1 -1
- package/internal/validators/request/index.js +1 -1
- package/internal/validators/request/index.js.map +1 -1
- package/internal/validators/request/organization.d.ts +6 -0
- package/internal/validators/request/organization.js +7 -0
- package/internal/validators/request/organization.js.map +1 -1
- package/internal/validators/response/index.d.ts +1 -0
- package/internal/validators/response/index.js +1 -0
- package/internal/validators/response/index.js.map +1 -1
- package/internal/validators/response/organization.d.ts +82 -0
- package/internal/validators/response/organization.js +6 -0
- package/internal/validators/response/organization.js.map +1 -1
- package/internal/validators/response/organizationMembership.d.ts +66 -0
- package/internal/validators/response/organizationMembership.js +29 -0
- package/internal/validators/response/organizationMembership.js.map +1 -0
- package/internal/validators/response/organizationReadModel.d.ts +60 -0
- package/internal/validators/util/index.d.ts +1 -0
- package/internal/validators/util/index.js +1 -0
- package/internal/validators/util/index.js.map +1 -1
- package/internal/validators/util/organizationLeaveRequest.d.ts +15 -0
- package/internal/validators/util/organizationLeaveRequest.js +22 -0
- package/internal/validators/util/organizationLeaveRequest.js.map +1 -0
- package/package.json +1 -1
- package/stores/container-contents/containerContentsStore.d.ts +1 -1
- package/stores/container-contents/containerContentsStore.js +2 -0
- package/stores/container-contents/containerContentsStore.js.map +1 -1
- package/stores/container-contents/operations/forgetOrganizationContentOperation.js +76 -0
- package/stores/container-contents/operations/forgetOrganizationContentOperation.js.map +1 -0
- package/stores/container-contents/types.d.ts +6 -0
- package/stores/container-contents/types.js.map +1 -1
- package/stores/documents/documentStore/attachments/attachmentRemoval.js +3 -4
- package/stores/documents/documentStore/attachments/attachmentRemoval.js.map +1 -1
- package/stores/documents/documentStore/attachments/index.js +5 -7
- package/stores/documents/documentStore/attachments/index.js.map +1 -1
- package/stores/documents/documentStore/index.js +16 -12
- package/stores/documents/documentStore/index.js.map +1 -1
- package/stores/documents/documentStore/initialization/index.js +9 -0
- package/stores/documents/documentStore/initialization/index.js.map +1 -1
- package/stores/documents/documentStore/mutations.js +5 -7
- package/stores/documents/documentStore/mutations.js.map +1 -1
- package/stores/documents/documentStore/rotation/index.js +2 -1
- package/stores/documents/documentStore/rotation/index.js.map +1 -1
- package/stores/documents/documentStore/rows/index.js +3 -4
- package/stores/documents/documentStore/rows/index.js.map +1 -1
- package/stores/documents/documentStore/state.js +18 -0
- package/stores/documents/documentStore/state.js.map +1 -1
- package/stores/documents/documentStore/sync/index.js +5 -2
- package/stores/documents/documentStore/sync/index.js.map +1 -1
- package/stores/documents/registry.d.ts +32 -0
- package/stores/documents/registry.js +79 -4
- package/stores/documents/registry.js.map +1 -1
- package/stores/documents/removedDocumentStore.js +38 -0
- package/stores/documents/removedDocumentStore.js.map +1 -0
- package/stores/documents/types.d.ts +2 -0
- package/stores/documents/types.js.map +1 -1
- package/sync/reconciliation/service.js +2 -2
- package/sync/reconciliation/service.js.map +1 -1
- package/sync/reconciliation/serviceTypes.d.ts +8 -1
- package/sync/reconciliation/serviceTypes.js.map +1 -1
- package/workflows/container-contents/pendingWrites/index.d.ts +5 -0
- package/workflows/container-contents/pendingWrites/index.js +7 -0
- package/workflows/container-contents/pendingWrites/index.js.map +1 -1
- package/workflows/container-contents/remoteHydration/index.js +7 -1
- package/workflows/container-contents/remoteHydration/index.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/organizationSyncPauseFilter.js +13 -0
- package/workflows/container-contents/remoteHydration/remoteContainers/organizationSyncPauseFilter.js.map +1 -0
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js +13 -2
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js.map +1 -1
- package/workflows/container-contents/syncPause/discoveryGuard.js +31 -0
- package/workflows/container-contents/syncPause/discoveryGuard.js.map +1 -0
- package/workflows/container-contents/syncPause/documentRemoval.js +154 -0
- package/workflows/container-contents/syncPause/documentRemoval.js.map +1 -0
- package/workflows/organizations/index.d.ts +3 -0
- package/workflows/organizations/index.js +3 -0
- package/workflows/organizations/index.js.map +1 -1
- package/workflows/organizations/memberships/leaveRequest.d.ts +31 -0
- package/workflows/organizations/memberships/leaveRequest.js +20 -0
- package/workflows/organizations/memberships/leaveRequest.js.map +1 -0
- package/workflows/organizations/memberships/leaveRequestVerification.d.ts +15 -0
- package/workflows/organizations/memberships/leaveRequestVerification.js +46 -0
- package/workflows/organizations/memberships/leaveRequestVerification.js.map +1 -0
- package/workflows/organizations/memberships/organizationMemberships.d.ts +84 -0
- package/workflows/organizations/memberships/organizationMemberships.js +95 -0
- package/workflows/organizations/memberships/organizationMemberships.js.map +1 -0
- package/workflows/sync/index.d.ts +1 -0
- package/workflows/sync/index.js +1 -0
- package/workflows/sync/index.js.map +1 -1
|
@@ -6,7 +6,7 @@ import { ensureDocumentStoreReady } from "../initialization/index.js";
|
|
|
6
6
|
import { revalidateDocumentMutationIdentity } from "../mutationIdentityRevalidation.js";
|
|
7
7
|
import { advancePendingBaseVersion, pendingDeltaSinceBase, persistDocument, } from "../persistence.js";
|
|
8
8
|
import { reportDocumentStoreWriteFailure } from "../reportWriteFailure.js";
|
|
9
|
-
import { canWriteDocument, } from "../state.js";
|
|
9
|
+
import { canWriteDocument, chainQueuedWrite, } from "../state.js";
|
|
10
10
|
import { captureDocumentStoreSyncGeneration, isDocumentStoreSyncGenerationCurrent, } from "../sync/syncGeneration.js";
|
|
11
11
|
import { resolveRowAttribution } from "./rowAttribution.js";
|
|
12
12
|
// Fixed literal: a reported message must never carry row ids or field values.
|
|
@@ -66,13 +66,12 @@ function queueRowMutation(state, mutate) {
|
|
|
66
66
|
// `setReadySnapshot` always re-derives them from the doc — so there is no
|
|
67
67
|
// optimistic snapshot for a concurrent sync pass to clobber. Input smoothness
|
|
68
68
|
// during rapid edits is handled in the app layer (useDocumentRowEditing).
|
|
69
|
-
state
|
|
69
|
+
return chainQueuedWrite(state, state.writeChain
|
|
70
70
|
.catch(() => undefined)
|
|
71
71
|
.then(async () => persistRowMutation(state, writeGeneration, mutate))
|
|
72
72
|
.catch((error) => {
|
|
73
73
|
reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);
|
|
74
|
-
});
|
|
75
|
-
return state.writeChain;
|
|
74
|
+
}));
|
|
76
75
|
}
|
|
77
76
|
export async function addRowToDocumentStore(state, scheduleSync, fields) {
|
|
78
77
|
const id = createDocumentRowId();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { encodeVersionVector } from \"@tearleads/loro\";\nimport {\n addDocumentRow,\n createDocumentRowId,\n removeDocumentRow,\n setDocumentRowFields,\n} from \"../../../../data/documents/documentRowList\";\nimport { createPendingUpdateFields } from \"../../../../data/documents/documentSync\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { ensureDocumentStoreReady } from \"../initialization\";\nimport { revalidateDocumentMutationIdentity } from \"../mutationIdentityRevalidation\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n persistDocument,\n} from \"../persistence\";\nimport { reportDocumentStoreWriteFailure } from \"../reportWriteFailure\";\nimport {\n canWriteDocument,\n type DocumentState,\n type DocumentStoreState,\n} from \"../state\";\nimport {\n captureDocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"../sync/syncGeneration\";\nimport { resolveRowAttribution } from \"./rowAttribution\";\n\n// Fixed literal: a reported message must never carry row ids or field values.\nconst ROW_FAILURE_MESSAGE = \"Documents: row mutation failed\";\n\nasync function persistRowMutation(\n state: DocumentStoreState,\n expectedLocalWriteGeneration: number,\n mutate: (doc: DocumentState) => boolean,\n): Promise<void> {\n if (state.localWriteGeneration !== expectedLocalWriteGeneration) {\n return;\n }\n const currentDoc = state.doc;\n if (!currentDoc || !canWriteDocument(state)) {\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n if (!mutate(currentDoc)) {\n await revalidateDocumentMutationIdentity({ currentDoc, generation, state });\n return;\n }\n\n const update = pendingDeltaSinceBase(state, currentDoc);\n if (update.byteLength === 0) {\n await revalidateDocumentMutationIdentity({ currentDoc, generation, state });\n return;\n }\n // Captured at delta time: the enqueued row proves coverage up to exactly\n // this version, so it is the frontier the persist below may publish.\n const coveredVersion = encodeVersionVector(currentDoc);\n\n const pendingUpdate = createPendingUpdateFields(update);\n if (!pendingUpdate) {\n await revalidateDocumentMutationIdentity({ currentDoc, generation, state });\n return;\n }\n // Row writes change neither prose nor structured fields; setReadySnapshot\n // always re-derives rows from the doc, so preserve the text/structured fields\n // in case this write overlaps an in-flight keystroke elsewhere.\n const persisted = await persistDocument(\n state,\n currentDoc,\n { snapshotEndVersion: coveredVersion },\n {\n pendingUpdate,\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n },\n generation,\n );\n if (\n !persisted ||\n persisted.pullContinuationSuperseded ||\n persisted.syncIdentitySuperseded ||\n !isDocumentStoreSyncGenerationCurrent(state, generation)\n ) {\n // Refused: the document was deleted while this persist was queued\n // and the store is cleared — no state advance, no sync request.\n return;\n }\n advancePendingBaseVersion(state, currentDoc);\n requestDocumentStoreSync(state);\n}\n\nfunction queueRowMutation(\n state: DocumentStoreState,\n mutate: (doc: DocumentState) => boolean,\n): Promise<void> {\n const writeGeneration = state.localWriteGeneration;\n // Unlike text/structured-field writes, row writes intentionally do NOT bump\n // `state.pendingLocalWrites`: rows are never in the optimistic-preserve set —\n // `setReadySnapshot` always re-derives them from the doc — so there is no\n // optimistic snapshot for a concurrent sync pass to clobber. Input smoothness\n // during rapid edits is handled in the app layer (useDocumentRowEditing).\n state.writeChain = state.writeChain\n .catch(() => undefined)\n .then(async () => persistRowMutation(state, writeGeneration, mutate))\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n });\n return state.writeChain;\n}\n\nexport async function addRowToDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n fields: Readonly<Record<string, string>>,\n): Promise<string> {\n const id = createDocumentRowId();\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n return id;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return id;\n }\n\n await queueRowMutation(state, (doc) => {\n addDocumentRow(doc, id, fields, resolveRowAttribution(state));\n return true;\n });\n return id;\n}\n\nexport async function updateRowInDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n id: string,\n patch: Readonly<Record<string, string>>,\n): Promise<void> {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n await queueRowMutation(state, (doc) =>\n setDocumentRowFields(doc, id, patch, resolveRowAttribution(state)),\n );\n}\n\nexport async function removeRowFromDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n id: string,\n): Promise<void> {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n await queueRowMutation(state, (doc) => removeDocumentRow(doc, id));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { encodeVersionVector } from \"@tearleads/loro\";\nimport {\n addDocumentRow,\n createDocumentRowId,\n removeDocumentRow,\n setDocumentRowFields,\n} from \"../../../../data/documents/documentRowList\";\nimport { createPendingUpdateFields } from \"../../../../data/documents/documentSync\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { ensureDocumentStoreReady } from \"../initialization\";\nimport { revalidateDocumentMutationIdentity } from \"../mutationIdentityRevalidation\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n persistDocument,\n} from \"../persistence\";\nimport { reportDocumentStoreWriteFailure } from \"../reportWriteFailure\";\nimport {\n canWriteDocument,\n chainQueuedWrite,\n type DocumentState,\n type DocumentStoreState,\n} from \"../state\";\nimport {\n captureDocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"../sync/syncGeneration\";\nimport { resolveRowAttribution } from \"./rowAttribution\";\n\n// Fixed literal: a reported message must never carry row ids or field values.\nconst ROW_FAILURE_MESSAGE = \"Documents: row mutation failed\";\n\nasync function persistRowMutation(\n state: DocumentStoreState,\n expectedLocalWriteGeneration: number,\n mutate: (doc: DocumentState) => boolean,\n): Promise<void> {\n if (state.localWriteGeneration !== expectedLocalWriteGeneration) {\n return;\n }\n const currentDoc = state.doc;\n if (!currentDoc || !canWriteDocument(state)) {\n return;\n }\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) {\n return;\n }\n\n if (!mutate(currentDoc)) {\n await revalidateDocumentMutationIdentity({ currentDoc, generation, state });\n return;\n }\n\n const update = pendingDeltaSinceBase(state, currentDoc);\n if (update.byteLength === 0) {\n await revalidateDocumentMutationIdentity({ currentDoc, generation, state });\n return;\n }\n // Captured at delta time: the enqueued row proves coverage up to exactly\n // this version, so it is the frontier the persist below may publish.\n const coveredVersion = encodeVersionVector(currentDoc);\n\n const pendingUpdate = createPendingUpdateFields(update);\n if (!pendingUpdate) {\n await revalidateDocumentMutationIdentity({ currentDoc, generation, state });\n return;\n }\n // Row writes change neither prose nor structured fields; setReadySnapshot\n // always re-derives rows from the doc, so preserve the text/structured fields\n // in case this write overlaps an in-flight keystroke elsewhere.\n const persisted = await persistDocument(\n state,\n currentDoc,\n { snapshotEndVersion: coveredVersion },\n {\n pendingUpdate,\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n },\n generation,\n );\n if (\n !persisted ||\n persisted.pullContinuationSuperseded ||\n persisted.syncIdentitySuperseded ||\n !isDocumentStoreSyncGenerationCurrent(state, generation)\n ) {\n // Refused: the document was deleted while this persist was queued\n // and the store is cleared — no state advance, no sync request.\n return;\n }\n advancePendingBaseVersion(state, currentDoc);\n requestDocumentStoreSync(state);\n}\n\nfunction queueRowMutation(\n state: DocumentStoreState,\n mutate: (doc: DocumentState) => boolean,\n): Promise<void> {\n const writeGeneration = state.localWriteGeneration;\n // Unlike text/structured-field writes, row writes intentionally do NOT bump\n // `state.pendingLocalWrites`: rows are never in the optimistic-preserve set —\n // `setReadySnapshot` always re-derives them from the doc — so there is no\n // optimistic snapshot for a concurrent sync pass to clobber. Input smoothness\n // during rapid edits is handled in the app layer (useDocumentRowEditing).\n return chainQueuedWrite(\n state,\n state.writeChain\n .catch(() => undefined)\n .then(async () => persistRowMutation(state, writeGeneration, mutate))\n .catch((error: unknown) => {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n }),\n );\n}\n\nexport async function addRowToDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n fields: Readonly<Record<string, string>>,\n): Promise<string> {\n const id = createDocumentRowId();\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n return id;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return id;\n }\n\n await queueRowMutation(state, (doc) => {\n addDocumentRow(doc, id, fields, resolveRowAttribution(state));\n return true;\n });\n return id;\n}\n\nexport async function updateRowInDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n id: string,\n patch: Readonly<Record<string, string>>,\n): Promise<void> {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n await queueRowMutation(state, (doc) =>\n setDocumentRowFields(doc, id, patch, resolveRowAttribution(state)),\n );\n}\n\nexport async function removeRowFromDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n id: string,\n): Promise<void> {\n let ready: boolean;\n try {\n ready = await ensureDocumentStoreReady(state, scheduleSync);\n } catch (error) {\n reportDocumentStoreWriteFailure(state, ROW_FAILURE_MESSAGE, error);\n return;\n }\n\n if (!ready || !state.doc || !canWriteDocument(state)) {\n return;\n }\n\n await queueRowMutation(state, (doc) => removeDocumentRow(doc, id));\n}\n"]}
|
|
@@ -45,6 +45,7 @@ export function createDocumentStoreState(localId, initialRuntime, persistence, e
|
|
|
45
45
|
pendingBaseVersion: null,
|
|
46
46
|
pendingLocalWrites: 0,
|
|
47
47
|
persistence,
|
|
48
|
+
queuedWrites: 0,
|
|
48
49
|
pullContinuation: null,
|
|
49
50
|
record: null,
|
|
50
51
|
rejectedServedAttachmentBindings: new Set(),
|
|
@@ -194,4 +195,21 @@ export function subscribeToDocumentStore(state, listener) {
|
|
|
194
195
|
state.listeners.add(listener);
|
|
195
196
|
return () => void state.listeners.delete(listener);
|
|
196
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Counts `write` in `queuedWrites` until it settles. Counted synchronously, so
|
|
200
|
+
* a write started while a removal runs is visible to its commit guard.
|
|
201
|
+
*/
|
|
202
|
+
export function countQueuedWrite(state, write) {
|
|
203
|
+
state.queuedWrites += 1;
|
|
204
|
+
const settle = () => {
|
|
205
|
+
state.queuedWrites -= 1;
|
|
206
|
+
};
|
|
207
|
+
void write.then(settle, settle);
|
|
208
|
+
return write;
|
|
209
|
+
}
|
|
210
|
+
/** Installs `link` as the store's write chain, counted until it settles. */
|
|
211
|
+
export function chainQueuedWrite(state, link) {
|
|
212
|
+
state.writeChain = countQueuedWrite(state, link);
|
|
213
|
+
return state.writeChain;
|
|
214
|
+
}
|
|
197
215
|
//# sourceMappingURL=state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["state.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,EAEL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,GAExB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAEL,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yCAAyC,CAAC;AAIjD,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAGL,uCAAuC,EAOvC,2BAA2B,GAC5B,MAAM,8BAA8B,CAAC;AAMtC,OAAO,EACL,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAqJ9E,MAAM,uBAAuB,GAAqB;IAChD,WAAW,EAAE,EAAE;IACf,wBAAwB,EAAE,EAAE;IAC5B,4BAA4B,EAAE,EAAE;IAChC,SAAS,EAAE,KAAK;IAChB,QAAQ,EAAE,IAAI;IACd,eAAe,EAAE,IAAI;IACrB,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,qBAAqB;IACnC,oBAAoB,EAAE,OAAO;IAC7B,qBAAqB,EAAE,EAAE;IACzB,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,EAAE;IACR,gBAAgB,EAAE,EAAE;IACpB,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,MAAM,UAAU,wBAAwB,CACtC,OAAe,EACf,cAAgC,EAChC,WAAiC,EACjC,OAAwC,EACxC,iBAAgC,EAChC,WAAW,GAAG,EAAE,EAChB,sBAA0C,qBAAqB,EAC/D,yBAAyB,GAAG,IAAI;IAEhC,OAAO;QACL,wBAAwB,EAAE,EAAE;QAC5B,+BAA+B,EAAE,EAAE;QACnC,4BAA4B,EAAE,EAAE;QAChC,GAAG,EAAE,IAAI;QACT,OAAO;QACP,iBAAiB;QACjB,mBAAmB;QACnB,WAAW;QACX,iBAAiB,EAAE,IAAI;QACvB,WAAW,EAAE,KAAK;QAClB,cAAc,EAAE,CAAC;QACjB,oBAAoB,EAAE,CAAC;QACvB,wBAAwB,EAAE,IAAI,GAAG,EAAE;QACnC,OAAO;QACP,SAAS,EAAE,IAAI,GAAG,EAAE;QACpB,kBAAkB,EAAE,EAAE;QACtB,kBAAkB,EAAE,IAAI;QACxB,kBAAkB,EAAE,CAAC;QACrB,WAAW;QACX,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,IAAI;QACZ,gCAAgC,EAAE,IAAI,GAAG,EAAE;QAC3C,kBAAkB,EAAE,CAAC;QACrB,wBAAwB,EACtB,uCAAuC,CAAC,cAAc,CAAC;QACzD,8BAA8B,EAAE,CAAC;QACjC,iBAAiB,EAAE,CAAC,yBAAyB;QAC7C,yBAAyB;QACzB,sBAAsB,EAAE,KAAK;QAC7B,mBAAmB,EAAE,KAAK;QAC1B,qBAAqB,EAAE,CAAC;QACxB,OAAO,EAAE,cAAc;QACvB,QAAQ,EAAE,EAAE,GAAG,uBAAuB,EAAE;QACxC,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,OAAO,CAAC,OAAO,EAAE;QAC7B,gBAAgB,EAAE,IAAI;QACtB,0BAA0B,EAAE,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAyB;IAClD,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACvC,QAAQ,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,KAAyB,EACzB,IAAsB;IAEtB,IACE,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC;QACrE,kBAAkB,CAChB,KAAK,CAAC,QAAQ,CAAC,wBAAwB,EACvC,IAAI,CAAC,wBAAwB,CAC9B;QACD,kBAAkB,CAChB,KAAK,CAAC,QAAQ,CAAC,4BAA4B,EAC3C,IAAI,CAAC,4BAA4B,CAClC;QACD,KAAK,CAAC,QAAQ,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS;QAC3C,KAAK,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;QACzC,KAAK,CAAC,QAAQ,CAAC,eAAe,KAAK,IAAI,CAAC,eAAe;QACvD,KAAK,CAAC,QAAQ,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU;QAC7C,KAAK,CAAC,QAAQ,CAAC,YAAY,KAAK,IAAI,CAAC,YAAY;QACjD,KAAK,CAAC,QAAQ,CAAC,oBAAoB,KAAK,IAAI,CAAC,oBAAoB;QACjE,oBAAoB,CAClB,KAAK,CAAC,QAAQ,CAAC,qBAAqB,EACpC,IAAI,CAAC,qBAAqB,CAC3B;QACD,KAAK,CAAC,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;QACnC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;QAChD,kBAAkB,CAChB,KAAK,CAAC,QAAQ,CAAC,gBAAgB,EAC/B,IAAI,CAAC,gBAAgB,CACtB;QACD,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI;QACjC,KAAK,CAAC,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;QACnC,KAAK,CAAC,QAAQ,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,EACvC,CAAC;QACD,OAAO;IACT,CAAC;IAED,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACtB,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAyB,EACzB,EAAE,WAAW,EAA4B;IAEzC,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC;IACjC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC;IACjB,KAAK,CAAC,oBAAoB,IAAI,CAAC,CAAC;IAChC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,CAAC,kBAAkB,GAAG,EAAE,CAAC;IAC9B,KAAK,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,kBAAkB,GAAG,CAAC,CAAC;IAC7B,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC;IACpC,KAAK,CAAC,+BAA+B,GAAG,EAAE,CAAC;IAC3C,KAAK,CAAC,4BAA4B,GAAG,EAAE,CAAC;IACxC,KAAK,CAAC,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAC;IAC3C,KAAK,CAAC,gCAAgC,GAAG,IAAI,GAAG,EAAE,CAAC;IACnD,KAAK,CAAC,8BAA8B,GAAG,CAAC,CAAC;IACzC,KAAK,CAAC,iBAAiB,GAAG,CAAC,KAAK,CAAC,yBAAyB,CAAC;IAC3D,KAAK,CAAC,sBAAsB,GAAG,KAAK,CAAC;IACrC,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC;IAClC,KAAK,CAAC,qBAAqB,GAAG,CAAC,CAAC;IAChC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IACrC,mBAAmB,CAAC,KAAK,EAAE,EAAE,GAAG,uBAAuB,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,uBAAuB,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAyB;IAChE,uBAAuB,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAyB;IACtD,OAAO,CACL,gBAAgB,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO;QACxC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAC5C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAyB;IACxD,OAAO,4BAA4B,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAyB,EACzB,aAAmC,KAAK,CAAC,GAAG;IAE5C,OAAO,UAAU,CAAC,CAAC,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,eAAe,CACtB,KAAyB,EACzB,aAAmC,KAAK,CAAC,GAAG;IAE5C,OAAO,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAyB;IACvD,OAAO,2BAA2B,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAyB,EACzB,UAAyB,EACzB,OAAgB,EAChB,YAAqB,EACrB,wBAA+D;IAE/D,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,uBAAuB,CAC3C,UAAU,EACV,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,CACvC,CAAC;IACF,MAAM,IAAI,GAAG,YAAY,IAAI,aAAa,CAAC,IAAI,CAAC;IAChD,MAAM,gBAAgB,GACpB,wBAAwB,IAAI,aAAa,CAAC,gBAAgB,CAAC;IAC7D,MAAM,cAAc,GAClB,YAAY,KAAK,SAAS,IAAI,wBAAwB,KAAK,SAAS;QAClE,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,0BAA0B,CACxB;YACE,YAAY,EAAE,aAAa,CAAC,YAAY;YACxC,gBAAgB;YAChB,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;SAC9D,EACD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,CACvC,CAAC;IAER,mBAAmB,CAAC,KAAK,EAAE;QACzB,WAAW;QACX,wBAAwB,EAAE,qBAAqB,CAAC;YAC9C,WAAW;YACX,qBAAqB,EAAE,KAAK,CAAC,+BAA+B;YAC5D,cAAc,EAAE,IAAI,GAAG,CACrB,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAChE;SACF,CAAC;QACF,4BAA4B,EAAE,wBAAwB,CACpD,KAAK,CAAC,4BAA4B,EAClC,WAAW,CACZ;QACD,SAAS,EAAE,cAAc,CAAC,KAAK,CAAC;QAChC,QAAQ,EAAE,gBAAgB,CAAC,KAAK,CAAC;QACjC,eAAe,EAAE,sBAAsB,CAAC,KAAK,CAAC;QAC9C,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,IAAI;QAC5C,YAAY,EAAE,cAAc,CAAC,YAAY;QACzC,oBAAoB,EAAE,6BAA6B,CACjD,KAAK,CAAC,MAAM,EAAE,oBAAoB,CACnC;QACD,qBAAqB,EAAE,cAAc,CAAC,qBAAqB;QAC3D,KAAK,EAAE,IAAI;QACX,IAAI;QACJ,gBAAgB,EAAE,cAAc,CAAC,gBAAgB;QACjD,IAAI;QACJ,KAAK,EAAE,cAAc,CAAC,KAAK;QAC3B,OAAO;KACR,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAyB,EACzB,OAAgB;IAEhB,mBAAmB,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,KAAyB;IACpE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,mBAAmB,CAAC,KAAK,EAAE;QACzB,GAAG,KAAK,CAAC,QAAQ;QACjB,SAAS,EAAE,cAAc,CAAC,KAAK,CAAC;QAChC,QAAQ,EAAE,gBAAgB,CAAC,KAAK,CAAC;QACjC,oBAAoB,EAAE,6BAA6B,CACjD,KAAK,CAAC,MAAM,EAAE,oBAAoB,CACnC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,KAAyB,EACzB,QAAoB;IAEpB,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9B,OAAO,GAAG,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import type { createDocument } from \"@tearleads/loro\";\nimport type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../data/documents/documentConstants\";\nimport {\n type DocumentAttachment,\n getDocumentAttachments,\n sameDocumentAttachments,\n} from \"../../../data/documents/documentContent\";\nimport {\n projectStoredDocumentState,\n readStoredDocumentState,\n type StoredDocumentKind,\n} from \"../../../data/documents/documentKinds\";\nimport {\n type DocumentRow,\n listDocumentRows,\n sameDocumentRows,\n} from \"../../../data/documents/documentRowList\";\nimport type { DocumentSummary } from \"../../../data/documents/documentSummary\";\nimport type { DocumentSyncPullContinuation } from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { SyncRemoteDocumentResult } from \"../../../data/documents/shared/types\";\nimport {\n canWriteEffectiveAccessLevel,\n normalizeEffectiveAccessLevel,\n} from \"../../../data/keying/accessLevel\";\nimport type { DomainScope } from \"../../../data/shared/domainScope\";\nimport {\n type AttachmentRemovalRows,\n type AttachmentStagingRows,\n createDocumentProjectionUserKeyResolver,\n type DocumentProjectionUserKeyResolver,\n type DocumentRecord,\n type DocumentSyncLane,\n type DocumentsPersistence,\n type PendingAttachmentRecord,\n type PendingUpdateInsert,\n resolveDocumentCreateAuthor,\n} from \"../../../workflows/documents\";\nimport type {\n DocumentSnapshot,\n DocumentStoreOpenOptions,\n DocumentsRuntime,\n} from \"../types\";\nimport {\n getAttachmentStatuses,\n getAttachmentStorageKeys,\n} from \"./attachments/attachmentSnapshot\";\nimport { sameValidationIssues, shallowEqualRecord } from \"./snapshotEquality\";\nexport type DocumentState = Awaited<ReturnType<typeof createDocument>>;\nexport type EncapsulationKeyPair = NonNullable<\n DocumentsRuntime[\"crypto\"][\"encapsulationKeyPair\"]\n>;\nexport type DocumentAttachmentBinding = NonNullable<\n Awaited<ReturnType<DocumentsRuntime[\"apiClient\"][\"listDocumentAttachments\"]>>\n>[number];\nexport type PendingMutationSyncResult = {\n completed: boolean;\n nextRecord: DocumentRecord;\n};\nexport interface PersistedDocumentRecord {\n creationSuperseded?: true;\n historyRestoreState?:\n | Awaited<ReturnType<DocumentsPersistence[\"loadHistoryRestoreState\"]>>\n | undefined;\n pullContinuationSuperseded?: true;\n record: DocumentRecord;\n syncIdentitySuperseded?: true;\n updatedAt?: string | undefined;\n}\nexport interface SaveDocumentRecordOptions {\n acceptedPendingUpdateIds?: readonly string[] | undefined;\n attachmentRemoval?: AttachmentRemovalRows | undefined;\n attachmentStaging?: AttachmentStagingRows | undefined;\n clearSyncFailure?: boolean | undefined;\n expectedSyncState?:\n | {\n pullContinuation: DocumentSyncPullContinuation | null;\n record: DocumentRecord;\n }\n | undefined;\n historyCheckpoint?:\n | {\n coveredTailIds: readonly string[];\n endVersionVector: string;\n pruneCoveredLocalState: boolean;\n snapshot: string;\n }\n | undefined;\n historyUpdateOrigin?: \"local\" | \"remote\" | undefined;\n historyUpdates?: readonly string[] | undefined;\n pendingUpdate?: Omit<PendingUpdateInsert, \"localId\"> | undefined;\n pendingBaseVersionOverride?: string | null | undefined;\n preserveSnapshotStructuredFields?: boolean | undefined;\n preserveSnapshotText?: boolean | undefined;\n stillCurrent?: (() => boolean) | undefined;\n}\nexport interface DocumentSyncAttempt {\n consumedPullContinuation: DocumentSyncPullContinuation | null;\n outgoingUpdateCount: number;\n requestRecord: DocumentRecord;\n synced: SyncRemoteDocumentResult;\n /** `writerProjectionGeneration` when the request left; gates the install. */\n writerProjectionGeneration: number;\n}\nexport interface DocumentStorePersistenceEffects {\n emitPersistedDocument: (\n domainScope: DomainScope,\n persistedDocument: DocumentSummary,\n placementChanged?: boolean | undefined,\n ) => void;\n registerDocumentIdentity: (\n domainScope: DomainScope,\n localId: string,\n documentId: string | null,\n ) => void;\n}\nexport interface DocumentStoreState {\n attachmentBlobIdBySlotId: Record<string, string | null>;\n /** Plaintext digest of the held bytes per slot; see `getAttachmentStatuses`. */\n attachmentContentSha256BySlotId: Record<string, string>;\n attachmentStorageKeyBySlotId: Record<string, string>;\n /** Creation's birth rides the first attach; see `deferredInitialUpdate.ts`. */\n deferInitialUpdate?: boolean;\n doc: DocumentState | null;\n effects: DocumentStorePersistenceEffects;\n initialDocumentId: string | null;\n /** Fields and rows a created record starts with; see `initialContent.ts`. */\n initialContent?: Pick<\n DocumentStoreOpenOptions,\n \"initialRows\" | \"initialStructuredFields\"\n >;\n initialDocumentKind: StoredDocumentKind;\n initialText: string;\n initializePromise: Promise<void> | null;\n initialized: boolean;\n lastEventCount: number;\n /** Invalidates queued local-write closures when this store is cleared. */\n localWriteGeneration: number;\n locallyAcceptedUpdateIds: Set<string>;\n localId: string;\n listeners: Set<() => void>;\n pendingAttachments: PendingAttachmentRecord[];\n /**\n * Oplog version through which every op in `doc` is already durably enqueued as\n * a pending update or synced from a remote peer. It advances only after an\n * edit's enqueue+persist succeeds, so a later edit can recover any orphaned\n * delta left by a failed write instead of silently dropping it from sync.\n * `null` only before initialization sets it to the loaded doc's version.\n */\n pendingBaseVersion: string | null;\n /**\n * Local text/structured writes queued on `writeChain` but not yet drained.\n * While positive, sync MUST preserve the optimistic text/fields because `doc`\n * can lag the latest keystroke. Remote merges remain in `doc` and publish when\n * the final write settles.\n */\n pendingLocalWrites: number;\n persistence: DocumentsPersistence;\n /**\n * Durable continuation for a bounded remote pull, mirrored from the document\n * record so the live lane can advance it without re-reading SQLite.\n */\n pullContinuation: DocumentSyncPullContinuation | null;\n record: DocumentRecord | null;\n /** Served bindings hydration refused for a held copy; see `hydrate.ts`. */\n rejectedServedAttachmentBindings: Set<string>;\n /**\n * Consecutive completed sync passes that re-keyed conflicted pending updates\n * without settling anything. Bounds the rekey-driven self re-arm so a server\n * that keeps conflicting fresh ids cannot drive a network-speed loop; see\n * shouldReArmAfterOutgoingSettlement.\n */\n rekeyOnlyPassCount: number;\n resolveProjectionUserKey: DocumentProjectionUserKeyResolver;\n /** Latest remote-update sequence durably applied by a completed probe. */\n remoteUpdateCompletedSignalSeq: number;\n /** A cancelled remote-only owner blocks late responses until fresh work. */\n remoteSyncBlocked: boolean;\n scheduleStartupRemoteSync: boolean;\n remoteUpdatePending: boolean;\n /** Sequence used to keep an older pass from clearing a newer remote event. */\n remoteUpdateSignalSeq: number;\n runtime: DocumentsRuntime;\n snapshot: DocumentSnapshot;\n syncLane: DocumentSyncLane | null;\n /** Parked behind another member's ancestor repair; a path hint re-runs. */\n awaitingAncestorRepair: boolean;\n writeChain: Promise<void>;\n writerProjection: DocumentWriterProjectionResponse | null;\n /**\n * Bumped whenever a realtime hint drops `writerProjection`; an operation that\n * fetched or was handed a projection installs it only if this is unchanged\n * since it started, so a pre-hint answer never lands after the hint.\n */\n writerProjectionGeneration: number;\n}\nconst EMPTY_DOCUMENT_SNAPSHOT: DocumentSnapshot = {\n attachments: [],\n attachmentStatusBySlotId: {},\n attachmentStorageKeyBySlotId: {},\n canAttach: false,\n canWrite: true,\n currentAuthorId: null,\n documentId: null,\n documentKind: DEFAULT_DOCUMENT_KIND,\n effectiveAccessLevel: \"admin\",\n fieldValidationIssues: [],\n ready: false,\n rows: [],\n structuredFields: {},\n text: \"\",\n title: \"\",\n syncing: false,\n};\n\nexport function createDocumentStoreState(\n localId: string,\n initialRuntime: DocumentsRuntime,\n persistence: DocumentsPersistence,\n effects: DocumentStorePersistenceEffects,\n initialDocumentId: string | null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n scheduleStartupRemoteSync = true,\n): DocumentStoreState {\n return {\n attachmentBlobIdBySlotId: {},\n attachmentContentSha256BySlotId: {},\n attachmentStorageKeyBySlotId: {},\n doc: null,\n effects,\n initialDocumentId,\n initialDocumentKind,\n initialText,\n initializePromise: null,\n initialized: false,\n lastEventCount: 0,\n localWriteGeneration: 0,\n locallyAcceptedUpdateIds: new Set(),\n localId,\n listeners: new Set(),\n pendingAttachments: [],\n pendingBaseVersion: null,\n pendingLocalWrites: 0,\n persistence,\n pullContinuation: null,\n record: null,\n rejectedServedAttachmentBindings: new Set(),\n rekeyOnlyPassCount: 0,\n resolveProjectionUserKey:\n createDocumentProjectionUserKeyResolver(initialRuntime),\n remoteUpdateCompletedSignalSeq: 0,\n remoteSyncBlocked: !scheduleStartupRemoteSync,\n scheduleStartupRemoteSync,\n awaitingAncestorRepair: false,\n remoteUpdatePending: false,\n remoteUpdateSignalSeq: 0,\n runtime: initialRuntime,\n snapshot: { ...EMPTY_DOCUMENT_SNAPSHOT },\n syncLane: null,\n writeChain: Promise.resolve(),\n writerProjection: null,\n writerProjectionGeneration: 0,\n };\n}\n\nfunction emitDocumentStore(state: DocumentStoreState) {\n for (const listener of state.listeners) {\n listener();\n }\n}\n\nexport function setDocumentSnapshot(\n state: DocumentStoreState,\n next: DocumentSnapshot,\n) {\n if (\n sameDocumentAttachments(state.snapshot.attachments, next.attachments) &&\n shallowEqualRecord(\n state.snapshot.attachmentStatusBySlotId,\n next.attachmentStatusBySlotId,\n ) &&\n shallowEqualRecord(\n state.snapshot.attachmentStorageKeyBySlotId,\n next.attachmentStorageKeyBySlotId,\n ) &&\n state.snapshot.canAttach === next.canAttach &&\n state.snapshot.canWrite === next.canWrite &&\n state.snapshot.currentAuthorId === next.currentAuthorId &&\n state.snapshot.documentId === next.documentId &&\n state.snapshot.documentKind === next.documentKind &&\n state.snapshot.effectiveAccessLevel === next.effectiveAccessLevel &&\n sameValidationIssues(\n state.snapshot.fieldValidationIssues,\n next.fieldValidationIssues,\n ) &&\n state.snapshot.ready === next.ready &&\n sameDocumentRows(state.snapshot.rows, next.rows) &&\n shallowEqualRecord(\n state.snapshot.structuredFields,\n next.structuredFields,\n ) &&\n state.snapshot.text === next.text &&\n state.snapshot.title === next.title &&\n state.snapshot.syncing === next.syncing\n ) {\n return;\n }\n\n state.snapshot = next;\n emitDocumentStore(state);\n}\n\nfunction clearDocumentStoreState(\n state: DocumentStoreState,\n { initialized }: { initialized: boolean },\n) {\n state.deferInitialUpdate = false;\n state.doc = null;\n state.localWriteGeneration += 1;\n state.record = null;\n state.pendingAttachments = [];\n state.pendingBaseVersion = null;\n state.pendingLocalWrites = 0;\n state.pullContinuation = null;\n state.attachmentBlobIdBySlotId = {};\n state.attachmentContentSha256BySlotId = {};\n state.attachmentStorageKeyBySlotId = {};\n state.locallyAcceptedUpdateIds = new Set();\n state.rejectedServedAttachmentBindings = new Set();\n state.remoteUpdateCompletedSignalSeq = 0;\n state.remoteSyncBlocked = !state.scheduleStartupRemoteSync;\n state.awaitingAncestorRepair = false;\n state.remoteUpdatePending = false;\n state.remoteUpdateSignalSeq = 0;\n state.writerProjection = null;\n state.initialized = initialized;\n state.initializePromise = null;\n state.writeChain = Promise.resolve();\n setDocumentSnapshot(state, { ...EMPTY_DOCUMENT_SNAPSHOT });\n}\n\nexport function resetDocumentStore(state: DocumentStoreState) {\n clearDocumentStoreState(state, { initialized: false });\n}\n\nexport function markDocumentStoreRemoved(state: DocumentStoreState) {\n clearDocumentStoreState(state, { initialized: true });\n}\n\nexport function canAttachFiles(state: DocumentStoreState): boolean {\n return (\n canWriteDocument(state) &&\n state.runtime.infra.dbStatus === \"ready\" &&\n !!state.runtime.crypto.encapsulationKeyPair\n );\n}\n\nexport function canWriteDocument(state: DocumentStoreState): boolean {\n return canWriteEffectiveAccessLevel(state.record?.effectiveAccessLevel);\n}\n\nfunction getSnapshotAttachments(\n state: DocumentStoreState,\n currentDoc: DocumentState | null = state.doc,\n): DocumentAttachment[] {\n return currentDoc ? getDocumentAttachments(currentDoc) : [];\n}\n\nfunction getSnapshotRows(\n state: DocumentStoreState,\n currentDoc: DocumentState | null = state.doc,\n): DocumentRow[] {\n return currentDoc ? listDocumentRows(currentDoc) : [];\n}\n\nfunction resolveCurrentAuthorId(state: DocumentStoreState): string | null {\n return resolveDocumentCreateAuthor(state.runtime)?.signerUserId ?? null;\n}\n\nexport function setReadySnapshot(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n syncing: boolean,\n textOverride?: string,\n structuredFieldsOverride?: DocumentSnapshot[\"structuredFields\"],\n) {\n const attachments = getSnapshotAttachments(state, currentDoc);\n const rows = getSnapshotRows(state, currentDoc);\n const documentState = readStoredDocumentState(\n currentDoc,\n state.runtime.infra.documentProjectors,\n );\n const text = textOverride ?? documentState.text;\n const structuredFields =\n structuredFieldsOverride ?? documentState.structuredFields;\n const projectedState =\n textOverride === undefined && structuredFieldsOverride === undefined\n ? documentState\n : projectStoredDocumentState(\n {\n documentKind: documentState.documentKind,\n structuredFields,\n text,\n rows: rows.map((row) => ({ id: row.id, fields: row.fields })),\n },\n state.runtime.infra.documentProjectors,\n );\n\n setDocumentSnapshot(state, {\n attachments,\n attachmentStatusBySlotId: getAttachmentStatuses({\n attachments,\n contentSha256BySlotId: state.attachmentContentSha256BySlotId,\n pendingSlotIds: new Set(\n state.pendingAttachments.map((attachment) => attachment.slotId),\n ),\n }),\n attachmentStorageKeyBySlotId: getAttachmentStorageKeys(\n state.attachmentStorageKeyBySlotId,\n attachments,\n ),\n canAttach: canAttachFiles(state),\n canWrite: canWriteDocument(state),\n currentAuthorId: resolveCurrentAuthorId(state),\n documentId: state.record?.documentId ?? null,\n documentKind: projectedState.documentKind,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n state.record?.effectiveAccessLevel,\n ),\n fieldValidationIssues: projectedState.fieldValidationIssues,\n ready: true,\n rows,\n structuredFields: projectedState.structuredFields,\n text,\n title: projectedState.title,\n syncing,\n });\n}\n\nexport function setDocumentSyncing(\n state: DocumentStoreState,\n syncing: boolean,\n) {\n setDocumentSnapshot(state, { ...state.snapshot, syncing });\n}\n\nexport function refreshAttachabilitySnapshot(state: DocumentStoreState) {\n if (!state.snapshot.ready) {\n return;\n }\n\n setDocumentSnapshot(state, {\n ...state.snapshot,\n canAttach: canAttachFiles(state),\n canWrite: canWriteDocument(state),\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n state.record?.effectiveAccessLevel,\n ),\n });\n}\n\nexport function subscribeToDocumentStore(\n state: DocumentStoreState,\n listener: () => void,\n) {\n state.listeners.add(listener);\n return () => void state.listeners.delete(listener);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { createDocument } from \"@tearleads/loro\";\nimport type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../data/documents/documentConstants\";\nimport {\n type DocumentAttachment,\n getDocumentAttachments,\n sameDocumentAttachments,\n} from \"../../../data/documents/documentContent\";\nimport {\n projectStoredDocumentState,\n readStoredDocumentState,\n type StoredDocumentKind,\n} from \"../../../data/documents/documentKinds\";\nimport {\n type DocumentRow,\n listDocumentRows,\n sameDocumentRows,\n} from \"../../../data/documents/documentRowList\";\nimport type { DocumentSummary } from \"../../../data/documents/documentSummary\";\nimport type { DocumentSyncPullContinuation } from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { SyncRemoteDocumentResult } from \"../../../data/documents/shared/types\";\nimport {\n canWriteEffectiveAccessLevel,\n normalizeEffectiveAccessLevel,\n} from \"../../../data/keying/accessLevel\";\nimport type { DomainScope } from \"../../../data/shared/domainScope\";\nimport {\n type AttachmentRemovalRows,\n type AttachmentStagingRows,\n createDocumentProjectionUserKeyResolver,\n type DocumentProjectionUserKeyResolver,\n type DocumentRecord,\n type DocumentSyncLane,\n type DocumentsPersistence,\n type PendingAttachmentRecord,\n type PendingUpdateInsert,\n resolveDocumentCreateAuthor,\n} from \"../../../workflows/documents\";\nimport type {\n DocumentSnapshot,\n DocumentStoreOpenOptions,\n DocumentsRuntime,\n} from \"../types\";\nimport {\n getAttachmentStatuses,\n getAttachmentStorageKeys,\n} from \"./attachments/attachmentSnapshot\";\nimport { sameValidationIssues, shallowEqualRecord } from \"./snapshotEquality\";\nexport type DocumentState = Awaited<ReturnType<typeof createDocument>>;\nexport type EncapsulationKeyPair = NonNullable<\n DocumentsRuntime[\"crypto\"][\"encapsulationKeyPair\"]\n>;\nexport type DocumentAttachmentBinding = NonNullable<\n Awaited<ReturnType<DocumentsRuntime[\"apiClient\"][\"listDocumentAttachments\"]>>\n>[number];\nexport type PendingMutationSyncResult = {\n completed: boolean;\n nextRecord: DocumentRecord;\n};\nexport interface PersistedDocumentRecord {\n creationSuperseded?: true;\n historyRestoreState?:\n | Awaited<ReturnType<DocumentsPersistence[\"loadHistoryRestoreState\"]>>\n | undefined;\n pullContinuationSuperseded?: true;\n record: DocumentRecord;\n syncIdentitySuperseded?: true;\n updatedAt?: string | undefined;\n}\nexport interface SaveDocumentRecordOptions {\n acceptedPendingUpdateIds?: readonly string[] | undefined;\n attachmentRemoval?: AttachmentRemovalRows | undefined;\n attachmentStaging?: AttachmentStagingRows | undefined;\n clearSyncFailure?: boolean | undefined;\n expectedSyncState?:\n | {\n pullContinuation: DocumentSyncPullContinuation | null;\n record: DocumentRecord;\n }\n | undefined;\n historyCheckpoint?:\n | {\n coveredTailIds: readonly string[];\n endVersionVector: string;\n pruneCoveredLocalState: boolean;\n snapshot: string;\n }\n | undefined;\n historyUpdateOrigin?: \"local\" | \"remote\" | undefined;\n historyUpdates?: readonly string[] | undefined;\n pendingUpdate?: Omit<PendingUpdateInsert, \"localId\"> | undefined;\n pendingBaseVersionOverride?: string | null | undefined;\n preserveSnapshotStructuredFields?: boolean | undefined;\n preserveSnapshotText?: boolean | undefined;\n stillCurrent?: (() => boolean) | undefined;\n}\nexport interface DocumentSyncAttempt {\n consumedPullContinuation: DocumentSyncPullContinuation | null;\n outgoingUpdateCount: number;\n requestRecord: DocumentRecord;\n synced: SyncRemoteDocumentResult;\n /** `writerProjectionGeneration` when the request left; gates the install. */\n writerProjectionGeneration: number;\n}\nexport interface DocumentStorePersistenceEffects {\n emitPersistedDocument: (\n domainScope: DomainScope,\n persistedDocument: DocumentSummary,\n placementChanged?: boolean | undefined,\n ) => void;\n registerDocumentIdentity: (\n domainScope: DomainScope,\n localId: string,\n documentId: string | null,\n ) => void;\n}\nexport interface DocumentStoreState {\n attachmentBlobIdBySlotId: Record<string, string | null>;\n /** Plaintext digest of the held bytes per slot; see `getAttachmentStatuses`. */\n attachmentContentSha256BySlotId: Record<string, string>;\n attachmentStorageKeyBySlotId: Record<string, string>;\n /** Creation's birth rides the first attach; see `deferredInitialUpdate.ts`. */\n deferInitialUpdate?: boolean;\n doc: DocumentState | null;\n effects: DocumentStorePersistenceEffects;\n initialDocumentId: string | null;\n /** Fields and rows a created record starts with; see `initialContent.ts`. */\n initialContent?: Pick<\n DocumentStoreOpenOptions,\n \"initialRows\" | \"initialStructuredFields\"\n >;\n initialDocumentKind: StoredDocumentKind;\n initialText: string;\n initializePromise: Promise<void> | null;\n initialized: boolean;\n lastEventCount: number;\n /** Invalidates queued local-write closures when this store is cleared. */\n localWriteGeneration: number;\n locallyAcceptedUpdateIds: Set<string>;\n localId: string;\n listeners: Set<() => void>;\n pendingAttachments: PendingAttachmentRecord[];\n /**\n * Oplog version through which every op in `doc` is already durably enqueued as\n * a pending update or synced from a remote peer. It advances only after an\n * edit's enqueue+persist succeeds, so a later edit can recover any orphaned\n * delta left by a failed write instead of silently dropping it from sync.\n * `null` only before initialization sets it to the loaded doc's version.\n */\n pendingBaseVersion: string | null;\n /**\n * Local text/structured writes queued on `writeChain` but not yet drained.\n * While positive, sync MUST preserve the optimistic text/fields because `doc`\n * can lag the latest keystroke. Remote merges remain in `doc` and publish when\n * the final write settles.\n */\n pendingLocalWrites: number;\n /** Local writes called or chained but unsettled; zero means all in SQLite. */\n queuedWrites: number;\n persistence: DocumentsPersistence;\n /**\n * Durable continuation for a bounded remote pull, mirrored from the document\n * record so the live lane can advance it without re-reading SQLite.\n */\n pullContinuation: DocumentSyncPullContinuation | null;\n record: DocumentRecord | null;\n /** Served bindings hydration refused for a held copy; see `hydrate.ts`. */\n rejectedServedAttachmentBindings: Set<string>;\n /**\n * Consecutive completed sync passes that re-keyed conflicted pending updates\n * without settling anything. Bounds the rekey-driven self re-arm so a server\n * that keeps conflicting fresh ids cannot drive a network-speed loop; see\n * shouldReArmAfterOutgoingSettlement.\n */\n rekeyOnlyPassCount: number;\n resolveProjectionUserKey: DocumentProjectionUserKeyResolver;\n /** Latest remote-update sequence durably applied by a completed probe. */\n remoteUpdateCompletedSignalSeq: number;\n /** A cancelled remote-only owner blocks late responses until fresh work. */\n remoteSyncBlocked: boolean;\n scheduleStartupRemoteSync: boolean;\n remoteUpdatePending: boolean;\n /** Sequence used to keep an older pass from clearing a newer remote event. */\n remoteUpdateSignalSeq: number;\n runtime: DocumentsRuntime;\n snapshot: DocumentSnapshot;\n syncLane: DocumentSyncLane | null;\n /** Parked behind another member's ancestor repair; a path hint re-runs. */\n awaitingAncestorRepair: boolean;\n writeChain: Promise<void>;\n writerProjection: DocumentWriterProjectionResponse | null;\n /**\n * Bumped whenever a realtime hint drops `writerProjection`; an operation that\n * fetched or was handed a projection installs it only if this is unchanged\n * since it started, so a pre-hint answer never lands after the hint.\n */\n writerProjectionGeneration: number;\n}\nconst EMPTY_DOCUMENT_SNAPSHOT: DocumentSnapshot = {\n attachments: [],\n attachmentStatusBySlotId: {},\n attachmentStorageKeyBySlotId: {},\n canAttach: false,\n canWrite: true,\n currentAuthorId: null,\n documentId: null,\n documentKind: DEFAULT_DOCUMENT_KIND,\n effectiveAccessLevel: \"admin\",\n fieldValidationIssues: [],\n ready: false,\n rows: [],\n structuredFields: {},\n text: \"\",\n title: \"\",\n syncing: false,\n};\n\nexport function createDocumentStoreState(\n localId: string,\n initialRuntime: DocumentsRuntime,\n persistence: DocumentsPersistence,\n effects: DocumentStorePersistenceEffects,\n initialDocumentId: string | null,\n initialText = \"\",\n initialDocumentKind: StoredDocumentKind = DEFAULT_DOCUMENT_KIND,\n scheduleStartupRemoteSync = true,\n): DocumentStoreState {\n return {\n attachmentBlobIdBySlotId: {},\n attachmentContentSha256BySlotId: {},\n attachmentStorageKeyBySlotId: {},\n doc: null,\n effects,\n initialDocumentId,\n initialDocumentKind,\n initialText,\n initializePromise: null,\n initialized: false,\n lastEventCount: 0,\n localWriteGeneration: 0,\n locallyAcceptedUpdateIds: new Set(),\n localId,\n listeners: new Set(),\n pendingAttachments: [],\n pendingBaseVersion: null,\n pendingLocalWrites: 0,\n persistence,\n queuedWrites: 0,\n pullContinuation: null,\n record: null,\n rejectedServedAttachmentBindings: new Set(),\n rekeyOnlyPassCount: 0,\n resolveProjectionUserKey:\n createDocumentProjectionUserKeyResolver(initialRuntime),\n remoteUpdateCompletedSignalSeq: 0,\n remoteSyncBlocked: !scheduleStartupRemoteSync,\n scheduleStartupRemoteSync,\n awaitingAncestorRepair: false,\n remoteUpdatePending: false,\n remoteUpdateSignalSeq: 0,\n runtime: initialRuntime,\n snapshot: { ...EMPTY_DOCUMENT_SNAPSHOT },\n syncLane: null,\n writeChain: Promise.resolve(),\n writerProjection: null,\n writerProjectionGeneration: 0,\n };\n}\n\nfunction emitDocumentStore(state: DocumentStoreState) {\n for (const listener of state.listeners) {\n listener();\n }\n}\n\nexport function setDocumentSnapshot(\n state: DocumentStoreState,\n next: DocumentSnapshot,\n) {\n if (\n sameDocumentAttachments(state.snapshot.attachments, next.attachments) &&\n shallowEqualRecord(\n state.snapshot.attachmentStatusBySlotId,\n next.attachmentStatusBySlotId,\n ) &&\n shallowEqualRecord(\n state.snapshot.attachmentStorageKeyBySlotId,\n next.attachmentStorageKeyBySlotId,\n ) &&\n state.snapshot.canAttach === next.canAttach &&\n state.snapshot.canWrite === next.canWrite &&\n state.snapshot.currentAuthorId === next.currentAuthorId &&\n state.snapshot.documentId === next.documentId &&\n state.snapshot.documentKind === next.documentKind &&\n state.snapshot.effectiveAccessLevel === next.effectiveAccessLevel &&\n sameValidationIssues(\n state.snapshot.fieldValidationIssues,\n next.fieldValidationIssues,\n ) &&\n state.snapshot.ready === next.ready &&\n sameDocumentRows(state.snapshot.rows, next.rows) &&\n shallowEqualRecord(\n state.snapshot.structuredFields,\n next.structuredFields,\n ) &&\n state.snapshot.text === next.text &&\n state.snapshot.title === next.title &&\n state.snapshot.syncing === next.syncing\n ) {\n return;\n }\n\n state.snapshot = next;\n emitDocumentStore(state);\n}\n\nfunction clearDocumentStoreState(\n state: DocumentStoreState,\n { initialized }: { initialized: boolean },\n) {\n state.deferInitialUpdate = false;\n state.doc = null;\n state.localWriteGeneration += 1;\n state.record = null;\n state.pendingAttachments = [];\n state.pendingBaseVersion = null;\n state.pendingLocalWrites = 0;\n state.pullContinuation = null;\n state.attachmentBlobIdBySlotId = {};\n state.attachmentContentSha256BySlotId = {};\n state.attachmentStorageKeyBySlotId = {};\n state.locallyAcceptedUpdateIds = new Set();\n state.rejectedServedAttachmentBindings = new Set();\n state.remoteUpdateCompletedSignalSeq = 0;\n state.remoteSyncBlocked = !state.scheduleStartupRemoteSync;\n state.awaitingAncestorRepair = false;\n state.remoteUpdatePending = false;\n state.remoteUpdateSignalSeq = 0;\n state.writerProjection = null;\n state.initialized = initialized;\n state.initializePromise = null;\n state.writeChain = Promise.resolve();\n setDocumentSnapshot(state, { ...EMPTY_DOCUMENT_SNAPSHOT });\n}\n\nexport function resetDocumentStore(state: DocumentStoreState) {\n clearDocumentStoreState(state, { initialized: false });\n}\n\nexport function markDocumentStoreRemoved(state: DocumentStoreState) {\n clearDocumentStoreState(state, { initialized: true });\n}\n\nexport function canAttachFiles(state: DocumentStoreState): boolean {\n return (\n canWriteDocument(state) &&\n state.runtime.infra.dbStatus === \"ready\" &&\n !!state.runtime.crypto.encapsulationKeyPair\n );\n}\n\nexport function canWriteDocument(state: DocumentStoreState): boolean {\n return canWriteEffectiveAccessLevel(state.record?.effectiveAccessLevel);\n}\n\nfunction getSnapshotAttachments(\n state: DocumentStoreState,\n currentDoc: DocumentState | null = state.doc,\n): DocumentAttachment[] {\n return currentDoc ? getDocumentAttachments(currentDoc) : [];\n}\n\nfunction getSnapshotRows(\n state: DocumentStoreState,\n currentDoc: DocumentState | null = state.doc,\n): DocumentRow[] {\n return currentDoc ? listDocumentRows(currentDoc) : [];\n}\n\nfunction resolveCurrentAuthorId(state: DocumentStoreState): string | null {\n return resolveDocumentCreateAuthor(state.runtime)?.signerUserId ?? null;\n}\n\nexport function setReadySnapshot(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n syncing: boolean,\n textOverride?: string,\n structuredFieldsOverride?: DocumentSnapshot[\"structuredFields\"],\n) {\n const attachments = getSnapshotAttachments(state, currentDoc);\n const rows = getSnapshotRows(state, currentDoc);\n const documentState = readStoredDocumentState(\n currentDoc,\n state.runtime.infra.documentProjectors,\n );\n const text = textOverride ?? documentState.text;\n const structuredFields =\n structuredFieldsOverride ?? documentState.structuredFields;\n const projectedState =\n textOverride === undefined && structuredFieldsOverride === undefined\n ? documentState\n : projectStoredDocumentState(\n {\n documentKind: documentState.documentKind,\n structuredFields,\n text,\n rows: rows.map((row) => ({ id: row.id, fields: row.fields })),\n },\n state.runtime.infra.documentProjectors,\n );\n\n setDocumentSnapshot(state, {\n attachments,\n attachmentStatusBySlotId: getAttachmentStatuses({\n attachments,\n contentSha256BySlotId: state.attachmentContentSha256BySlotId,\n pendingSlotIds: new Set(\n state.pendingAttachments.map((attachment) => attachment.slotId),\n ),\n }),\n attachmentStorageKeyBySlotId: getAttachmentStorageKeys(\n state.attachmentStorageKeyBySlotId,\n attachments,\n ),\n canAttach: canAttachFiles(state),\n canWrite: canWriteDocument(state),\n currentAuthorId: resolveCurrentAuthorId(state),\n documentId: state.record?.documentId ?? null,\n documentKind: projectedState.documentKind,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n state.record?.effectiveAccessLevel,\n ),\n fieldValidationIssues: projectedState.fieldValidationIssues,\n ready: true,\n rows,\n structuredFields: projectedState.structuredFields,\n text,\n title: projectedState.title,\n syncing,\n });\n}\n\nexport function setDocumentSyncing(\n state: DocumentStoreState,\n syncing: boolean,\n) {\n setDocumentSnapshot(state, { ...state.snapshot, syncing });\n}\n\nexport function refreshAttachabilitySnapshot(state: DocumentStoreState) {\n if (!state.snapshot.ready) {\n return;\n }\n\n setDocumentSnapshot(state, {\n ...state.snapshot,\n canAttach: canAttachFiles(state),\n canWrite: canWriteDocument(state),\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n state.record?.effectiveAccessLevel,\n ),\n });\n}\n\nexport function subscribeToDocumentStore(\n state: DocumentStoreState,\n listener: () => void,\n) {\n state.listeners.add(listener);\n return () => void state.listeners.delete(listener);\n}\n\n/**\n * Counts `write` in `queuedWrites` until it settles. Counted synchronously, so\n * a write started while a removal runs is visible to its commit guard.\n */\nexport function countQueuedWrite<T>(\n state: DocumentStoreState,\n write: Promise<T>,\n): Promise<T> {\n state.queuedWrites += 1;\n const settle = () => {\n state.queuedWrites -= 1;\n };\n void write.then(settle, settle);\n return write;\n}\n\n/** Installs `link` as the store's write chain, counted until it settles. */\nexport function chainQueuedWrite(\n state: DocumentStoreState,\n link: Promise<void>,\n): Promise<void> {\n state.writeChain = countQueuedWrite(state, link);\n return state.writeChain;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { reportAndRethrowKeyingVerificationError } from "../../../../data/keyingProjectionVerification/error.js";
|
|
2
2
|
import { isDatabaseUnavailableError, registerDocumentSyncLane, resolveDocumentCreateAuthor, } from "../../../../workflows/documents/index.js";
|
|
3
|
-
import { requestDocumentStoreSync } from "../../registry.js";
|
|
3
|
+
import { onDocumentStoreRetired, requestDocumentStoreSync, } from "../../registry.js";
|
|
4
4
|
import { awaitInitializationForSync } from "../initialization/index.js";
|
|
5
5
|
import { listPendingUpdates } from "../persistence.js";
|
|
6
6
|
import { setDocumentSyncing, } from "../state.js";
|
|
@@ -10,7 +10,7 @@ import { cleanupPreRegisteredUpdateIdsOnFailure, discardPreRegisteredUpdateIds,
|
|
|
10
10
|
import { syncPendingAttachments } from "./syncAttachments.js";
|
|
11
11
|
import { syncDetachedAttachmentBindings } from "./syncDetachedAttachments.js";
|
|
12
12
|
import { finalizeDocumentSync } from "./syncFinalize.js";
|
|
13
|
-
import { captureDocumentStoreAttachmentSyncGeneration, captureDocumentStoreRemoteSyncGeneration, captureDocumentStoreSyncGeneration, isDocumentStoreRemoteSyncBlocked, isDocumentStoreSyncGenerationCurrent, isDocumentStoreSyncLaneGenerationCurrent, } from "./syncGeneration.js";
|
|
13
|
+
import { captureDocumentStoreAttachmentSyncGeneration, captureDocumentStoreRemoteSyncGeneration, captureDocumentStoreSyncGeneration, invalidateDocumentStoreSyncLane, isDocumentStoreRemoteSyncBlocked, isDocumentStoreSyncGenerationCurrent, isDocumentStoreSyncLaneGenerationCurrent, } from "./syncGeneration.js";
|
|
14
14
|
import { prepareDocumentOutgoingCoverage } from "./syncOutgoingCoverage.js";
|
|
15
15
|
import { requestRemoteDocumentSync } from "./syncRequest.js";
|
|
16
16
|
import { ensureSeededRemoteDocument } from "./syncSeededCreate.js";
|
|
@@ -272,6 +272,9 @@ async function runScheduledSyncLoop(state, syncLaneGeneration) {
|
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
export function registerDocumentStoreSyncLane(state, getSyncLaneGeneration) {
|
|
275
|
+
// Retiring the store (its document removed under it) ends this lane's
|
|
276
|
+
// current and in-flight work; a replacement store registers its own.
|
|
277
|
+
onDocumentStoreRetired(state.runtime.state.domainScope, state.localId, () => invalidateDocumentStoreSyncLane(state));
|
|
275
278
|
return registerDocumentSyncLane({
|
|
276
279
|
domainScope: state.runtime.state.domainScope,
|
|
277
280
|
localId: state.localId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { reportAndRethrowKeyingVerificationError } from \"../../../../data/keyingProjectionVerification/error\";\nimport {\n type DocumentRecord,\n type DocumentSyncLane,\n isDatabaseUnavailableError,\n type PendingUpdateRecord,\n registerDocumentSyncLane,\n resolveDocumentCreateAuthor,\n} from \"../../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { awaitInitializationForSync } from \"../initialization\";\nimport { listPendingUpdates } from \"../persistence\";\nimport {\n type DocumentState,\n type DocumentStoreState,\n type DocumentSyncAttempt,\n type EncapsulationKeyPair,\n setDocumentSyncing,\n} from \"../state\";\nimport { logRevalidationUnavailable as logUnavailable } from \"./remoteRevalidationTelemetry\";\nimport {\n getActiveDocumentRemoteWork,\n runDocumentRemoteWork,\n} from \"./remoteWork\";\nimport {\n cleanupPreRegisteredUpdateIdsOnFailure,\n discardPreRegisteredUpdateIds,\n preRegisterMaterializedDocumentSyncUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport { syncPendingAttachments } from \"./syncAttachments\";\nimport { syncDetachedAttachmentBindings } from \"./syncDetachedAttachments\";\nimport { finalizeDocumentSync } from \"./syncFinalize\";\nimport {\n captureDocumentStoreAttachmentSyncGeneration,\n captureDocumentStoreRemoteSyncGeneration,\n captureDocumentStoreSyncGeneration,\n type DocumentStoreSyncGeneration,\n type DocumentStoreSyncLaneGeneration,\n isDocumentStoreRemoteSyncBlocked,\n isDocumentStoreSyncGenerationCurrent,\n isDocumentStoreSyncLaneGenerationCurrent,\n} from \"./syncGeneration\";\nimport { prepareDocumentOutgoingCoverage } from \"./syncOutgoingCoverage\";\nimport { requestRemoteDocumentSync } from \"./syncRequest\";\nimport { ensureSeededRemoteDocument } from \"./syncSeededCreate\";\nimport {\n isContainerAwaitingRemoteCreate,\n shouldSkipCleanScheduledDocumentSync,\n} from \"./syncShared\";\n\nfunction canRunScheduledSync(state: DocumentStoreState): boolean {\n return (\n // A deferred birth waits for its attach to carry it (see\n // deferredInitialUpdate.ts); a pass now would ship it on its own.\n state.deferInitialUpdate !== true &&\n state.doc !== null &&\n state.snapshot.ready &&\n state.runtime.state.online &&\n state.runtime.auth.isAuthenticated &&\n state.runtime.crypto.encapsulationKeyPair !== null &&\n resolveDocumentCreateAuthor(state.runtime) !== null\n );\n}\n\nasync function requestOutgoingDocumentBatch(input: {\n readonly currentDoc: DocumentState;\n readonly encapsulationKeyPair: EncapsulationKeyPair;\n readonly generation: DocumentStoreSyncGeneration;\n readonly pendingUpdates: PendingUpdateRecord[];\n readonly record: DocumentRecord;\n readonly state: DocumentStoreState;\n}): Promise<{\n sentUpdateIds: string[];\n syncAttempt: DocumentSyncAttempt | null;\n}> {\n const { planningUpdates, queuedUpdateCount } = prepareDocumentStoreSyncQueue(\n input.pendingUpdates,\n );\n const sentUpdateIds: string[] = [];\n const syncAttempt = await cleanupPreRegisteredUpdateIdsOnFailure(\n input.state,\n sentUpdateIds,\n () =>\n requestRemoteDocumentSync({\n currentDoc: input.currentDoc,\n currentRecord: input.record,\n encapsulationKeyPair: input.encapsulationKeyPair,\n generation: input.generation,\n onOutgoingUpdatesMaterialized: (updateIds) =>\n preRegisterMaterializedDocumentSyncUpdateIds(\n input.state,\n sentUpdateIds,\n updateIds,\n ),\n pendingUpdates: planningUpdates,\n queuedUpdateCount,\n state: input.state,\n unavailableWriterLogMessage:\n \"Documents: skipped sync because the writer context is unavailable.\",\n }),\n );\n return { sentUpdateIds, syncAttempt };\n}\n\n/**\n * Keep the full durable queue visible to stale-heal/checkpoint classification.\n * The workflow planner owns the final count and byte bounds, and the exact\n * materialized batch is pre-registered immediately before each submit.\n */\nexport function prepareDocumentStoreSyncQueue(\n pendingUpdates: PendingUpdateRecord[],\n): {\n planningUpdates: PendingUpdateRecord[];\n queuedUpdateCount: number;\n} {\n return {\n planningUpdates: pendingUpdates,\n queuedUpdateCount: pendingUpdates.length,\n };\n}\n\nexport function canSyncDetachedAttachmentBindings(\n record: DocumentRecord,\n pendingUpdateCount: number,\n): boolean {\n return (\n pendingUpdateCount === 0 &&\n (record.pullContinuation ?? null) === null &&\n !record.pullContinuationRecoveryRequired\n );\n}\n\nasync function syncDocumentState(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<DocumentRecord> {\n // Snapshot the remote-update signal sequence before any await. The GET below\n // fetches server state as of its own snapshot; any remote event delivered\n // after this point describes an update that may not be in that response, so\n // finalizeDocumentSync must not clear the signal if this sequence has moved.\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n let pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (pendingUpdates.length === 0 && isDocumentStoreRemoteSyncBlocked(state)) {\n return nextRecord;\n }\n // Create the remote document even when nothing is queued to send: a note\n // created and never edited enqueues no updates, but its local row is still a\n // pending create the write queue reports — it must flush, not sit. Defer\n // while the container itself still awaits its remote create — with OR\n // without queued edits, since the create cannot succeed before its parent\n // exists and attempting it just records a spurious failure. The structural\n // lane primes this store again as soon as the container create lands.\n if (!nextRecord.documentId) {\n const containerAwaitsCreate = await isContainerAwaitingRemoteCreate(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (containerAwaitsCreate) return nextRecord;\n }\n const created = await ensureSeededRemoteDocument({\n consumedRemoteUpdateSignalSeq,\n currentDoc,\n encapsulationKeyPair,\n generation,\n nextRecord,\n pendingUpdates,\n state,\n });\n let nextRemoteRecord = created.record;\n pendingUpdates = created.pendingUpdates;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (!nextRemoteRecord?.documentId) return nextRecord;\n\n const preparedCoverage = await prepareDocumentOutgoingCoverage({\n currentDoc,\n generation,\n pendingUpdates,\n state,\n });\n if (!preparedCoverage) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n nextRemoteRecord = preparedCoverage.record;\n pendingUpdates = preparedCoverage.pendingUpdates;\n\n if (\n shouldSkipCleanScheduledDocumentSync({\n currentRecord: nextRemoteRecord,\n pendingUpdates,\n state,\n })\n ) {\n return nextRemoteRecord;\n }\n\n // Pre-register the IDs we are about to send so the author's OWN\n // `document_update_created` echo (fanned back over realtime) is classified as\n // self-authored and never re-arms a redundant sync. Registering BEFORE the\n // network await closes the race where the echo lands before\n // finalizeDocumentSync records the accepted IDs — the gap that turned every\n // fast keystroke into an extra self-triggered sync.\n const { sentUpdateIds, syncAttempt } = await requestOutgoingDocumentBatch({\n currentDoc,\n encapsulationKeyPair,\n generation,\n pendingUpdates,\n record: nextRemoteRecord,\n state,\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n if (!syncAttempt) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n logUnavailable(state, wasRemoteProbe);\n return nextRemoteRecord;\n }\n\n return cleanupPreRegisteredUpdateIdsOnFailure(state, sentUpdateIds, () =>\n finalizeDocumentSync(\n state,\n currentDoc,\n nextRemoteRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n sentUpdateIds,\n wasRemoteProbe,\n ),\n );\n}\n\nasync function revalidateRemoteDocumentBeforeAttachments(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<{ canSyncAttachments: boolean; nextRecord: DocumentRecord }> {\n if (state.pendingAttachments.length === 0 || !nextRecord.documentId) {\n return { canSyncAttachments: true, nextRecord };\n }\n\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n const syncAttempt = await requestRemoteDocumentSync({\n state,\n currentDoc,\n currentRecord: nextRecord,\n encapsulationKeyPair,\n generation,\n pendingUpdates: [],\n unavailableWriterLogMessage:\n \"Documents: skipped pre-attachment revalidation because the writer context is unavailable.\",\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return { canSyncAttachments: false, nextRecord };\n }\n if (!syncAttempt) {\n logUnavailable(state, wasRemoteProbe);\n return { canSyncAttachments: false, nextRecord };\n }\n\n const refreshedRecord = await finalizeDocumentSync(\n state,\n currentDoc,\n nextRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n [],\n wasRemoteProbe,\n );\n return {\n canSyncAttachments:\n !syncAttempt.synced.hasIncompletePull &&\n refreshedRecord.pullContinuation == null &&\n refreshedRecord.pullContinuationRecoveryRequired !== true &&\n isDocumentStoreSyncGenerationCurrent(state, generation),\n nextRecord: refreshedRecord,\n };\n}\n\nasync function runDocumentSyncPass(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const currentDoc = state.doc;\n const encapsulationKeyPair = state.runtime.crypto.encapsulationKeyPair;\n let nextRecord = state.record;\n\n if (!currentDoc || !nextRecord || !encapsulationKeyPair) {\n return;\n }\n\n const generation = captureDocumentStoreRemoteSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n const attachmentGeneration = captureDocumentStoreAttachmentSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n if (!generation || !attachmentGeneration) {\n requestDocumentStoreSync(state);\n return;\n }\n\n const revalidation = await revalidateRemoteDocumentBeforeAttachments(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n nextRecord = revalidation.nextRecord;\n if (!revalidation.canSyncAttachments) {\n return;\n }\n\n const attachmentResult = await syncPendingAttachments(\n state,\n nextRecord,\n encapsulationKeyPair,\n attachmentGeneration,\n );\n nextRecord = attachmentResult.nextRecord;\n if (state.pendingAttachments.length > 0) {\n return;\n }\n // A settled bind and the content update carrying its digest are two server\n // writes. Push the content in this same pass rather than re-arming a later\n // one, so a device lost between them is the only remaining window: peers\n // otherwise see the old digest against the new binding.\n\n nextRecord = await syncDocumentState(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n\n if (!state.doc || !state.record) return;\n\n const pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n if (!canSyncDetachedAttachmentBindings(nextRecord, pendingUpdates.length)) {\n return;\n }\n\n await syncDetachedAttachmentBindings(state, nextRecord, generation);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n }\n}\n\nasync function runScheduledSyncIteration(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n if (!(await awaitInitializationForSync(state))) {\n return false;\n }\n if (!isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)) {\n return true;\n }\n\n if (!canRunScheduledSync(state)) {\n return true;\n }\n\n try {\n await runDocumentSyncPass(state, syncLaneGeneration);\n return true;\n } catch (error) {\n if (isDatabaseUnavailableError(error)) {\n return false;\n }\n\n await reportAndRethrowKeyingVerificationError(\n error,\n state.runtime.util.reportSecurityIncident,\n {\n objectId: state.record?.documentId ?? state.localId,\n objectKind: \"document\",\n operation: \"document.sync\",\n },\n );\n\n throw error;\n }\n}\n\nasync function runScheduledSyncLoop(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const syncingGeneration = captureDocumentStoreSyncGeneration(\n state,\n state.doc,\n );\n setDocumentSyncing(state, true);\n\n try {\n await runScheduledSyncIteration(state, syncLaneGeneration);\n } finally {\n if (\n syncingGeneration &&\n isDocumentStoreSyncGenerationCurrent(state, syncingGeneration) &&\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n setDocumentSyncing(state, false);\n }\n }\n}\n\nexport function registerDocumentStoreSyncLane(\n state: DocumentStoreState,\n getSyncLaneGeneration: () => DocumentStoreSyncLaneGeneration | null,\n): DocumentSyncLane {\n return registerDocumentSyncLane({\n domainScope: state.runtime.state.domainScope,\n localId: state.localId,\n priority: () =>\n state.remoteUpdatePending || state.record?.snapshotEndVersion === \"\"\n ? -1\n : 0,\n logError: (message, error) => {\n // Read the runtime lazily: a store's runtime is replaced in place, and a\n // reference captured here would report into a torn-down host.\n const { log, logError } = state.runtime.util;\n // Return the host's result: both callbacks are declared `=> void` but may\n // be async, and the lane reporter only catches a rejection it is handed.\n return logError ? logError(message, error) : log(message);\n },\n run: () => {\n const syncLaneGeneration = getSyncLaneGeneration();\n if (!syncLaneGeneration) return Promise.resolve();\n const activeWork = getActiveDocumentRemoteWork(state);\n if (activeWork) {\n // Re-arm on settlement, not immediately: immediate re-requests would\n // spin this lane and starve other work while the HTTP request is held.\n void activeWork.then(() => {\n if (\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n requestDocumentStoreSync(state);\n }\n });\n return Promise.resolve();\n }\n return runDocumentRemoteWork(state, () =>\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ? runScheduledSyncLoop(state, syncLaneGeneration)\n : Promise.resolve(),\n );\n },\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { reportAndRethrowKeyingVerificationError } from \"../../../../data/keyingProjectionVerification/error\";\nimport {\n type DocumentRecord,\n type DocumentSyncLane,\n isDatabaseUnavailableError,\n type PendingUpdateRecord,\n registerDocumentSyncLane,\n resolveDocumentCreateAuthor,\n} from \"../../../../workflows/documents\";\nimport {\n onDocumentStoreRetired,\n requestDocumentStoreSync,\n} from \"../../registry\";\nimport { awaitInitializationForSync } from \"../initialization\";\nimport { listPendingUpdates } from \"../persistence\";\nimport {\n type DocumentState,\n type DocumentStoreState,\n type DocumentSyncAttempt,\n type EncapsulationKeyPair,\n setDocumentSyncing,\n} from \"../state\";\nimport { logRevalidationUnavailable as logUnavailable } from \"./remoteRevalidationTelemetry\";\nimport {\n getActiveDocumentRemoteWork,\n runDocumentRemoteWork,\n} from \"./remoteWork\";\nimport {\n cleanupPreRegisteredUpdateIdsOnFailure,\n discardPreRegisteredUpdateIds,\n preRegisterMaterializedDocumentSyncUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport { syncPendingAttachments } from \"./syncAttachments\";\nimport { syncDetachedAttachmentBindings } from \"./syncDetachedAttachments\";\nimport { finalizeDocumentSync } from \"./syncFinalize\";\nimport {\n captureDocumentStoreAttachmentSyncGeneration,\n captureDocumentStoreRemoteSyncGeneration,\n captureDocumentStoreSyncGeneration,\n type DocumentStoreSyncGeneration,\n type DocumentStoreSyncLaneGeneration,\n invalidateDocumentStoreSyncLane,\n isDocumentStoreRemoteSyncBlocked,\n isDocumentStoreSyncGenerationCurrent,\n isDocumentStoreSyncLaneGenerationCurrent,\n} from \"./syncGeneration\";\nimport { prepareDocumentOutgoingCoverage } from \"./syncOutgoingCoverage\";\nimport { requestRemoteDocumentSync } from \"./syncRequest\";\nimport { ensureSeededRemoteDocument } from \"./syncSeededCreate\";\nimport {\n isContainerAwaitingRemoteCreate,\n shouldSkipCleanScheduledDocumentSync,\n} from \"./syncShared\";\n\nfunction canRunScheduledSync(state: DocumentStoreState): boolean {\n return (\n // A deferred birth waits for its attach to carry it (see\n // deferredInitialUpdate.ts); a pass now would ship it on its own.\n state.deferInitialUpdate !== true &&\n state.doc !== null &&\n state.snapshot.ready &&\n state.runtime.state.online &&\n state.runtime.auth.isAuthenticated &&\n state.runtime.crypto.encapsulationKeyPair !== null &&\n resolveDocumentCreateAuthor(state.runtime) !== null\n );\n}\n\nasync function requestOutgoingDocumentBatch(input: {\n readonly currentDoc: DocumentState;\n readonly encapsulationKeyPair: EncapsulationKeyPair;\n readonly generation: DocumentStoreSyncGeneration;\n readonly pendingUpdates: PendingUpdateRecord[];\n readonly record: DocumentRecord;\n readonly state: DocumentStoreState;\n}): Promise<{\n sentUpdateIds: string[];\n syncAttempt: DocumentSyncAttempt | null;\n}> {\n const { planningUpdates, queuedUpdateCount } = prepareDocumentStoreSyncQueue(\n input.pendingUpdates,\n );\n const sentUpdateIds: string[] = [];\n const syncAttempt = await cleanupPreRegisteredUpdateIdsOnFailure(\n input.state,\n sentUpdateIds,\n () =>\n requestRemoteDocumentSync({\n currentDoc: input.currentDoc,\n currentRecord: input.record,\n encapsulationKeyPair: input.encapsulationKeyPair,\n generation: input.generation,\n onOutgoingUpdatesMaterialized: (updateIds) =>\n preRegisterMaterializedDocumentSyncUpdateIds(\n input.state,\n sentUpdateIds,\n updateIds,\n ),\n pendingUpdates: planningUpdates,\n queuedUpdateCount,\n state: input.state,\n unavailableWriterLogMessage:\n \"Documents: skipped sync because the writer context is unavailable.\",\n }),\n );\n return { sentUpdateIds, syncAttempt };\n}\n\n/**\n * Keep the full durable queue visible to stale-heal/checkpoint classification.\n * The workflow planner owns the final count and byte bounds, and the exact\n * materialized batch is pre-registered immediately before each submit.\n */\nexport function prepareDocumentStoreSyncQueue(\n pendingUpdates: PendingUpdateRecord[],\n): {\n planningUpdates: PendingUpdateRecord[];\n queuedUpdateCount: number;\n} {\n return {\n planningUpdates: pendingUpdates,\n queuedUpdateCount: pendingUpdates.length,\n };\n}\n\nexport function canSyncDetachedAttachmentBindings(\n record: DocumentRecord,\n pendingUpdateCount: number,\n): boolean {\n return (\n pendingUpdateCount === 0 &&\n (record.pullContinuation ?? null) === null &&\n !record.pullContinuationRecoveryRequired\n );\n}\n\nasync function syncDocumentState(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<DocumentRecord> {\n // Snapshot the remote-update signal sequence before any await. The GET below\n // fetches server state as of its own snapshot; any remote event delivered\n // after this point describes an update that may not be in that response, so\n // finalizeDocumentSync must not clear the signal if this sequence has moved.\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n let pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (pendingUpdates.length === 0 && isDocumentStoreRemoteSyncBlocked(state)) {\n return nextRecord;\n }\n // Create the remote document even when nothing is queued to send: a note\n // created and never edited enqueues no updates, but its local row is still a\n // pending create the write queue reports — it must flush, not sit. Defer\n // while the container itself still awaits its remote create — with OR\n // without queued edits, since the create cannot succeed before its parent\n // exists and attempting it just records a spurious failure. The structural\n // lane primes this store again as soon as the container create lands.\n if (!nextRecord.documentId) {\n const containerAwaitsCreate = await isContainerAwaitingRemoteCreate(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (containerAwaitsCreate) return nextRecord;\n }\n const created = await ensureSeededRemoteDocument({\n consumedRemoteUpdateSignalSeq,\n currentDoc,\n encapsulationKeyPair,\n generation,\n nextRecord,\n pendingUpdates,\n state,\n });\n let nextRemoteRecord = created.record;\n pendingUpdates = created.pendingUpdates;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (!nextRemoteRecord?.documentId) return nextRecord;\n\n const preparedCoverage = await prepareDocumentOutgoingCoverage({\n currentDoc,\n generation,\n pendingUpdates,\n state,\n });\n if (!preparedCoverage) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n nextRemoteRecord = preparedCoverage.record;\n pendingUpdates = preparedCoverage.pendingUpdates;\n\n if (\n shouldSkipCleanScheduledDocumentSync({\n currentRecord: nextRemoteRecord,\n pendingUpdates,\n state,\n })\n ) {\n return nextRemoteRecord;\n }\n\n // Pre-register the IDs we are about to send so the author's OWN\n // `document_update_created` echo (fanned back over realtime) is classified as\n // self-authored and never re-arms a redundant sync. Registering BEFORE the\n // network await closes the race where the echo lands before\n // finalizeDocumentSync records the accepted IDs — the gap that turned every\n // fast keystroke into an extra self-triggered sync.\n const { sentUpdateIds, syncAttempt } = await requestOutgoingDocumentBatch({\n currentDoc,\n encapsulationKeyPair,\n generation,\n pendingUpdates,\n record: nextRemoteRecord,\n state,\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n if (!syncAttempt) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n logUnavailable(state, wasRemoteProbe);\n return nextRemoteRecord;\n }\n\n return cleanupPreRegisteredUpdateIdsOnFailure(state, sentUpdateIds, () =>\n finalizeDocumentSync(\n state,\n currentDoc,\n nextRemoteRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n sentUpdateIds,\n wasRemoteProbe,\n ),\n );\n}\n\nasync function revalidateRemoteDocumentBeforeAttachments(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<{ canSyncAttachments: boolean; nextRecord: DocumentRecord }> {\n if (state.pendingAttachments.length === 0 || !nextRecord.documentId) {\n return { canSyncAttachments: true, nextRecord };\n }\n\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n const syncAttempt = await requestRemoteDocumentSync({\n state,\n currentDoc,\n currentRecord: nextRecord,\n encapsulationKeyPair,\n generation,\n pendingUpdates: [],\n unavailableWriterLogMessage:\n \"Documents: skipped pre-attachment revalidation because the writer context is unavailable.\",\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return { canSyncAttachments: false, nextRecord };\n }\n if (!syncAttempt) {\n logUnavailable(state, wasRemoteProbe);\n return { canSyncAttachments: false, nextRecord };\n }\n\n const refreshedRecord = await finalizeDocumentSync(\n state,\n currentDoc,\n nextRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n [],\n wasRemoteProbe,\n );\n return {\n canSyncAttachments:\n !syncAttempt.synced.hasIncompletePull &&\n refreshedRecord.pullContinuation == null &&\n refreshedRecord.pullContinuationRecoveryRequired !== true &&\n isDocumentStoreSyncGenerationCurrent(state, generation),\n nextRecord: refreshedRecord,\n };\n}\n\nasync function runDocumentSyncPass(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const currentDoc = state.doc;\n const encapsulationKeyPair = state.runtime.crypto.encapsulationKeyPair;\n let nextRecord = state.record;\n\n if (!currentDoc || !nextRecord || !encapsulationKeyPair) {\n return;\n }\n\n const generation = captureDocumentStoreRemoteSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n const attachmentGeneration = captureDocumentStoreAttachmentSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n if (!generation || !attachmentGeneration) {\n requestDocumentStoreSync(state);\n return;\n }\n\n const revalidation = await revalidateRemoteDocumentBeforeAttachments(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n nextRecord = revalidation.nextRecord;\n if (!revalidation.canSyncAttachments) {\n return;\n }\n\n const attachmentResult = await syncPendingAttachments(\n state,\n nextRecord,\n encapsulationKeyPair,\n attachmentGeneration,\n );\n nextRecord = attachmentResult.nextRecord;\n if (state.pendingAttachments.length > 0) {\n return;\n }\n // A settled bind and the content update carrying its digest are two server\n // writes. Push the content in this same pass rather than re-arming a later\n // one, so a device lost between them is the only remaining window: peers\n // otherwise see the old digest against the new binding.\n\n nextRecord = await syncDocumentState(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n\n if (!state.doc || !state.record) return;\n\n const pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n if (!canSyncDetachedAttachmentBindings(nextRecord, pendingUpdates.length)) {\n return;\n }\n\n await syncDetachedAttachmentBindings(state, nextRecord, generation);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n }\n}\n\nasync function runScheduledSyncIteration(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n if (!(await awaitInitializationForSync(state))) {\n return false;\n }\n if (!isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)) {\n return true;\n }\n\n if (!canRunScheduledSync(state)) {\n return true;\n }\n\n try {\n await runDocumentSyncPass(state, syncLaneGeneration);\n return true;\n } catch (error) {\n if (isDatabaseUnavailableError(error)) {\n return false;\n }\n\n await reportAndRethrowKeyingVerificationError(\n error,\n state.runtime.util.reportSecurityIncident,\n {\n objectId: state.record?.documentId ?? state.localId,\n objectKind: \"document\",\n operation: \"document.sync\",\n },\n );\n\n throw error;\n }\n}\n\nasync function runScheduledSyncLoop(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const syncingGeneration = captureDocumentStoreSyncGeneration(\n state,\n state.doc,\n );\n setDocumentSyncing(state, true);\n\n try {\n await runScheduledSyncIteration(state, syncLaneGeneration);\n } finally {\n if (\n syncingGeneration &&\n isDocumentStoreSyncGenerationCurrent(state, syncingGeneration) &&\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n setDocumentSyncing(state, false);\n }\n }\n}\n\nexport function registerDocumentStoreSyncLane(\n state: DocumentStoreState,\n getSyncLaneGeneration: () => DocumentStoreSyncLaneGeneration | null,\n): DocumentSyncLane {\n // Retiring the store (its document removed under it) ends this lane's\n // current and in-flight work; a replacement store registers its own.\n onDocumentStoreRetired(state.runtime.state.domainScope, state.localId, () =>\n invalidateDocumentStoreSyncLane(state),\n );\n return registerDocumentSyncLane({\n domainScope: state.runtime.state.domainScope,\n localId: state.localId,\n priority: () =>\n state.remoteUpdatePending || state.record?.snapshotEndVersion === \"\"\n ? -1\n : 0,\n logError: (message, error) => {\n // Read the runtime lazily: a store's runtime is replaced in place, and a\n // reference captured here would report into a torn-down host.\n const { log, logError } = state.runtime.util;\n // Return the host's result: both callbacks are declared `=> void` but may\n // be async, and the lane reporter only catches a rejection it is handed.\n return logError ? logError(message, error) : log(message);\n },\n run: () => {\n const syncLaneGeneration = getSyncLaneGeneration();\n if (!syncLaneGeneration) return Promise.resolve();\n const activeWork = getActiveDocumentRemoteWork(state);\n if (activeWork) {\n // Re-arm on settlement, not immediately: immediate re-requests would\n // spin this lane and starve other work while the HTTP request is held.\n void activeWork.then(() => {\n if (\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n requestDocumentStoreSync(state);\n }\n });\n return Promise.resolve();\n }\n return runDocumentRemoteWork(state, () =>\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ? runScheduledSyncLoop(state, syncLaneGeneration)\n : Promise.resolve(),\n );\n },\n });\n}\n"]}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { DomainScope } from "../../data/shared/domainScope.js";
|
|
2
2
|
import type { DocumentStore, DocumentStoreFacade, PersistedDocumentListener } from "./types.js";
|
|
3
3
|
interface DocumentStoreRegistry {
|
|
4
|
+
/** How the last open built each store's backing store, by store key. */
|
|
5
|
+
freshStoreFactories: Map<string, () => DocumentStore>;
|
|
6
|
+
/** Each backing store's way to stop its sync lane, by local id. */
|
|
7
|
+
retireHandlersByLocalId: Map<string, () => void>;
|
|
8
|
+
/**
|
|
9
|
+
* Stores whose document was removed under them, each with whether its
|
|
10
|
+
* removal still holds; see retireDocumentStore.
|
|
11
|
+
*/
|
|
12
|
+
retiredStores: Map<string, () => boolean>;
|
|
4
13
|
storeKeysByDocumentId: Map<string, string>;
|
|
5
14
|
storeKeysByLocalId: Map<string, string>;
|
|
6
15
|
storesByKey: Map<string, DocumentStoreFacade>;
|
|
@@ -10,6 +19,11 @@ export declare function getOrCreateDocumentStoreRegistry(domainScope: DomainScop
|
|
|
10
19
|
export declare function resolveDocumentStoreKey(registry: DocumentStoreRegistry, localId: string, documentId: string | null): string;
|
|
11
20
|
export declare function registerDocumentStore(domainScope: DomainScope, localId: string, store: DocumentStoreFacade, documentId: string | null): void;
|
|
12
21
|
export declare function registerDocumentStoreIdentity(domainScope: DomainScope, localId: string, documentId: string | null): void;
|
|
22
|
+
/**
|
|
23
|
+
* Whether an open store holds local writes for the document that have not
|
|
24
|
+
* reached SQLite yet, which no persisted-write scan can see.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hasQueuedDocumentStoreWrites(domainScope: DomainScope, localId: string): boolean;
|
|
13
27
|
export declare function requestDocumentStoreSync(state: {
|
|
14
28
|
syncLane: {
|
|
15
29
|
requestSync: () => void;
|
|
@@ -40,4 +54,22 @@ export declare function subscribeToPersistedDocuments(domainScope: DomainScope,
|
|
|
40
54
|
export declare function emitPersistedDocumentDeletion(domainScope: DomainScope, localId: string): void;
|
|
41
55
|
export declare function subscribeToPersistedDocumentDeletions(domainScope: DomainScope, listener: PersistedDocumentDeletionListener): () => void;
|
|
42
56
|
export declare function requestDomainDocumentSync(domainScope: DomainScope): void;
|
|
57
|
+
/** Lets the backing store for `localId` stop its sync lane when retired. */
|
|
58
|
+
export declare function onDocumentStoreRetired(domainScope: DomainScope, localId: string, stopSyncLane: () => void): void;
|
|
59
|
+
/**
|
|
60
|
+
* Retires the store of a document a paused organization's cleanup removed.
|
|
61
|
+
* Its backing store's sync lane stops and the facade an editor may hold
|
|
62
|
+
* switches to a read-only stand-in, so nothing recreates or downloads the
|
|
63
|
+
* document. While `stillRemoved()` holds, reopening returns the stand-in;
|
|
64
|
+
* after that, the next open rebinds the facade to a fresh backing store that
|
|
65
|
+
* loads whatever SQLite holds by then, such as a copy rediscovered on resume.
|
|
66
|
+
*/
|
|
67
|
+
export declare function retireDocumentStore(domainScope: DomainScope, localId: string, stillRemoved: () => boolean): void;
|
|
68
|
+
/**
|
|
69
|
+
* Undoes a retirement whose deletion did not commit: the document survives,
|
|
70
|
+
* so its facade gets a fresh backing store again.
|
|
71
|
+
*/
|
|
72
|
+
export declare function restoreDocumentStore(domainScope: DomainScope, localId: string): void;
|
|
73
|
+
/** The registered store for a key, rebound once its removal has lifted. */
|
|
74
|
+
export declare function takeRegisteredDocumentStore(registry: DocumentStoreRegistry, storeKey: string, createFresh: () => DocumentStore): DocumentStoreFacade | undefined;
|
|
43
75
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { registerInternalDocumentRelink, relinkDocumentStoreWithCommitSideEffect, } from "./documentStore/internalRelink.js";
|
|
2
|
+
import { createRemovedDocumentStore } from "./removedDocumentStore.js";
|
|
2
3
|
const documentStoreRegistriesByScope = new WeakMap();
|
|
3
4
|
// Per-scope listener plumbing shared by the persisted-document and
|
|
4
5
|
// persisted-document-deletion channels: emit fans out to the scope's
|
|
@@ -36,6 +37,9 @@ export function getOrCreateDocumentStoreRegistry(domainScope) {
|
|
|
36
37
|
return existingRegistry;
|
|
37
38
|
}
|
|
38
39
|
const nextRegistry = {
|
|
40
|
+
freshStoreFactories: new Map(),
|
|
41
|
+
retireHandlersByLocalId: new Map(),
|
|
42
|
+
retiredStores: new Map(),
|
|
39
43
|
storeKeysByDocumentId: new Map(),
|
|
40
44
|
storeKeysByLocalId: new Map(),
|
|
41
45
|
storesByKey: new Map(),
|
|
@@ -74,9 +78,27 @@ export function registerDocumentStoreIdentity(domainScope, localId, documentId)
|
|
|
74
78
|
if (localStore) {
|
|
75
79
|
documentStore?.rebindTo(localStore);
|
|
76
80
|
registry.storesByKey.set(documentStoreKey, localStore);
|
|
81
|
+
// The store's retirement and how to rebuild it move with it.
|
|
82
|
+
moveKeyedEntry(registry.freshStoreFactories, localStoreKey, documentStoreKey);
|
|
83
|
+
moveKeyedEntry(registry.retiredStores, localStoreKey, documentStoreKey);
|
|
77
84
|
}
|
|
78
85
|
registry.storesByKey.delete(localStoreKey);
|
|
79
86
|
}
|
|
87
|
+
function moveKeyedEntry(entries, fromKey, toKey) {
|
|
88
|
+
const value = entries.get(fromKey);
|
|
89
|
+
entries.delete(fromKey);
|
|
90
|
+
if (value !== undefined)
|
|
91
|
+
entries.set(toKey, value);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Whether an open store holds local writes for the document that have not
|
|
95
|
+
* reached SQLite yet, which no persisted-write scan can see.
|
|
96
|
+
*/
|
|
97
|
+
export function hasQueuedDocumentStoreWrites(domainScope, localId) {
|
|
98
|
+
const registry = documentStoreRegistriesByScope.get(domainScope);
|
|
99
|
+
const storeKey = registry?.storeKeysByLocalId.get(localId) ?? localId;
|
|
100
|
+
return registry?.storesByKey.get(storeKey)?.hasQueuedWrites() ?? false;
|
|
101
|
+
}
|
|
80
102
|
export function requestDocumentStoreSync(state) {
|
|
81
103
|
state.syncLane?.requestSync();
|
|
82
104
|
}
|
|
@@ -85,8 +107,9 @@ export function requestRegisteredDocumentRemoteSync(domainScope, localId, docume
|
|
|
85
107
|
if (!registry) {
|
|
86
108
|
return false;
|
|
87
109
|
}
|
|
88
|
-
const
|
|
89
|
-
|
|
110
|
+
const storeKey = resolveDocumentStoreKey(registry, localId, documentId);
|
|
111
|
+
const store = registry.storesByKey.get(storeKey);
|
|
112
|
+
if (!store || registry.retiredStores.has(storeKey)) {
|
|
90
113
|
return false;
|
|
91
114
|
}
|
|
92
115
|
// Explicit refresh uses this path to recover missed websocket invalidations
|
|
@@ -158,6 +181,7 @@ export function createDocumentStoreFacade(initialStore) {
|
|
|
158
181
|
discardLocalState: (expectedDocumentId) => targetStore.discardLocalState(expectedDocumentId),
|
|
159
182
|
ensureInitialized: () => targetStore.ensureInitialized(),
|
|
160
183
|
getSnapshot: () => targetStore.getSnapshot(),
|
|
184
|
+
hasQueuedWrites: () => targetStore.hasQueuedWrites(),
|
|
161
185
|
removeAttachment: (slotId) => targetStore.removeAttachment(slotId),
|
|
162
186
|
removeRow: (id) => targetStore.removeRow(id),
|
|
163
187
|
replaceAttachment: (slotId, file) => targetStore.replaceAttachment(slotId, file),
|
|
@@ -199,8 +223,59 @@ export function requestDomainDocumentSync(domainScope) {
|
|
|
199
223
|
if (!registry) {
|
|
200
224
|
return;
|
|
201
225
|
}
|
|
202
|
-
for (const store of
|
|
203
|
-
|
|
226
|
+
for (const [storeKey, store] of registry.storesByKey) {
|
|
227
|
+
if (!registry.retiredStores.has(storeKey))
|
|
228
|
+
store.requestSync();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Lets the backing store for `localId` stop its sync lane when retired. */
|
|
232
|
+
export function onDocumentStoreRetired(domainScope, localId, stopSyncLane) {
|
|
233
|
+
getOrCreateDocumentStoreRegistry(domainScope).retireHandlersByLocalId.set(localId, stopSyncLane);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Retires the store of a document a paused organization's cleanup removed.
|
|
237
|
+
* Its backing store's sync lane stops and the facade an editor may hold
|
|
238
|
+
* switches to a read-only stand-in, so nothing recreates or downloads the
|
|
239
|
+
* document. While `stillRemoved()` holds, reopening returns the stand-in;
|
|
240
|
+
* after that, the next open rebinds the facade to a fresh backing store that
|
|
241
|
+
* loads whatever SQLite holds by then, such as a copy rediscovered on resume.
|
|
242
|
+
*/
|
|
243
|
+
export function retireDocumentStore(domainScope, localId, stillRemoved) {
|
|
244
|
+
const registry = documentStoreRegistriesByScope.get(domainScope);
|
|
245
|
+
const storeKey = registry?.storeKeysByLocalId.get(localId) ?? localId;
|
|
246
|
+
const store = registry?.storesByKey.get(storeKey);
|
|
247
|
+
if (!registry || !store || registry.retiredStores.has(storeKey))
|
|
248
|
+
return;
|
|
249
|
+
registry.retireHandlersByLocalId.get(localId)?.();
|
|
250
|
+
store.rebindTo(createRemovedDocumentStore(store.getSnapshot()));
|
|
251
|
+
registry.retiredStores.set(storeKey, stillRemoved);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Undoes a retirement whose deletion did not commit: the document survives,
|
|
255
|
+
* so its facade gets a fresh backing store again.
|
|
256
|
+
*/
|
|
257
|
+
export function restoreDocumentStore(domainScope, localId) {
|
|
258
|
+
const registry = documentStoreRegistriesByScope.get(domainScope);
|
|
259
|
+
const storeKey = registry?.storeKeysByLocalId.get(localId) ?? localId;
|
|
260
|
+
const store = registry?.storesByKey.get(storeKey);
|
|
261
|
+
if (!registry || !store || !registry.retiredStores.delete(storeKey))
|
|
262
|
+
return;
|
|
263
|
+
const createFresh = registry.freshStoreFactories.get(storeKey);
|
|
264
|
+
// Without a factory the next open rebinds it instead.
|
|
265
|
+
if (createFresh)
|
|
266
|
+
store.rebindTo(createFresh());
|
|
267
|
+
else
|
|
268
|
+
registry.retiredStores.set(storeKey, () => false);
|
|
269
|
+
}
|
|
270
|
+
/** The registered store for a key, rebound once its removal has lifted. */
|
|
271
|
+
export function takeRegisteredDocumentStore(registry, storeKey, createFresh) {
|
|
272
|
+
registry.freshStoreFactories.set(storeKey, createFresh);
|
|
273
|
+
const store = registry.storesByKey.get(storeKey);
|
|
274
|
+
const stillRemoved = registry.retiredStores.get(storeKey);
|
|
275
|
+
if (store && stillRemoved && !stillRemoved()) {
|
|
276
|
+
registry.retiredStores.delete(storeKey);
|
|
277
|
+
store.rebindTo(createFresh());
|
|
204
278
|
}
|
|
279
|
+
return store;
|
|
205
280
|
}
|
|
206
281
|
//# sourceMappingURL=registry.js.map
|