@tearleads/client-sdk 0.1.82 → 0.1.84
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/data/documents/documentSync.js.map +1 -1
- package/data/documents/shared/crypto.js.map +1 -1
- package/data/documents/shared/types.d.ts +1 -1
- package/data/documents/shared/types.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistence.js +2 -2
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistenceTypes.d.ts +1 -1
- package/data/persistence/container-contents/containerContentsPersistenceTypes.js.map +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +3 -3
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataPullContinuationPersistence.js +1 -1
- package/data/persistence/container-contents/containerMetadataPullContinuationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js.map +1 -1
- package/data/persistence/container-contents/containerPendingUpdatePersistence.js +2 -2
- package/data/persistence/container-contents/containerPendingUpdatePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRemovalWork.js +1 -1
- package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
- package/data/persistence/documents/documentDiscoveryReset.d.ts +6 -0
- package/data/persistence/documents/documentsPersistence.js +2 -2
- package/data/persistence/documents/documentsPersistence.js.map +1 -1
- package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js +1 -1
- package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js.map +1 -1
- package/data/persistence/documents/internal/discardDocument.js +2 -2
- package/data/persistence/documents/internal/discardDocument.js.map +1 -1
- package/data/persistence/documents/internal/documentDeletionPersistence.js +2 -2
- package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentMutationPersistence.js +3 -3
- package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentPullContinuationPersistence.js +1 -1
- package/data/persistence/documents/internal/documentPullContinuationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentRecordIdentity.js.map +1 -1
- package/data/persistence/documents/internal/documentRows.js.map +1 -1
- package/data/persistence/documents/internal/ensureDocumentsSchema.js +1 -1
- package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
- package/data/persistence/documents/internal/rowQueryPersistence.js +1 -1
- package/data/persistence/documents/internal/rowQueryPersistence.js.map +1 -1
- package/data/persistence/documents/internal/syncQueuePersistence.js +2 -2
- package/data/persistence/documents/internal/syncQueuePersistence.js.map +1 -1
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentHistoryPersistence.d.ts +1 -1
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentHistoryPersistence.js +5 -5
- package/data/persistence/documents/records/documentHistoryPersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPendingUpdatePersistence.d.ts +2 -2
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPendingUpdatePersistence.js +2 -2
- package/data/persistence/documents/records/documentPendingUpdatePersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPersistenceTypes.d.ts +2 -2
- package/data/persistence/documents/records/documentPersistenceTypes.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentRecordPersistence.d.ts +1 -1
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentRecordPersistence.js +4 -4
- package/data/persistence/documents/records/documentRecordPersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentSyncFailurePersistence.d.ts +2 -2
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentSyncFailurePersistence.js +3 -3
- package/data/persistence/documents/records/documentSyncFailurePersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/index.d.ts +2 -2
- package/data/{sqlite/documentPersistence → persistence/documents/records}/index.js +4 -4
- package/data/persistence/documents/records/index.js.map +1 -0
- package/data/persistence/documents/types.d.ts +2 -2
- package/data/persistence/documents/types.js.map +1 -1
- package/{workflows/sync/remoteResetPrincipalScope.d.ts → data/persistence/principalPolicy/principalPolicyRemoteReset.d.ts} +1 -1
- package/{workflows/sync/remoteResetPrincipalScope.js → data/persistence/principalPolicy/principalPolicyRemoteReset.js} +7 -7
- package/data/persistence/principalPolicy/principalPolicyRemoteReset.js.map +1 -0
- package/data/persistence/verifiedManifestBundlePersistence.d.ts +2 -0
- package/data/persistence/verifiedManifestBundlePersistence.js +7 -0
- package/data/persistence/verifiedManifestBundlePersistence.js.map +1 -1
- package/data/sqlite/{documentPersistence/documentOrphanBlobReclaims.js → schema/documentOrphanBlobReclaimSchema.js} +1 -1
- package/data/sqlite/schema/documentOrphanBlobReclaimSchema.js.map +1 -0
- package/data/sqlite/schema/index.js +1 -1
- package/data/sqlite/schema/index.js.map +1 -1
- package/data/sqlite/sqliteBindBudget.js +12 -0
- package/data/sqlite/sqliteBindBudget.js.map +1 -1
- package/package.json +1 -1
- package/workflows/container-contents/container-state/create/createIntentSeed.js.map +1 -1
- package/workflows/container-contents/container-state/create/createWithMetadataPlan.js.map +1 -1
- package/workflows/container-contents/container-state/types.js.map +1 -1
- package/workflows/container-contents/metadata/index.js.map +1 -1
- package/workflows/container-contents/metadata/metadataEvents.d.ts +1 -1
- package/workflows/container-contents/metadata/metadataEvents.js.map +1 -1
- package/workflows/container-contents/metadata/metadataIncomingUpdateIsolation.js +1 -1
- package/workflows/container-contents/metadata/metadataIncomingUpdateIsolation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataRemoteSync.d.ts +1 -1
- package/workflows/container-contents/metadata/metadataRemoteSync.js.map +1 -1
- package/workflows/container-contents/pendingWrites/index.js +1 -1
- package/workflows/container-contents/pendingWrites/index.js.map +1 -1
- package/workflows/container-contents/recovery/accessRestoration.js +1 -1
- package/workflows/container-contents/recovery/accessRestoration.js.map +1 -1
- package/workflows/container-contents/remoteReset/containerRemoteReset.d.ts +185 -0
- package/workflows/container-contents/remoteReset/containerRemoteReset.js +174 -0
- package/workflows/container-contents/remoteReset/containerRemoteReset.js.map +1 -0
- package/workflows/container-contents/remoteReset/remoteResetCursorScope.d.ts +14 -0
- package/workflows/{sync → container-contents/remoteReset}/remoteResetCursorScope.js +2 -2
- package/workflows/container-contents/remoteReset/remoteResetCursorScope.js.map +1 -0
- package/workflows/documents/create/documentCreationPersistence.js.map +1 -1
- package/workflows/documents/create/index.d.ts +1 -1
- package/workflows/documents/create/index.js.map +1 -1
- package/workflows/documents/documentMutationCommit.d.ts +1 -1
- package/workflows/documents/documentMutationCommit.js.map +1 -1
- package/workflows/documents/index.d.ts +2 -2
- package/workflows/documents/index.js +2 -2
- package/workflows/documents/index.js.map +1 -1
- package/workflows/documents/remoteReset/documentRemoteReset.d.ts +56 -0
- package/workflows/documents/remoteReset/documentRemoteReset.js +135 -0
- package/workflows/documents/remoteReset/documentRemoteReset.js.map +1 -0
- package/workflows/{sync → documents/remoteReset}/remoteResetAttachments.js +3 -3
- package/workflows/documents/remoteReset/remoteResetAttachments.js.map +1 -0
- package/workflows/{sync → documents/remoteReset}/remoteResetPlans.d.ts +1 -1
- package/workflows/{sync → documents/remoteReset}/remoteResetPlans.js +7 -7
- package/workflows/documents/remoteReset/remoteResetPlans.js.map +1 -0
- package/workflows/documents/sync/index.js.map +1 -1
- package/workflows/documents/sync/initialSync.d.ts +1 -1
- package/workflows/documents/sync/initialSync.js.map +1 -1
- package/workflows/documents/sync/readOnlySync.d.ts +1 -1
- package/workflows/documents/sync/readOnlySync.js.map +1 -1
- package/workflows/documents/sync/syncAttemptPlanning.js.map +1 -1
- package/workflows/documents/sync/syncAttemptState.d.ts +1 -1
- package/workflows/documents/sync/syncAttemptState.js.map +1 -1
- package/workflows/documents/sync/syncResponseResult.js.map +1 -1
- package/workflows/documents/sync/syncSubmittedResult.js.map +1 -1
- package/workflows/documents/syncFailures/index.js.map +1 -1
- package/workflows/documents/syncPlan/syncContentKeys.d.ts +1 -1
- package/workflows/documents/syncPlan/syncContentKeys.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanMaterial.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanRequestBounds.js.map +1 -1
- package/workflows/documents/syncRekeys/syncContainerRekeys.js.map +1 -1
- package/workflows/documents/syncRekeys/syncRecoveryRekey.d.ts +1 -1
- package/workflows/documents/syncRekeys/syncRecoveryRekey.js +1 -1
- package/workflows/documents/syncRekeys/syncRecoveryRekey.js.map +1 -1
- package/workflows/organizations/readModel/listLocalOrganizations.js +1 -1
- package/workflows/organizations/readModel/listLocalOrganizations.js.map +1 -1
- package/workflows/organizations/readModel/organizationRemoteReset.js +25 -0
- package/workflows/organizations/readModel/organizationRemoteReset.js.map +1 -0
- package/workflows/registration/persistRegistrationBootstrap.d.ts +1 -1
- package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
- package/workflows/sync/remoteReset.js +60 -229
- package/workflows/sync/remoteReset.js.map +1 -1
- package/workflows/sync/remoteResetScope.d.ts +7 -10
- package/workflows/sync/remoteResetScope.js +26 -108
- package/workflows/sync/remoteResetScope.js.map +1 -1
- package/data/sqlite/documentPersistence/documentHistoryPersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/documentOrphanBlobReclaims.js.map +0 -1
- package/data/sqlite/documentPersistence/documentPendingUpdatePersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/documentPersistenceTypes.js.map +0 -1
- package/data/sqlite/documentPersistence/documentRecordPersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/documentSyncFailurePersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/index.js.map +0 -1
- package/workflows/sync/remoteResetAttachments.js.map +0 -1
- package/workflows/sync/remoteResetBatches.js +0 -13
- package/workflows/sync/remoteResetBatches.js.map +0 -1
- package/workflows/sync/remoteResetCursorScope.js.map +0 -1
- package/workflows/sync/remoteResetPlans.js.map +0 -1
- package/workflows/sync/remoteResetPrincipalScope.js.map +0 -1
- /package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPersistenceTypes.js +0 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
2
|
+
import { deleteDocumentPlacementRowsByContainerIds, deleteDocumentPlacementRowsByDocumentIds, } from "../../../data/persistence/container-contents/documentContainerProjectionPersistence.js";
|
|
3
|
+
import { recordSupersededContainerBindingsInTransaction } from "../../../data/persistence/container-contents/supersededContainerBindings.js";
|
|
4
|
+
import { containerHydrationTombstones, containerSyncWatermarks, containers, documentContainerProjection, dormantContainerMetadata, dormantMetadataSweepRequests, inContainerIntentLanes, inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../../data/sqlite/schema/index.js";
|
|
5
|
+
import { documentIntentLinkTargets } from "../../../data/sqlite/schema/documentPlacementIntentSchema.js";
|
|
6
|
+
import { remoteResetBatches } from "../../../data/sqlite/sqliteBindBudget.js";
|
|
7
|
+
import { isRemoteResetSyncCursor } from "./remoteResetCursorScope.js";
|
|
8
|
+
// Container Contents' part of a remote reset. The sync remote reset calls these
|
|
9
|
+
// in one transaction: it forgets the organization's server state, strips server
|
|
10
|
+
// identity from the folders it keeps, and queues them to be created again.
|
|
11
|
+
export { clearRemoteResetSyncCursors } from "./remoteResetCursorScope.js";
|
|
12
|
+
const CONTAINER_CREATE_INTENT_TYPE = "container.create";
|
|
13
|
+
/** The organization's live folders, plus the ids of its dormant ones. */
|
|
14
|
+
export async function loadContainerResetScope(tx, organizationId) {
|
|
15
|
+
const liveContainerRows = (await tx
|
|
16
|
+
.select({ id: containers.id, parentId: containers.parentId })
|
|
17
|
+
.from(containers)
|
|
18
|
+
.where(eq(containers.organizationId, organizationId))).flatMap((row) => (row.id ? [{ id: row.id, parentId: row.parentId }] : []));
|
|
19
|
+
const dormantContainerRows = await tx
|
|
20
|
+
.select({ id: dormantContainerMetadata.containerId })
|
|
21
|
+
.from(dormantContainerMetadata)
|
|
22
|
+
.where(eq(dormantContainerMetadata.organizationId, organizationId));
|
|
23
|
+
const containerRows = liveContainerRows;
|
|
24
|
+
return {
|
|
25
|
+
containerIds: [
|
|
26
|
+
...new Set([
|
|
27
|
+
...containerRows.map((row) => row.id),
|
|
28
|
+
...dormantContainerRows.map((row) => row.id),
|
|
29
|
+
]),
|
|
30
|
+
],
|
|
31
|
+
containerRows,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Every document placement, which decides the documents a reset covers. */
|
|
35
|
+
export function listDocumentPlacementRows(tx) {
|
|
36
|
+
return tx.select().from(documentContainerProjection);
|
|
37
|
+
}
|
|
38
|
+
/** Counts the queued folder and document move intents a reset clears. */
|
|
39
|
+
export async function countContainerResetIntents(input) {
|
|
40
|
+
const containerIdSet = new Set(input.containerIds);
|
|
41
|
+
const documentLocalIdSet = new Set(input.documentLocalIds);
|
|
42
|
+
const intents = await input.tx
|
|
43
|
+
.select({
|
|
44
|
+
lane: localIntents.lane,
|
|
45
|
+
localId: localIntents.localId,
|
|
46
|
+
subjectId: localIntents.subjectId,
|
|
47
|
+
})
|
|
48
|
+
.from(localIntents);
|
|
49
|
+
const containerIntentCount = (lane) => intents.filter((row) => row.lane === lane && containerIdSet.has(row.subjectId)).length;
|
|
50
|
+
return {
|
|
51
|
+
clearedContainerCreateIntentCount: containerIntentCount(LOCAL_INTENT_LANES.containerCreate),
|
|
52
|
+
clearedContainerMoveIntentCount: containerIntentCount(LOCAL_INTENT_LANES.containerMove),
|
|
53
|
+
clearedDocumentMoveIntentCount: intents.filter((row) => row.lane === LOCAL_INTENT_LANES.documentPlacement &&
|
|
54
|
+
row.localId !== null &&
|
|
55
|
+
documentLocalIdSet.has(row.localId)).length,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Counts the sync cursors `clearRemoteResetSyncCursors` deletes. */
|
|
59
|
+
export async function countRemoteResetSyncCursors(input) {
|
|
60
|
+
const scopedContainerIds = new Set(input.containerIds);
|
|
61
|
+
const syncLanes = await input.tx.select().from(containerSyncWatermarks);
|
|
62
|
+
return syncLanes.filter((row) => isRemoteResetSyncCursor({
|
|
63
|
+
containerIds: scopedContainerIds,
|
|
64
|
+
row,
|
|
65
|
+
})).length;
|
|
66
|
+
}
|
|
67
|
+
export async function clearDormantContainerMetadataForRemoteReset(tx, organizationId) {
|
|
68
|
+
for (const table of [
|
|
69
|
+
dormantContainerMetadata,
|
|
70
|
+
dormantMetadataSweepRequests,
|
|
71
|
+
]) {
|
|
72
|
+
await tx
|
|
73
|
+
.delete(table)
|
|
74
|
+
.where(eq(table.organizationId, organizationId))
|
|
75
|
+
.run();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** Clears the folders' placements, queued intents, and hydration tombstones. */
|
|
79
|
+
export async function clearContainerRowsForRemoteReset(input) {
|
|
80
|
+
for (const containerBatch of remoteResetBatches(input.containerIds)) {
|
|
81
|
+
await deleteDocumentPlacementRowsByContainerIds(input.tx, containerBatch);
|
|
82
|
+
await input.tx
|
|
83
|
+
.delete(localIntents)
|
|
84
|
+
.where(and(inContainerIntentLanes(), inArray(localIntents.subjectId, containerBatch)))
|
|
85
|
+
.run();
|
|
86
|
+
await input.tx
|
|
87
|
+
.delete(containerHydrationTombstones)
|
|
88
|
+
.where(inArray(containerHydrationTombstones.containerId, containerBatch))
|
|
89
|
+
.run();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Clears the documents' placements and their queued placement intents. */
|
|
93
|
+
export async function clearDocumentPlacementsForRemoteReset(input) {
|
|
94
|
+
const { tx } = input;
|
|
95
|
+
for (const documentIdBatch of remoteResetBatches(input.oldDocumentIds)) {
|
|
96
|
+
await deleteDocumentPlacementRowsByDocumentIds(tx, documentIdBatch);
|
|
97
|
+
}
|
|
98
|
+
for (const localIdBatch of remoteResetBatches(input.documentLocalIds)) {
|
|
99
|
+
const placementIntents = and(inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement), inArray(localIntents.localId, localIdBatch));
|
|
100
|
+
await tx
|
|
101
|
+
.delete(documentIntentLinkTargets)
|
|
102
|
+
.where(inArray(documentIntentLinkTargets.intentId, tx
|
|
103
|
+
.select({ id: localIntents.id })
|
|
104
|
+
.from(localIntents)
|
|
105
|
+
.where(placementIntents)))
|
|
106
|
+
.run();
|
|
107
|
+
await tx.delete(localIntents).where(placementIntents).run();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Drops the folders' server timestamps and metadata document, and moves them
|
|
112
|
+
* to the replacement organization when there is one.
|
|
113
|
+
*/
|
|
114
|
+
export async function resetContainerServerIdentity(input) {
|
|
115
|
+
const { now, reset, tx } = input;
|
|
116
|
+
// Replacement re-homes folders under their ids; the purged organization
|
|
117
|
+
// can never bind them again on this device.
|
|
118
|
+
for (const containerIds of reset.replacement
|
|
119
|
+
? remoteResetBatches(input.containerIds)
|
|
120
|
+
: []) {
|
|
121
|
+
await recordSupersededContainerBindingsInTransaction(tx, {
|
|
122
|
+
containerIds,
|
|
123
|
+
organizationId: reset.organizationId,
|
|
124
|
+
supersededAt: now,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
for (const row of input.containerRows) {
|
|
128
|
+
await tx
|
|
129
|
+
.update(containers)
|
|
130
|
+
.set({
|
|
131
|
+
metadataDocumentId: null,
|
|
132
|
+
organizationId: reset.replacement?.organizationId ?? reset.organizationId,
|
|
133
|
+
parentId: reset.replacement && row.parentId === null
|
|
134
|
+
? reset.replacement.rootContainerId
|
|
135
|
+
: row.parentId,
|
|
136
|
+
serverCreatedAt: null,
|
|
137
|
+
serverUpdatedAt: null,
|
|
138
|
+
...(reset.replacement ? { systemSlot: null } : {}),
|
|
139
|
+
localUpdatedAt: now,
|
|
140
|
+
})
|
|
141
|
+
.where(eq(containers.id, row.id))
|
|
142
|
+
.run();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Queues a create for every kept folder that has a parent to create it in. */
|
|
146
|
+
export async function queueContainerCreatesForRemoteReset(input) {
|
|
147
|
+
const rows = input.containerRows.flatMap((row) => {
|
|
148
|
+
const parentId = row.parentId ?? input.reset.replacement?.rootContainerId ?? null;
|
|
149
|
+
return parentId ? [{ id: row.id, parentId }] : [];
|
|
150
|
+
});
|
|
151
|
+
if (rows.length === 0)
|
|
152
|
+
return 0;
|
|
153
|
+
for (const rowBatch of remoteResetBatches(rows)) {
|
|
154
|
+
await input.tx
|
|
155
|
+
.insert(localIntents)
|
|
156
|
+
.values(rowBatch.map((row) => ({
|
|
157
|
+
id: crypto.randomUUID(),
|
|
158
|
+
lane: LOCAL_INTENT_LANES.containerCreate,
|
|
159
|
+
subjectId: row.id,
|
|
160
|
+
targetContainerId: row.parentId,
|
|
161
|
+
intentType: CONTAINER_CREATE_INTENT_TYPE,
|
|
162
|
+
syncStatus: "pending",
|
|
163
|
+
remoteContainerId: null,
|
|
164
|
+
remoteMetadataAccessStateHash: null,
|
|
165
|
+
remoteMetadataDocumentId: null,
|
|
166
|
+
lastError: null,
|
|
167
|
+
createdAt: input.now,
|
|
168
|
+
updatedAt: input.now,
|
|
169
|
+
})))
|
|
170
|
+
.run();
|
|
171
|
+
}
|
|
172
|
+
return rows.length;
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=containerRemoteReset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containerRemoteReset.js","sourceRoot":"","sources":["containerRemoteReset.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray } from \"drizzle-orm\";\nimport {\n deleteDocumentPlacementRowsByContainerIds,\n deleteDocumentPlacementRowsByDocumentIds,\n} from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { recordSupersededContainerBindingsInTransaction } from \"../../../data/persistence/container-contents/supersededContainerBindings\";\nimport {\n containerHydrationTombstones,\n containerSyncWatermarks,\n containers,\n documentContainerProjection,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../../data/sqlite/schema\";\nimport { documentIntentLinkTargets } from \"../../../data/sqlite/schema/documentPlacementIntentSchema\";\nimport { remoteResetBatches } from \"../../../data/sqlite/sqliteBindBudget\";\nimport type { ClientSQLiteTransactionScope } from \"../../../data/sqlite/sqlitePersistenceRuntime\";\nimport { isRemoteResetSyncCursor } from \"./remoteResetCursorScope\";\n\n// Container Contents' part of a remote reset. The sync remote reset calls these\n// in one transaction: it forgets the organization's server state, strips server\n// identity from the folders it keeps, and queues them to be created again.\nexport { clearRemoteResetSyncCursors } from \"./remoteResetCursorScope\";\n\nconst CONTAINER_CREATE_INTENT_TYPE = \"container.create\";\n\nexport interface ContainerRemoteReset {\n readonly organizationId: string;\n readonly replacement?:\n | {\n readonly organizationId: string;\n readonly rootContainerId: string;\n }\n | undefined;\n}\n\nexport interface ResetContainerRow {\n readonly id: string;\n readonly parentId: string | null;\n}\n\n/** The organization's live folders, plus the ids of its dormant ones. */\nexport async function loadContainerResetScope(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<{\n containerIds: string[];\n containerRows: ResetContainerRow[];\n}> {\n const liveContainerRows = (\n await tx\n .select({ id: containers.id, parentId: containers.parentId })\n .from(containers)\n .where(eq(containers.organizationId, organizationId))\n ).flatMap((row) => (row.id ? [{ id: row.id, parentId: row.parentId }] : []));\n const dormantContainerRows = await tx\n .select({ id: dormantContainerMetadata.containerId })\n .from(dormantContainerMetadata)\n .where(eq(dormantContainerMetadata.organizationId, organizationId));\n const containerRows = liveContainerRows;\n return {\n containerIds: [\n ...new Set([\n ...containerRows.map((row) => row.id),\n ...dormantContainerRows.map((row) => row.id),\n ]),\n ],\n containerRows,\n };\n}\n\n/** Every document placement, which decides the documents a reset covers. */\nexport function listDocumentPlacementRows(tx: ClientSQLiteTransactionScope) {\n return tx.select().from(documentContainerProjection);\n}\n\n/** Counts the queued folder and document move intents a reset clears. */\nexport async function countContainerResetIntents(input: {\n containerIds: readonly string[];\n documentLocalIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<{\n clearedContainerCreateIntentCount: number;\n clearedContainerMoveIntentCount: number;\n clearedDocumentMoveIntentCount: number;\n}> {\n const containerIdSet = new Set(input.containerIds);\n const documentLocalIdSet = new Set(input.documentLocalIds);\n const intents = await input.tx\n .select({\n lane: localIntents.lane,\n localId: localIntents.localId,\n subjectId: localIntents.subjectId,\n })\n .from(localIntents);\n const containerIntentCount = (lane: string) =>\n intents.filter(\n (row) => row.lane === lane && containerIdSet.has(row.subjectId),\n ).length;\n return {\n clearedContainerCreateIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerCreate,\n ),\n clearedContainerMoveIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerMove,\n ),\n clearedDocumentMoveIntentCount: intents.filter(\n (row) =>\n row.lane === LOCAL_INTENT_LANES.documentPlacement &&\n row.localId !== null &&\n documentLocalIdSet.has(row.localId),\n ).length,\n };\n}\n\n/** Counts the sync cursors `clearRemoteResetSyncCursors` deletes. */\nexport async function countRemoteResetSyncCursors(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<number> {\n const scopedContainerIds = new Set(input.containerIds);\n const syncLanes = await input.tx.select().from(containerSyncWatermarks);\n return syncLanes.filter((row) =>\n isRemoteResetSyncCursor({\n containerIds: scopedContainerIds,\n row,\n }),\n ).length;\n}\n\nexport async function clearDormantContainerMetadataForRemoteReset(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<void> {\n for (const table of [\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n ] as const) {\n await tx\n .delete(table)\n .where(eq(table.organizationId, organizationId))\n .run();\n }\n}\n\n/** Clears the folders' placements, queued intents, and hydration tombstones. */\nexport async function clearContainerRowsForRemoteReset(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n for (const containerBatch of remoteResetBatches(input.containerIds)) {\n await deleteDocumentPlacementRowsByContainerIds(input.tx, containerBatch);\n await input.tx\n .delete(localIntents)\n .where(\n and(\n inContainerIntentLanes(),\n inArray(localIntents.subjectId, containerBatch),\n ),\n )\n .run();\n await input.tx\n .delete(containerHydrationTombstones)\n .where(inArray(containerHydrationTombstones.containerId, containerBatch))\n .run();\n }\n}\n\n/** Clears the documents' placements and their queued placement intents. */\nexport async function clearDocumentPlacementsForRemoteReset(input: {\n documentLocalIds: readonly string[];\n oldDocumentIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { tx } = input;\n for (const documentIdBatch of remoteResetBatches(input.oldDocumentIds)) {\n await deleteDocumentPlacementRowsByDocumentIds(tx, documentIdBatch);\n }\n for (const localIdBatch of remoteResetBatches(input.documentLocalIds)) {\n const placementIntents = and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n inArray(localIntents.localId, localIdBatch),\n );\n await tx\n .delete(documentIntentLinkTargets)\n .where(\n inArray(\n documentIntentLinkTargets.intentId,\n tx\n .select({ id: localIntents.id })\n .from(localIntents)\n .where(placementIntents),\n ),\n )\n .run();\n await tx.delete(localIntents).where(placementIntents).run();\n }\n}\n\n/**\n * Drops the folders' server timestamps and metadata document, and moves them\n * to the replacement organization when there is one.\n */\nexport async function resetContainerServerIdentity(input: {\n containerIds: readonly string[];\n containerRows: readonly ResetContainerRow[];\n now: string;\n reset: ContainerRemoteReset;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { now, reset, tx } = input;\n // Replacement re-homes folders under their ids; the purged organization\n // can never bind them again on this device.\n for (const containerIds of reset.replacement\n ? remoteResetBatches(input.containerIds)\n : []) {\n await recordSupersededContainerBindingsInTransaction(tx, {\n containerIds,\n organizationId: reset.organizationId,\n supersededAt: now,\n });\n }\n for (const row of input.containerRows) {\n await tx\n .update(containers)\n .set({\n metadataDocumentId: null,\n organizationId:\n reset.replacement?.organizationId ?? reset.organizationId,\n parentId:\n reset.replacement && row.parentId === null\n ? reset.replacement.rootContainerId\n : row.parentId,\n serverCreatedAt: null,\n serverUpdatedAt: null,\n ...(reset.replacement ? { systemSlot: null } : {}),\n localUpdatedAt: now,\n })\n .where(eq(containers.id, row.id))\n .run();\n }\n}\n\n/** Queues a create for every kept folder that has a parent to create it in. */\nexport async function queueContainerCreatesForRemoteReset(input: {\n containerRows: readonly ResetContainerRow[];\n now: string;\n reset: ContainerRemoteReset;\n tx: ClientSQLiteTransactionScope;\n}): Promise<number> {\n const rows = input.containerRows.flatMap((row) => {\n const parentId =\n row.parentId ?? input.reset.replacement?.rootContainerId ?? null;\n return parentId ? [{ id: row.id, parentId }] : [];\n });\n if (rows.length === 0) return 0;\n for (const rowBatch of remoteResetBatches(rows)) {\n await input.tx\n .insert(localIntents)\n .values(\n rowBatch.map((row) => ({\n id: crypto.randomUUID(),\n lane: LOCAL_INTENT_LANES.containerCreate,\n subjectId: row.id,\n targetContainerId: row.parentId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\" as const,\n remoteContainerId: null,\n remoteMetadataAccessStateHash: null,\n remoteMetadataDocumentId: null,\n lastError: null,\n createdAt: input.now,\n updatedAt: input.now,\n })),\n )\n .run();\n }\n return rows.length;\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ClientSQLiteTransactionScope } from "../../../data/sqlite/sqlitePersistenceRuntime.js";
|
|
2
|
+
interface SyncCursorRow {
|
|
3
|
+
readonly laneId: string;
|
|
4
|
+
readonly laneKind: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function isRemoteResetSyncCursor(input: {
|
|
7
|
+
containerIds: ReadonlySet<string>;
|
|
8
|
+
row: SyncCursorRow;
|
|
9
|
+
}): boolean;
|
|
10
|
+
export declare function clearRemoteResetSyncCursors(input: {
|
|
11
|
+
containerIds: readonly string[];
|
|
12
|
+
tx: ClientSQLiteTransactionScope;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { and, eq, inArray, or } from "drizzle-orm";
|
|
2
|
-
import { containerSyncWatermarks } from "
|
|
3
|
-
import { remoteResetBatches } from "
|
|
2
|
+
import { containerSyncWatermarks } from "../../../data/sqlite/schema/index.js";
|
|
3
|
+
import { remoteResetBatches } from "../../../data/sqlite/sqliteBindBudget.js";
|
|
4
4
|
const CONTAINER_DOCUMENTS_LANE = "container_documents";
|
|
5
5
|
const CONTAINER_PARENT_LANE = "container_parent";
|
|
6
6
|
// The API root feed lists every accessible organization. Its one cursor must
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remoteResetCursorScope.js","sourceRoot":"","sources":["remoteResetCursorScope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAG3E,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AACvD,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AACjD,6EAA6E;AAC7E,0EAA0E;AAC1E,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5B,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAOrC,MAAM,UAAU,uBAAuB,CAAC,KAGvC;IACC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,wBAAwB,EAAE,CAAC;QACpD,OAAO,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,qBAAqB;QAAE,OAAO,KAAK,CAAC;IAC/D,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO,CACL,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC;QAC/C,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KAGjD;IACC,mEAAmE;IACnE,MAAM,KAAK,GAAG,uBAAuB,CAAC;IACtC,MAAM,KAAK,CAAC,EAAE;SACX,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EACzC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAC/B,CACF;SACA,GAAG,EAAE,CAAC;IACT,KAAK,MAAM,cAAc,IAAI,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QACpE,MAAM,aAAa,GAAG,cAAc,CAAC,GAAG,CACtC,CAAC,WAAW,EAAE,EAAE,CAAC,GAAG,kBAAkB,GAAG,WAAW,EAAE,CACvD,CAAC;QACF,MAAM,KAAK,CAAC,EAAE;aACX,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CACJ,EAAE,CACA,GAAG,CACD,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EACzC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,CACrC,EACD,GAAG,CACD,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,wBAAwB,CAAC,EAC5C,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,CACtC,CACF,CACF;aACA,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC","sourcesContent":["import { and, eq, inArray, or } from \"drizzle-orm\";\nimport { containerSyncWatermarks } from \"../../../data/sqlite/schema\";\nimport { remoteResetBatches } from \"../../../data/sqlite/sqliteBindBudget\";\nimport type { ClientSQLiteTransactionScope } from \"../../../data/sqlite/sqlitePersistenceRuntime\";\n\nconst CONTAINER_DOCUMENTS_LANE = \"container_documents\";\nconst CONTAINER_PARENT_LANE = \"container_parent\";\n// The API root feed lists every accessible organization. Its one cursor must\n// reset on any organization's purge; child feeds use globally unique IDs.\nconst ROOT_LANE_ID = \"root\";\nconst PARENT_LANE_PREFIX = \"parent:\";\n\ninterface SyncCursorRow {\n readonly laneId: string;\n readonly laneKind: string;\n}\n\nexport function isRemoteResetSyncCursor(input: {\n containerIds: ReadonlySet<string>;\n row: SyncCursorRow;\n}): boolean {\n if (input.row.laneKind === CONTAINER_DOCUMENTS_LANE) {\n return input.containerIds.has(input.row.laneId);\n }\n if (input.row.laneKind !== CONTAINER_PARENT_LANE) return false;\n if (input.row.laneId === ROOT_LANE_ID) return true;\n return (\n input.row.laneId.startsWith(PARENT_LANE_PREFIX) &&\n input.containerIds.has(input.row.laneId.slice(PARENT_LANE_PREFIX.length))\n );\n}\n\nexport async function clearRemoteResetSyncCursors(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n // One row per lane holds both the cursor and its freshness marker.\n const table = containerSyncWatermarks;\n await input.tx\n .delete(table)\n .where(\n and(\n eq(table.laneKind, CONTAINER_PARENT_LANE),\n eq(table.laneId, ROOT_LANE_ID),\n ),\n )\n .run();\n for (const containerBatch of remoteResetBatches(input.containerIds)) {\n const parentLaneIds = containerBatch.map(\n (containerId) => `${PARENT_LANE_PREFIX}${containerId}`,\n );\n await input.tx\n .delete(table)\n .where(\n or(\n and(\n eq(table.laneKind, CONTAINER_PARENT_LANE),\n inArray(table.laneId, parentLaneIds),\n ),\n and(\n eq(table.laneKind, CONTAINER_DOCUMENTS_LANE),\n inArray(table.laneId, containerBatch),\n ),\n ),\n )\n .run();\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentCreationPersistence.js","sourceRoot":"","sources":["documentCreationPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAQzB,MAAM,UAAU,yBAAyB,CAAC,KAUzC;IACC,OAAO,KAAK,CAAC,WAAW,CAAC,mCAAmC,CAC1D,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,MAAM,EACZ;QACE,gBAAgB,EAAE,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC;QACvD,QAAQ,EAAE,aAAa,CAAC,yBAAyB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;KACrE,EACD,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,YAAY;QACvC,CAAC,CAAC;YACE,GAAG,CAAC,KAAK,CAAC,aAAa;gBACrB,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE;gBACxC,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpE;QACH,CAAC,CAAC,SAAS,EACb,KAAK,CAAC,oBAAoB,CAC3B,CAAC;AACJ,CAAC","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n encodeVersionVector,\n exportFullHistorySnapshot,\n} from \"@tearleads/loro\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../../data/persistence/documents/documentsPersistence\";\nimport type { PendingUpdateFields } from \"../../../data/
|
|
1
|
+
{"version":3,"file":"documentCreationPersistence.js","sourceRoot":"","sources":["documentCreationPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAQzB,MAAM,UAAU,yBAAyB,CAAC,KAUzC;IACC,OAAO,KAAK,CAAC,WAAW,CAAC,mCAAmC,CAC1D,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,MAAM,EACZ;QACE,gBAAgB,EAAE,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC;QACvD,QAAQ,EAAE,aAAa,CAAC,yBAAyB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;KACrE,EACD,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,YAAY;QACvC,CAAC,CAAC;YACE,GAAG,CAAC,KAAK,CAAC,aAAa;gBACrB,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE;gBACxC,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpE;QACH,CAAC,CAAC,SAAS,EACb,KAAK,CAAC,oBAAoB,CAC3B,CAAC;AACJ,CAAC","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n encodeVersionVector,\n exportFullHistorySnapshot,\n} from \"@tearleads/loro\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../../data/persistence/documents/documentsPersistence\";\nimport type { PendingUpdateFields } from \"../../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\n\nexport function createInitialDocumentRows(input: {\n currentDoc: Parameters<typeof encodeVersionVector>[0];\n execSql: ExecSql;\n persistence: DocumentsPersistence;\n pendingUpdate?: PendingUpdateFields | undefined;\n record: StoredDocumentRecord;\n stillCurrent?: (() => boolean) | undefined;\n saveClientProjection: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[4];\n}): Promise<string | null> {\n return input.persistence.createDocumentWithHistoryCheckpoint(\n input.execSql,\n input.record,\n {\n endVersionVector: encodeVersionVector(input.currentDoc),\n snapshot: bytesToBase64(exportFullHistorySnapshot(input.currentDoc)),\n },\n input.pendingUpdate || input.stillCurrent\n ? {\n ...(input.pendingUpdate\n ? { pendingUpdate: input.pendingUpdate }\n : {}),\n ...(input.stillCurrent ? { stillCurrent: input.stillCurrent } : {}),\n }\n : undefined,\n input.saveClientProjection,\n );\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ContainerWriterProjectionResponse, type DocumentCreateResponse } from "../../../internal/validators/response/index.js";
|
|
2
2
|
import type { CreateRemoteDocumentResult, DocumentCreateApi, DocumentCreateAuthor, MaterializedDocumentCreatePlan, ProjectionVerificationOptions } from "../../../data/documents/shared/types.js";
|
|
3
3
|
import type { ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer } from "../../../data/keyingProjectionVerification/index.js";
|
|
4
|
-
import type { PendingUpdateRecord } from "../../../data/
|
|
4
|
+
import type { PendingUpdateRecord } from "../../../data/persistence/documents/records/index.js";
|
|
5
5
|
import type { ExecSql } from "../../../data/sqlite/sqlSchema.js";
|
|
6
6
|
import type { DocumentCreateTerminalFailureHandler } from "./createProjectionFetch.js";
|
|
7
7
|
export declare function buildMaterializedDocumentCreatePlan(input: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentCreateRequest } from \"@tearleads/validators/request\";\nimport {\n type ContainerWriterProjectionResponse,\n DOCUMENT_SYNC_ERROR_CODES,\n type DocumentCreateResponse,\n} from \"@tearleads/validators/response\";\nimport { assertContainerAuthorAccess } from \"../../../data/containers/shared/authorAccess\";\nimport { buildDocumentCreatePlan } from \"../../../data/documents/shared/events\";\nimport { wrapDocumentContentKeyForCreate } from \"../../../data/documents/shared/projection\";\nimport type {\n CreateRemoteDocumentResult,\n DocumentCreateApi,\n DocumentCreateAuthor,\n MaterializedDocumentCreatePlan,\n ProjectionVerificationOptions,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport {\n collectContainerWriterProjectionPrincipalPolicies,\n nullOnProjectionVerificationCancellation,\n requireProjectionUserKeyResolver,\n} from \"../../../data/keyingProjectionVerification\";\nimport { isContainerCreatePending } from \"../../../data/persistence/container-contents/pendingContainerCreate\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport { recordDocumentAuthorAccessFailure } from \"../authorAccessFailure\";\nimport {\n buildDocumentCreateSeedRequest,\n documentCreateSeedFits,\n} from \"../sync/initialSync\";\nimport {\n isDocumentManifestAlreadyExistsConflict,\n shouldRetryWithFreshProjection,\n} from \"../syncFailures/syncFailureClassification\";\nimport { adoptExistingRemoteDocument } from \"./createAdoption\";\nimport type { DocumentCreateTerminalFailureHandler } from \"./createProjectionFetch\";\nimport { fetchContainerWriterProjectionForCreate } from \"./createProjectionFetch\";\nimport { acknowledgeRemoteDocumentCreate } from \"./createResponse\";\n\nexport async function buildMaterializedDocumentCreatePlan(\n input: {\n author: DocumentCreateAuthor;\n containerProjection: ContainerWriterProjectionResponse;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql?: ExecSql | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n signedAt?: string | undefined;\n targetSecretKey: Uint8Array;\n } & ProjectionVerificationOptions,\n): Promise<MaterializedDocumentCreatePlan> {\n const contentKey =\n input.contentKey ?? crypto.getRandomValues(new Uint8Array(32));\n if (contentKey.byteLength !== 32) {\n throw new Error(\"Document content key must be 32 bytes\");\n }\n // Resolved before wrapping: each envelope is sealed to its document and\n // content-key epoch.\n const documentId = input.documentId ?? crypto.randomUUID();\n const contentKeyEpoch = input.contentKeyEpoch ?? 1;\n const targetEnvelopes = await wrapDocumentContentKeyForCreate({\n contentKey,\n contentKeyEpoch,\n documentId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n projection: input.containerProjection,\n secretKey: input.targetSecretKey,\n ...projectionVerificationOptions(input),\n });\n if (input.resolveProjectionUserKey) {\n const principalPolicies =\n await collectContainerWriterProjectionPrincipalPolicies({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n projection: input.containerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n });\n assertContainerAuthorAccess({\n // Document signing derives its organization from the verified target.\n author: {\n ...input.author,\n organizationId: input.containerProjection.organizationId,\n },\n projection: input.containerProjection,\n principalPolicies,\n minimumAccess: \"write\",\n });\n }\n // The explicit local-trust variant builds provisioning artifacts before\n // their new principal policies exist remotely; remote creates cannot use it.\n const plan = await buildDocumentCreatePlan({\n author: input.author,\n containerProjection: input.containerProjection,\n contentKeyEpoch,\n documentId,\n ...(input.eventId === undefined ? {} : { eventId: input.eventId }),\n ...(input.signedAt === undefined ? {} : { signedAt: input.signedAt }),\n targetEnvelopes,\n });\n\n return {\n contentKey,\n plan,\n };\n}\n\nexport { documentWriterProjectionFromCreateResponse } from \"./createProjection\";\n\ninterface MaterializedDocumentCreatePlanWithProjection {\n readonly containerProjection: ContainerWriterProjectionResponse;\n readonly materializedPlan: MaterializedDocumentCreatePlan;\n}\n\nasync function buildMaterializedDocumentCreatePlanWithFreshProjection(input: {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<MaterializedDocumentCreatePlanWithProjection | null> {\n const buildWithProjection = async (\n containerProjection: ContainerWriterProjectionResponse,\n ) => {\n if (\n containerProjection.containerId !== input.containerId ||\n (input.expectedOrganizationId !== undefined &&\n containerProjection.organizationId !== input.expectedOrganizationId)\n ) {\n throw new Error(\n \"Container writer projection belongs to another container or organization\",\n );\n }\n return {\n containerProjection,\n materializedPlan: await buildMaterializedDocumentCreatePlan({\n author: input.author,\n containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n signedAt: input.signedAt,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n };\n };\n\n const containerProjection =\n input.containerProjection ??\n (await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n }));\n if (!containerProjection) {\n return null;\n }\n\n try {\n return await buildWithProjection(containerProjection);\n } catch (error) {\n if (\n !shouldRetryWithFreshProjection(error, (message) =>\n message.includes(\"could not be unwrapped\"),\n )\n ) {\n throw error;\n }\n }\n\n // Only this container's projection was stale; evict just it rather than\n // wiping every cached projection.\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const refreshedProjection = await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n });\n return refreshedProjection ? buildWithProjection(refreshedProjection) : null;\n}\n\ninterface RemoteDocumentCreateInput {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n /**\n * Invoked when the create submission fails terminally (not a benign\n * adopt/stale-target conflict) — e.g. the server denies the write. Callers\n * persist the failure so the write queue can surface it.\n */\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n /**\n * The queued row holding the new document's whole content (see\n * `documentCreateSeedCandidate`). The create commits it as its seed, and the\n * caller settles the row from the response instead of syncing it.\n */\n seedUpdate?: PendingUpdateRecord | undefined;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}\n\n/**\n * A seed only saves the first sync. A refusal of the seeded create falls back\n * to the plain create once, so the row syncs as before and seeding adds no\n * failure mode. A lost response is adopted, and a stale target is replanned\n * with a fresh seed, exactly as for a plain create. Building the seed awaits\n * its encryption, so each submission rechecks the caller is still current and\n * returns null instead of creating a document whose response would be dropped.\n */\nasync function submitPlannedDocumentCreateRequest(\n input: RemoteDocumentCreateInput,\n createPlan: MaterializedDocumentCreatePlanWithProjection,\n): Promise<DocumentCreateSubmission | null> {\n const request = createPlan.materializedPlan.plan.request;\n const organizationId = createPlan.containerProjection.organizationId;\n const seed = input.seedUpdate\n ? await buildDocumentCreateSeedRequest({\n author: input.author,\n containerProjection: createPlan.containerProjection,\n materializedDocument: createPlan.materializedPlan,\n pendingUpdate: input.seedUpdate,\n })\n : null;\n if (seed && documentCreateSeedFits(seed)) {\n if (input.stillCurrent?.() === false) return null;\n const seeded = await submitDocumentCreate(\n input.apiClient,\n { ...request, initialSync: seed },\n organizationId,\n );\n if (\n seeded.ok ||\n isDocumentManifestAlreadyExistsConflict(seeded) ||\n isStaleDocumentCreateTargetConflict(seeded)\n ) {\n return seeded;\n }\n }\n if (input.stillCurrent?.() === false) return null;\n return submitDocumentCreate(input.apiClient, request, organizationId);\n}\n\nfunction isRemoteDocumentCreatePlanBlocked(\n input: RemoteDocumentCreateInput,\n createPlan: MaterializedDocumentCreatePlanWithProjection,\n): boolean {\n const organizationId = createPlan.containerProjection.organizationId;\n return input.isRemoteSyncBlocked?.(organizationId) ?? false;\n}\n\nasync function submitPlannedDocumentCreate(\n input: RemoteDocumentCreateInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<{\n readonly createPlan: MaterializedDocumentCreatePlanWithProjection;\n readonly submission: DocumentCreateSubmission;\n} | null> {\n const verificationOptions = { stillCurrent: input.stillCurrent };\n const warmReferencedPrincipalPolicies = input.warmReferencedPrincipalPolicies;\n let createPlan = await buildMaterializedDocumentCreatePlanWithFreshProjection(\n {\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n containerProjection: input.containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n },\n );\n if (!createPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, createPlan)) return null;\n if (input.stillCurrent?.() === false) return null;\n let submission = await submitPlannedDocumentCreateRequest(input, createPlan);\n if (!submission) return null;\n if (isStaleDocumentCreateTargetConflict(submission)) {\n if (input.stillCurrent?.() === false) {\n return { createPlan, submission };\n }\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const firstPlan = createPlan.materializedPlan;\n const refreshedPlan =\n await buildMaterializedDocumentCreatePlanWithFreshProjection({\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n contentKey: firstPlan.contentKey,\n contentKeyEpoch:\n firstPlan.plan.request.contentKeyBundle.contentKeyEpoch,\n documentId: firstPlan.plan.documentId,\n eventId: firstPlan.plan.event.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: firstPlan.plan.event.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n });\n if (!refreshedPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, refreshedPlan)) return null;\n createPlan = refreshedPlan;\n if (input.stillCurrent?.() === false) return null;\n submission = await submitPlannedDocumentCreateRequest(input, createPlan);\n if (!submission) return null;\n }\n return { createPlan, submission };\n}\n\nexport async function createRemoteDocument(\n input: RemoteDocumentCreateInput,\n): Promise<CreateRemoteDocumentResult | null> {\n // The store retries once the folder's own create settles.\n if (await isContainerCreatePending(input.execSql, input.containerId)) {\n return null;\n }\n const resolveProjectionUserKey = requireProjectionUserKeyResolver(\n input.resolveProjectionUserKey,\n \"Remote document create\",\n );\n const plannedSubmission = await recordDocumentAuthorAccessFailure(\n () =>\n nullOnProjectionVerificationCancellation(() =>\n submitPlannedDocumentCreate(input, resolveProjectionUserKey),\n ),\n input.onTerminalSubmitFailure,\n );\n if (!plannedSubmission) {\n return null;\n }\n const { createPlan, submission } = plannedSubmission;\n if (input.stillCurrent?.() === false) return null;\n if (submission.ok)\n return acknowledgeRemoteDocumentCreate({\n ...input,\n ...createPlan,\n resolveProjectionUserKey,\n response: submission.data,\n });\n\n // A stable documentId means a retry after a lost create response re-submits\n // the same id; the server then reports the manifest already exists. That is\n // not a failure — the first attempt committed. Adopt the existing remote\n // document instead of leaking a duplicate. Requires the stable id we sent, so\n // we can fetch its projection back.\n const stableDocumentId = input.documentId;\n if (stableDocumentId && isDocumentManifestAlreadyExistsConflict(submission)) {\n if (input.stillCurrent?.() === false) return null;\n const adopted = await nullOnProjectionVerificationCancellation(() =>\n adoptExistingRemoteDocument({\n apiClient: input.apiClient,\n documentId: stableDocumentId,\n execSql: input.execSql,\n expectedContainerId: input.containerId,\n expectedOrganizationId:\n input.expectedOrganizationId ??\n createPlan.containerProjection.organizationId,\n expectedSignerUserId: input.author.signerUserId,\n resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n );\n if (adopted) {\n return adopted;\n }\n // A conflict is the expected, benign outcome of an idempotent retry after a\n // lost create response. If adoption cannot complete yet (e.g. the writer\n // projection fetch failed transiently), do not surface the conflict as a UI\n // error — the sync engine retries and adopts it on a later tick.\n return null;\n }\n\n submission.report?.();\n await input.onTerminalSubmitFailure?.(submission);\n return null;\n}\n\ntype DocumentCreateSubmission =\n | {\n readonly data: DocumentCreateResponse;\n readonly ok: true;\n }\n | {\n readonly code?: string | undefined;\n readonly message: string;\n readonly ok: false;\n readonly report?: (() => void) | undefined;\n readonly status: number | null;\n };\n\nexport function isStaleDocumentCreateTargetConflict(\n submission: DocumentCreateSubmission,\n): boolean {\n return (\n !submission.ok &&\n submission.status === 409 &&\n submission.code === DOCUMENT_SYNC_ERROR_CODES.stateStale\n );\n}\n\nasync function submitDocumentCreate(\n apiClient: DocumentCreateApi,\n request: DocumentCreateRequest,\n expectedOrganizationId: string,\n): Promise<DocumentCreateSubmission> {\n return apiClient.createDocumentResult(request, {\n expectedPaymentRequiredOrganizationId: expectedOrganizationId,\n reportErrors: false,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentCreateRequest } from \"@tearleads/validators/request\";\nimport {\n type ContainerWriterProjectionResponse,\n DOCUMENT_SYNC_ERROR_CODES,\n type DocumentCreateResponse,\n} from \"@tearleads/validators/response\";\nimport { assertContainerAuthorAccess } from \"../../../data/containers/shared/authorAccess\";\nimport { buildDocumentCreatePlan } from \"../../../data/documents/shared/events\";\nimport { wrapDocumentContentKeyForCreate } from \"../../../data/documents/shared/projection\";\nimport type {\n CreateRemoteDocumentResult,\n DocumentCreateApi,\n DocumentCreateAuthor,\n MaterializedDocumentCreatePlan,\n ProjectionVerificationOptions,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport {\n collectContainerWriterProjectionPrincipalPolicies,\n nullOnProjectionVerificationCancellation,\n requireProjectionUserKeyResolver,\n} from \"../../../data/keyingProjectionVerification\";\nimport { isContainerCreatePending } from \"../../../data/persistence/container-contents/pendingContainerCreate\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport { recordDocumentAuthorAccessFailure } from \"../authorAccessFailure\";\nimport {\n buildDocumentCreateSeedRequest,\n documentCreateSeedFits,\n} from \"../sync/initialSync\";\nimport {\n isDocumentManifestAlreadyExistsConflict,\n shouldRetryWithFreshProjection,\n} from \"../syncFailures/syncFailureClassification\";\nimport { adoptExistingRemoteDocument } from \"./createAdoption\";\nimport type { DocumentCreateTerminalFailureHandler } from \"./createProjectionFetch\";\nimport { fetchContainerWriterProjectionForCreate } from \"./createProjectionFetch\";\nimport { acknowledgeRemoteDocumentCreate } from \"./createResponse\";\n\nexport async function buildMaterializedDocumentCreatePlan(\n input: {\n author: DocumentCreateAuthor;\n containerProjection: ContainerWriterProjectionResponse;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql?: ExecSql | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n signedAt?: string | undefined;\n targetSecretKey: Uint8Array;\n } & ProjectionVerificationOptions,\n): Promise<MaterializedDocumentCreatePlan> {\n const contentKey =\n input.contentKey ?? crypto.getRandomValues(new Uint8Array(32));\n if (contentKey.byteLength !== 32) {\n throw new Error(\"Document content key must be 32 bytes\");\n }\n // Resolved before wrapping: each envelope is sealed to its document and\n // content-key epoch.\n const documentId = input.documentId ?? crypto.randomUUID();\n const contentKeyEpoch = input.contentKeyEpoch ?? 1;\n const targetEnvelopes = await wrapDocumentContentKeyForCreate({\n contentKey,\n contentKeyEpoch,\n documentId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n projection: input.containerProjection,\n secretKey: input.targetSecretKey,\n ...projectionVerificationOptions(input),\n });\n if (input.resolveProjectionUserKey) {\n const principalPolicies =\n await collectContainerWriterProjectionPrincipalPolicies({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n projection: input.containerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n });\n assertContainerAuthorAccess({\n // Document signing derives its organization from the verified target.\n author: {\n ...input.author,\n organizationId: input.containerProjection.organizationId,\n },\n projection: input.containerProjection,\n principalPolicies,\n minimumAccess: \"write\",\n });\n }\n // The explicit local-trust variant builds provisioning artifacts before\n // their new principal policies exist remotely; remote creates cannot use it.\n const plan = await buildDocumentCreatePlan({\n author: input.author,\n containerProjection: input.containerProjection,\n contentKeyEpoch,\n documentId,\n ...(input.eventId === undefined ? {} : { eventId: input.eventId }),\n ...(input.signedAt === undefined ? {} : { signedAt: input.signedAt }),\n targetEnvelopes,\n });\n\n return {\n contentKey,\n plan,\n };\n}\n\nexport { documentWriterProjectionFromCreateResponse } from \"./createProjection\";\n\ninterface MaterializedDocumentCreatePlanWithProjection {\n readonly containerProjection: ContainerWriterProjectionResponse;\n readonly materializedPlan: MaterializedDocumentCreatePlan;\n}\n\nasync function buildMaterializedDocumentCreatePlanWithFreshProjection(input: {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<MaterializedDocumentCreatePlanWithProjection | null> {\n const buildWithProjection = async (\n containerProjection: ContainerWriterProjectionResponse,\n ) => {\n if (\n containerProjection.containerId !== input.containerId ||\n (input.expectedOrganizationId !== undefined &&\n containerProjection.organizationId !== input.expectedOrganizationId)\n ) {\n throw new Error(\n \"Container writer projection belongs to another container or organization\",\n );\n }\n return {\n containerProjection,\n materializedPlan: await buildMaterializedDocumentCreatePlan({\n author: input.author,\n containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n signedAt: input.signedAt,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n };\n };\n\n const containerProjection =\n input.containerProjection ??\n (await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n }));\n if (!containerProjection) {\n return null;\n }\n\n try {\n return await buildWithProjection(containerProjection);\n } catch (error) {\n if (\n !shouldRetryWithFreshProjection(error, (message) =>\n message.includes(\"could not be unwrapped\"),\n )\n ) {\n throw error;\n }\n }\n\n // Only this container's projection was stale; evict just it rather than\n // wiping every cached projection.\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const refreshedProjection = await fetchContainerWriterProjectionForCreate({\n apiClient: input.apiClient,\n containerId: input.containerId,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n });\n return refreshedProjection ? buildWithProjection(refreshedProjection) : null;\n}\n\ninterface RemoteDocumentCreateInput {\n apiClient: DocumentCreateApi;\n author: DocumentCreateAuthor;\n containerId: string;\n containerProjection?: ContainerWriterProjectionResponse | undefined;\n contentKey?: Uint8Array | undefined;\n contentKeyEpoch?: number | undefined;\n documentId?: string | undefined;\n eventId?: string | undefined;\n execSql: ExecSql;\n expectedOrganizationId?: string | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n /**\n * Invoked when the create submission fails terminally (not a benign\n * adopt/stale-target conflict) — e.g. the server denies the write. Callers\n * persist the failure so the write queue can surface it.\n */\n onTerminalSubmitFailure?: DocumentCreateTerminalFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n /**\n * The queued row holding the new document's whole content (see\n * `documentCreateSeedCandidate`). The create commits it as its seed, and the\n * caller settles the row from the response instead of syncing it.\n */\n seedUpdate?: PendingUpdateRecord | undefined;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}\n\n/**\n * A seed only saves the first sync. A refusal of the seeded create falls back\n * to the plain create once, so the row syncs as before and seeding adds no\n * failure mode. A lost response is adopted, and a stale target is replanned\n * with a fresh seed, exactly as for a plain create. Building the seed awaits\n * its encryption, so each submission rechecks the caller is still current and\n * returns null instead of creating a document whose response would be dropped.\n */\nasync function submitPlannedDocumentCreateRequest(\n input: RemoteDocumentCreateInput,\n createPlan: MaterializedDocumentCreatePlanWithProjection,\n): Promise<DocumentCreateSubmission | null> {\n const request = createPlan.materializedPlan.plan.request;\n const organizationId = createPlan.containerProjection.organizationId;\n const seed = input.seedUpdate\n ? await buildDocumentCreateSeedRequest({\n author: input.author,\n containerProjection: createPlan.containerProjection,\n materializedDocument: createPlan.materializedPlan,\n pendingUpdate: input.seedUpdate,\n })\n : null;\n if (seed && documentCreateSeedFits(seed)) {\n if (input.stillCurrent?.() === false) return null;\n const seeded = await submitDocumentCreate(\n input.apiClient,\n { ...request, initialSync: seed },\n organizationId,\n );\n if (\n seeded.ok ||\n isDocumentManifestAlreadyExistsConflict(seeded) ||\n isStaleDocumentCreateTargetConflict(seeded)\n ) {\n return seeded;\n }\n }\n if (input.stillCurrent?.() === false) return null;\n return submitDocumentCreate(input.apiClient, request, organizationId);\n}\n\nfunction isRemoteDocumentCreatePlanBlocked(\n input: RemoteDocumentCreateInput,\n createPlan: MaterializedDocumentCreatePlanWithProjection,\n): boolean {\n const organizationId = createPlan.containerProjection.organizationId;\n return input.isRemoteSyncBlocked?.(organizationId) ?? false;\n}\n\nasync function submitPlannedDocumentCreate(\n input: RemoteDocumentCreateInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<{\n readonly createPlan: MaterializedDocumentCreatePlanWithProjection;\n readonly submission: DocumentCreateSubmission;\n} | null> {\n const verificationOptions = { stillCurrent: input.stillCurrent };\n const warmReferencedPrincipalPolicies = input.warmReferencedPrincipalPolicies;\n let createPlan = await buildMaterializedDocumentCreatePlanWithFreshProjection(\n {\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n containerProjection: input.containerProjection,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n eventId: input.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n },\n );\n if (!createPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, createPlan)) return null;\n if (input.stillCurrent?.() === false) return null;\n let submission = await submitPlannedDocumentCreateRequest(input, createPlan);\n if (!submission) return null;\n if (isStaleDocumentCreateTargetConflict(submission)) {\n if (input.stillCurrent?.() === false) {\n return { createPlan, submission };\n }\n input.apiClient.evictContainerWriterProjection(input.containerId);\n const firstPlan = createPlan.materializedPlan;\n const refreshedPlan =\n await buildMaterializedDocumentCreatePlanWithFreshProjection({\n apiClient: input.apiClient,\n author: input.author,\n containerId: input.containerId,\n contentKey: firstPlan.contentKey,\n contentKeyEpoch:\n firstPlan.plan.request.contentKeyBundle.contentKeyEpoch,\n documentId: firstPlan.plan.documentId,\n eventId: firstPlan.plan.event.eventId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n knownContainerKeks: input.knownContainerKeks,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n resolveProjectionUserKey,\n signedAt: firstPlan.plan.event.signedAt,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies,\n ...verificationOptions,\n });\n if (!refreshedPlan) {\n return null;\n }\n if (isRemoteDocumentCreatePlanBlocked(input, refreshedPlan)) return null;\n createPlan = refreshedPlan;\n if (input.stillCurrent?.() === false) return null;\n submission = await submitPlannedDocumentCreateRequest(input, createPlan);\n if (!submission) return null;\n }\n return { createPlan, submission };\n}\n\nexport async function createRemoteDocument(\n input: RemoteDocumentCreateInput,\n): Promise<CreateRemoteDocumentResult | null> {\n // The store retries once the folder's own create settles.\n if (await isContainerCreatePending(input.execSql, input.containerId)) {\n return null;\n }\n const resolveProjectionUserKey = requireProjectionUserKeyResolver(\n input.resolveProjectionUserKey,\n \"Remote document create\",\n );\n const plannedSubmission = await recordDocumentAuthorAccessFailure(\n () =>\n nullOnProjectionVerificationCancellation(() =>\n submitPlannedDocumentCreate(input, resolveProjectionUserKey),\n ),\n input.onTerminalSubmitFailure,\n );\n if (!plannedSubmission) {\n return null;\n }\n const { createPlan, submission } = plannedSubmission;\n if (input.stillCurrent?.() === false) return null;\n if (submission.ok)\n return acknowledgeRemoteDocumentCreate({\n ...input,\n ...createPlan,\n resolveProjectionUserKey,\n response: submission.data,\n });\n\n // A stable documentId means a retry after a lost create response re-submits\n // the same id; the server then reports the manifest already exists. That is\n // not a failure — the first attempt committed. Adopt the existing remote\n // document instead of leaking a duplicate. Requires the stable id we sent, so\n // we can fetch its projection back.\n const stableDocumentId = input.documentId;\n if (stableDocumentId && isDocumentManifestAlreadyExistsConflict(submission)) {\n if (input.stillCurrent?.() === false) return null;\n const adopted = await nullOnProjectionVerificationCancellation(() =>\n adoptExistingRemoteDocument({\n apiClient: input.apiClient,\n documentId: stableDocumentId,\n execSql: input.execSql,\n expectedContainerId: input.containerId,\n expectedOrganizationId:\n input.expectedOrganizationId ??\n createPlan.containerProjection.organizationId,\n expectedSignerUserId: input.author.signerUserId,\n resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n );\n if (adopted) {\n return adopted;\n }\n // A conflict is the expected, benign outcome of an idempotent retry after a\n // lost create response. If adoption cannot complete yet (e.g. the writer\n // projection fetch failed transiently), do not surface the conflict as a UI\n // error — the sync engine retries and adopts it on a later tick.\n return null;\n }\n\n submission.report?.();\n await input.onTerminalSubmitFailure?.(submission);\n return null;\n}\n\ntype DocumentCreateSubmission =\n | {\n readonly data: DocumentCreateResponse;\n readonly ok: true;\n }\n | {\n readonly code?: string | undefined;\n readonly message: string;\n readonly ok: false;\n readonly report?: (() => void) | undefined;\n readonly status: number | null;\n };\n\nexport function isStaleDocumentCreateTargetConflict(\n submission: DocumentCreateSubmission,\n): boolean {\n return (\n !submission.ok &&\n submission.status === 409 &&\n submission.code === DOCUMENT_SYNC_ERROR_CODES.stateStale\n );\n}\n\nasync function submitDocumentCreate(\n apiClient: DocumentCreateApi,\n request: DocumentCreateRequest,\n expectedOrganizationId: string,\n): Promise<DocumentCreateSubmission> {\n return apiClient.createDocumentResult(request, {\n expectedPaymentRequiredOrganizationId: expectedOrganizationId,\n reportErrors: false,\n });\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type DocumentProjectorRegistry, type DocumentProjectorRegistryInput } from "../../data/documents/documentKinds.js";
|
|
2
2
|
import type { DocumentsPersistence, StoredDocumentRecord } from "../../data/persistence/documents/documentsPersistence.js";
|
|
3
|
-
import type { PendingUpdateFields } from "../../data/
|
|
3
|
+
import type { PendingUpdateFields } from "../../data/persistence/documents/records/index.js";
|
|
4
4
|
import type { ExecSql } from "../../data/sqlite/sqlSchema.js";
|
|
5
5
|
import { type PrepareDocumentMutationInput } from "./documentMutationPreparation.js";
|
|
6
6
|
export interface PersistedDocumentState {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentMutationCommit.js","sourceRoot":"","sources":["documentMutationCommit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type encodeVersionVector, getTextValue } from \"@tearleads/loro\";\nimport {\n DEFAULT_DOCUMENT_ACCESS_EPOCH,\n DEFAULT_DOCUMENT_KIND,\n} from \"../../data/documents/documentConstants\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n readStoredDocumentState,\n} from \"../../data/documents/documentKinds\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { PendingUpdateFields } from \"../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { createInitialDocumentRows } from \"./create/documentCreationPersistence\";\nimport {\n documentSyncSecurityContextMatches,\n type PrepareDocumentMutationInput,\n prepareDocumentMutation,\n} from \"./documentMutationPreparation\";\nimport { refuseDeletedDocumentPersist } from \"./documentPersistGuards\";\n\ntype DocumentContentState = Parameters<typeof encodeVersionVector>[0];\ntype NullableDocumentRuntimeField =\n | \"accessStateHash\"\n | \"lastCommitLsn\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\";\n\nconst MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS = 8;\n\nexport interface PersistedDocumentState {\n creationSuperseded?: true;\n historyRestoreState?:\n | Awaited<ReturnType<DocumentsPersistence[\"loadHistoryRestoreState\"]>>\n | undefined;\n pullContinuationSuperseded?: true;\n record: StoredDocumentRecord;\n syncIdentitySuperseded?: true;\n updatedAt?: string | undefined;\n}\n\nexport interface PersistDocumentStateInput\n extends PrepareDocumentMutationInput {\n acceptedPendingUpdateIds?: readonly string[] | undefined;\n attachmentRemoval?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentRemoval\"]\n | undefined;\n attachmentStaging?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentStaging\"]\n | undefined;\n canStartDurableMutation?: (() => boolean) | undefined;\n clearSyncFailure?: boolean | undefined;\n commitSideEffect?: (transactionExecSql: ExecSql) => Promise<void>;\n containerId?: string | null | undefined;\n documentProjectors: DocumentProjectorRegistryInput;\n execSql: ExecSql;\n patch?: Partial<StoredDocumentRecord> | undefined;\n pendingUpdate?: PendingUpdateFields | undefined;\n}\n\nasync function loadSupersededPersistedDocumentState(input: {\n creationSuperseded: boolean;\n execSql: ExecSql;\n localId: string;\n persistence: DocumentsPersistence;\n record: StoredDocumentRecord;\n syncIdentitySuperseded: boolean;\n}): Promise<PersistedDocumentState | null> {\n const { document, historyRestoreState } =\n await input.persistence.loadDocumentWithHistoryRestoreState(\n input.execSql,\n input.localId,\n );\n if (!document) return null;\n const syncIdentitySuperseded =\n input.syncIdentitySuperseded ||\n !documentSyncSecurityContextMatches(document, input.record);\n return {\n ...(input.creationSuperseded ? { creationSuperseded: true as const } : {}),\n historyRestoreState,\n pullContinuationSuperseded: true,\n record: document,\n ...(syncIdentitySuperseded\n ? { syncIdentitySuperseded: true as const }\n : {}),\n };\n}\n\nfunction resolveNullableDocumentRuntimeField(\n patch: Partial<StoredDocumentRecord>,\n key: NullableDocumentRuntimeField,\n currentValue: string | null | undefined,\n resetWhenUnpatched = false,\n): string | null {\n if (Object.hasOwn(patch, key)) return patch[key] ?? null;\n return resetWhenUnpatched ? null : (currentValue ?? null);\n}\n\nfunction resolveStoredDocumentContainerId(input: {\n containerId?: string | null | undefined;\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n}): string | null {\n if (Object.hasOwn(input.patch, \"containerId\")) {\n return input.patch.containerId ?? null;\n }\n return input.currentRecord?.containerId ?? input.containerId ?? null;\n}\n\nfunction resolveStoredDocumentPullState(input: {\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n securityContextChanged: boolean;\n}): Pick<\n StoredDocumentRecord,\n \"pullContinuation\" | \"pullContinuationRecoveryRequired\"\n> {\n if (Object.hasOwn(input.patch, \"pullContinuation\")) {\n return { pullContinuation: input.patch.pullContinuation ?? null };\n }\n if (input.securityContextChanged) return { pullContinuation: null };\n if (input.currentRecord?.pullContinuationRecoveryRequired) {\n return { pullContinuationRecoveryRequired: true };\n }\n return { pullContinuation: input.currentRecord?.pullContinuation ?? null };\n}\n\nfunction buildStoredDocumentRecord(input: {\n containerId?: string | null | undefined;\n currentDoc: DocumentContentState;\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n localId: string;\n patch: Partial<StoredDocumentRecord>;\n}) {\n const { currentDoc, currentRecord, documentProjectors, localId, patch } =\n input;\n const currentDocumentId = currentRecord?.documentId ?? null;\n const nextDocumentId = patch.documentId ?? currentDocumentId;\n const documentIdChanged = nextDocumentId !== currentDocumentId;\n const currentAccessEpoch =\n currentRecord?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH;\n const nextAccessEpoch = patch.accessEpoch ?? currentAccessEpoch;\n const securityContextChanged =\n documentIdChanged || nextAccessEpoch !== currentAccessEpoch;\n const documentState = readStoredDocumentState(currentDoc, documentProjectors);\n const record: StoredDocumentRecord = {\n id: currentRecord?.id ?? localId,\n accessEpoch: nextAccessEpoch,\n accessStateHash: resolveNullableDocumentRuntimeField(\n patch,\n \"accessStateHash\",\n currentRecord?.accessStateHash,\n securityContextChanged,\n ),\n containerId: resolveStoredDocumentContainerId({\n containerId: input.containerId,\n currentRecord,\n patch,\n }),\n contentKeyBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"contentKeyBundle\",\n currentRecord?.contentKeyBundle,\n securityContextChanged,\n ),\n documentId: nextDocumentId,\n effectiveAccessLevel:\n patch.effectiveAccessLevel ?? currentRecord?.effectiveAccessLevel ?? null,\n documentKekTargets: resolveNullableDocumentRuntimeField(\n patch,\n \"documentKekTargets\",\n currentRecord?.documentKekTargets,\n securityContextChanged,\n ),\n documentKind: patch.documentKind ?? documentState.documentKind,\n documentManifestBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"documentManifestBundle\",\n currentRecord?.documentManifestBundle,\n securityContextChanged,\n ),\n lastCommitLsn: resolveNullableDocumentRuntimeField(\n patch,\n \"lastCommitLsn\",\n currentRecord?.lastCommitLsn,\n documentIdChanged,\n ),\n snapshotEndVersion:\n patch.snapshotEndVersion ?? currentRecord?.snapshotEndVersion ?? \"\",\n pendingBaseVersion:\n patch.pendingBaseVersion !== undefined\n ? patch.pendingBaseVersion\n : (currentRecord?.pendingBaseVersion ?? null),\n recoveryGeneration:\n patch.recoveryGeneration ?? currentRecord?.recoveryGeneration ?? 0,\n ...resolveStoredDocumentPullState({\n currentRecord,\n patch,\n securityContextChanged,\n }),\n text: patch.text ?? getTextValue(currentDoc),\n title: patch.title ?? documentState.title,\n };\n return { documentState, record };\n}\n\nasync function saveDocumentClientProjection(input: {\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n documentState: ReturnType<typeof readStoredDocumentState>;\n execSql: ExecSql;\n localId: string;\n record: StoredDocumentRecord;\n updatedAt: string;\n}): Promise<void> {\n const previousKind =\n input.currentRecord?.documentKind ?? DEFAULT_DOCUMENT_KIND;\n const nextKind = input.record.documentKind ?? DEFAULT_DOCUMENT_KIND;\n if (previousKind !== nextKind) {\n await input.documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: previousKind,\n execSql: input.execSql,\n localId: input.localId,\n });\n }\n await input.documentProjectors.saveStoredDocumentClientProjection({\n containerId: input.record.containerId,\n documentId: input.record.documentId,\n documentKind: nextKind,\n execSql: input.execSql,\n localId: input.record.id,\n structuredFields: input.documentState.structuredFields,\n text: input.record.text,\n title: input.record.title ?? input.documentState.title,\n updatedAt: input.updatedAt,\n });\n}\n\nasync function settleSupersededDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n lockedExecSql: ExecSql;\n mutation: Awaited<ReturnType<typeof prepareDocumentMutation>>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { mutation, persistInput } = input;\n if (!mutation.mutationCurrentRecord) return null;\n const authoritativeRecord = persistInput.expectedSyncState\n ? await persistInput.persistence.settleAcceptedPendingUpdates(\n input.lockedExecSql,\n {\n expectedRecord: persistInput.expectedSyncState.record,\n pendingUpdateIds: input.acceptedPendingUpdateIds,\n },\n )\n : mutation.mutationCurrentRecord;\n if (!authoritativeRecord) return null;\n return loadSupersededPersistedDocumentState({\n creationSuperseded: mutation.creationSuperseded,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: authoritativeRecord,\n syncIdentitySuperseded: !mutation.securityContextMatches,\n });\n}\n\nasync function loadConcurrentCreationWinner(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState> {\n const winningRecord = await input.persistInput.persistence.loadDocument(\n input.execSql,\n input.persistInput.localId,\n );\n if (!winningRecord) {\n throw new Error(\"Concurrent document creation lost without a winner\");\n }\n const winner = await loadSupersededPersistedDocumentState({\n creationSuperseded: true,\n execSql: input.execSql,\n localId: input.persistInput.localId,\n persistence: input.persistInput.persistence,\n record: winningRecord,\n syncIdentitySuperseded: true,\n });\n if (!winner) {\n throw new Error(\"Concurrent document creation winner disappeared\");\n }\n return winner;\n}\n\nasync function resolveInitialDocumentCreation(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n savedAt: string | null;\n}): Promise<PersistedDocumentState | null> {\n if (input.savedAt !== null) {\n return { record: input.record, updatedAt: input.savedAt };\n }\n if (\n input.persistInput.canStartDurableMutation &&\n !input.persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n return loadConcurrentCreationWinner({\n execSql: input.execSql,\n persistInput: input.persistInput,\n });\n}\n\nasync function resolveDocumentMutationCommit(input: {\n committed: Awaited<\n ReturnType<DocumentsPersistence[\"commitDocumentMutation\"]>\n >;\n lockedExecSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { committed, persistInput, record } = input;\n if (\n persistInput.canStartDurableMutation &&\n !persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n if (committed.committed) return { record, updatedAt: committed.updatedAt };\n if (!committed.currentRecord) return null;\n if (persistInput.expectedSyncState === undefined) return \"retry\";\n return loadSupersededPersistedDocumentState({\n creationSuperseded: false,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: committed.currentRecord,\n syncIdentitySuperseded: !documentSyncSecurityContextMatches(\n committed.currentRecord,\n persistInput.expectedSyncState.record,\n ),\n });\n}\n\nasync function commitOnePreparedDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n mutation: Exclude<\n Awaited<ReturnType<typeof prepareDocumentMutation>>,\n { pullContinuationSuperseded: true }\n >;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { mutation, persistInput } = input;\n const { documentState, record } = buildStoredDocumentRecord({\n containerId: persistInput.containerId,\n currentDoc: persistInput.currentDoc,\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n localId: persistInput.localId,\n patch: mutation.resolvedPatch,\n });\n if (!mutation.mutationCurrentRecord) {\n const savedAt = await createInitialDocumentRows({\n currentDoc: persistInput.currentDoc,\n execSql: input.lockedExecSql,\n pendingUpdate: persistInput.pendingUpdate,\n persistence: persistInput.persistence,\n record,\n stillCurrent: persistInput.canStartDurableMutation,\n saveClientProjection: (transactionExecSql, updatedAt) =>\n saveDocumentClientProjection({\n currentRecord: null,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n }),\n });\n return resolveInitialDocumentCreation({\n execSql: input.lockedExecSql,\n persistInput,\n record,\n savedAt,\n });\n }\n\n const committed = await persistInput.persistence.commitDocumentMutation(\n input.lockedExecSql,\n {\n acceptedPendingUpdateIds: input.acceptedPendingUpdateIds,\n clearSyncFailure: persistInput.clearSyncFailure,\n ...(persistInput.attachmentRemoval\n ? { attachmentRemoval: persistInput.attachmentRemoval }\n : {}),\n ...(persistInput.attachmentStaging\n ? { attachmentStaging: persistInput.attachmentStaging }\n : {}),\n document: record,\n expectedRecord: mutation.mutationCurrentRecord,\n ...(persistInput.historyCheckpoint\n ? { historyCheckpoint: persistInput.historyCheckpoint }\n : {}),\n ...(persistInput.historyUpdateOrigin\n ? { historyUpdateOrigin: persistInput.historyUpdateOrigin }\n : {}),\n ...(persistInput.historyUpdates\n ? { historyUpdates: persistInput.historyUpdates }\n : {}),\n ...(persistInput.pendingUpdate\n ? { pendingUpdate: persistInput.pendingUpdate }\n : {}),\n settleAcceptedPendingOnConflict:\n persistInput.expectedSyncState !== undefined,\n ...(persistInput.canStartDurableMutation\n ? { stillCurrent: persistInput.canStartDurableMutation }\n : {}),\n },\n async (transactionExecSql, updatedAt) => {\n await saveDocumentClientProjection({\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n });\n await persistInput.commitSideEffect?.(transactionExecSql);\n },\n );\n return resolveDocumentMutationCommit({\n committed,\n lockedExecSql: input.lockedExecSql,\n persistInput,\n record,\n });\n}\n\nexport async function commitPreparedDocumentState(input: {\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n patch: Partial<StoredDocumentRecord>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { lockedExecSql, persistInput } = input;\n if (\n await refuseDeletedDocumentPersist({\n currentRecord: persistInput.currentRecord,\n documentProjectors: input.documentProjectors,\n execSql: lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n })\n ) {\n return null;\n }\n const acceptedPendingUpdateIds = persistInput.acceptedPendingUpdateIds ?? [];\n for (\n let attempt = 0;\n attempt < MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS;\n attempt += 1\n ) {\n const mutation = await prepareDocumentMutation(\n persistInput,\n lockedExecSql,\n input.patch,\n );\n if (mutation.pullContinuationSuperseded) {\n return settleSupersededDocumentMutation({\n acceptedPendingUpdateIds,\n lockedExecSql,\n mutation,\n persistInput,\n });\n }\n const result = await commitOnePreparedDocumentMutation({\n acceptedPendingUpdateIds,\n documentProjectors: input.documentProjectors,\n lockedExecSql,\n mutation,\n persistInput,\n });\n if (result !== \"retry\") return result;\n }\n throw new Error(\n `Document mutation commit gave up after ${MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS} concurrent conflicts`,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"documentMutationCommit.js","sourceRoot":"","sources":["documentMutationCommit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type encodeVersionVector, getTextValue } from \"@tearleads/loro\";\nimport {\n DEFAULT_DOCUMENT_ACCESS_EPOCH,\n DEFAULT_DOCUMENT_KIND,\n} from \"../../data/documents/documentConstants\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n readStoredDocumentState,\n} from \"../../data/documents/documentKinds\";\nimport type {\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../../data/persistence/documents/documentsPersistence\";\nimport type { PendingUpdateFields } from \"../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { createInitialDocumentRows } from \"./create/documentCreationPersistence\";\nimport {\n documentSyncSecurityContextMatches,\n type PrepareDocumentMutationInput,\n prepareDocumentMutation,\n} from \"./documentMutationPreparation\";\nimport { refuseDeletedDocumentPersist } from \"./documentPersistGuards\";\n\ntype DocumentContentState = Parameters<typeof encodeVersionVector>[0];\ntype NullableDocumentRuntimeField =\n | \"accessStateHash\"\n | \"lastCommitLsn\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\";\n\nconst MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS = 8;\n\nexport interface PersistedDocumentState {\n creationSuperseded?: true;\n historyRestoreState?:\n | Awaited<ReturnType<DocumentsPersistence[\"loadHistoryRestoreState\"]>>\n | undefined;\n pullContinuationSuperseded?: true;\n record: StoredDocumentRecord;\n syncIdentitySuperseded?: true;\n updatedAt?: string | undefined;\n}\n\nexport interface PersistDocumentStateInput\n extends PrepareDocumentMutationInput {\n acceptedPendingUpdateIds?: readonly string[] | undefined;\n attachmentRemoval?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentRemoval\"]\n | undefined;\n attachmentStaging?:\n | Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"attachmentStaging\"]\n | undefined;\n canStartDurableMutation?: (() => boolean) | undefined;\n clearSyncFailure?: boolean | undefined;\n commitSideEffect?: (transactionExecSql: ExecSql) => Promise<void>;\n containerId?: string | null | undefined;\n documentProjectors: DocumentProjectorRegistryInput;\n execSql: ExecSql;\n patch?: Partial<StoredDocumentRecord> | undefined;\n pendingUpdate?: PendingUpdateFields | undefined;\n}\n\nasync function loadSupersededPersistedDocumentState(input: {\n creationSuperseded: boolean;\n execSql: ExecSql;\n localId: string;\n persistence: DocumentsPersistence;\n record: StoredDocumentRecord;\n syncIdentitySuperseded: boolean;\n}): Promise<PersistedDocumentState | null> {\n const { document, historyRestoreState } =\n await input.persistence.loadDocumentWithHistoryRestoreState(\n input.execSql,\n input.localId,\n );\n if (!document) return null;\n const syncIdentitySuperseded =\n input.syncIdentitySuperseded ||\n !documentSyncSecurityContextMatches(document, input.record);\n return {\n ...(input.creationSuperseded ? { creationSuperseded: true as const } : {}),\n historyRestoreState,\n pullContinuationSuperseded: true,\n record: document,\n ...(syncIdentitySuperseded\n ? { syncIdentitySuperseded: true as const }\n : {}),\n };\n}\n\nfunction resolveNullableDocumentRuntimeField(\n patch: Partial<StoredDocumentRecord>,\n key: NullableDocumentRuntimeField,\n currentValue: string | null | undefined,\n resetWhenUnpatched = false,\n): string | null {\n if (Object.hasOwn(patch, key)) return patch[key] ?? null;\n return resetWhenUnpatched ? null : (currentValue ?? null);\n}\n\nfunction resolveStoredDocumentContainerId(input: {\n containerId?: string | null | undefined;\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n}): string | null {\n if (Object.hasOwn(input.patch, \"containerId\")) {\n return input.patch.containerId ?? null;\n }\n return input.currentRecord?.containerId ?? input.containerId ?? null;\n}\n\nfunction resolveStoredDocumentPullState(input: {\n currentRecord: StoredDocumentRecord | null;\n patch: Partial<StoredDocumentRecord>;\n securityContextChanged: boolean;\n}): Pick<\n StoredDocumentRecord,\n \"pullContinuation\" | \"pullContinuationRecoveryRequired\"\n> {\n if (Object.hasOwn(input.patch, \"pullContinuation\")) {\n return { pullContinuation: input.patch.pullContinuation ?? null };\n }\n if (input.securityContextChanged) return { pullContinuation: null };\n if (input.currentRecord?.pullContinuationRecoveryRequired) {\n return { pullContinuationRecoveryRequired: true };\n }\n return { pullContinuation: input.currentRecord?.pullContinuation ?? null };\n}\n\nfunction buildStoredDocumentRecord(input: {\n containerId?: string | null | undefined;\n currentDoc: DocumentContentState;\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n localId: string;\n patch: Partial<StoredDocumentRecord>;\n}) {\n const { currentDoc, currentRecord, documentProjectors, localId, patch } =\n input;\n const currentDocumentId = currentRecord?.documentId ?? null;\n const nextDocumentId = patch.documentId ?? currentDocumentId;\n const documentIdChanged = nextDocumentId !== currentDocumentId;\n const currentAccessEpoch =\n currentRecord?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH;\n const nextAccessEpoch = patch.accessEpoch ?? currentAccessEpoch;\n const securityContextChanged =\n documentIdChanged || nextAccessEpoch !== currentAccessEpoch;\n const documentState = readStoredDocumentState(currentDoc, documentProjectors);\n const record: StoredDocumentRecord = {\n id: currentRecord?.id ?? localId,\n accessEpoch: nextAccessEpoch,\n accessStateHash: resolveNullableDocumentRuntimeField(\n patch,\n \"accessStateHash\",\n currentRecord?.accessStateHash,\n securityContextChanged,\n ),\n containerId: resolveStoredDocumentContainerId({\n containerId: input.containerId,\n currentRecord,\n patch,\n }),\n contentKeyBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"contentKeyBundle\",\n currentRecord?.contentKeyBundle,\n securityContextChanged,\n ),\n documentId: nextDocumentId,\n effectiveAccessLevel:\n patch.effectiveAccessLevel ?? currentRecord?.effectiveAccessLevel ?? null,\n documentKekTargets: resolveNullableDocumentRuntimeField(\n patch,\n \"documentKekTargets\",\n currentRecord?.documentKekTargets,\n securityContextChanged,\n ),\n documentKind: patch.documentKind ?? documentState.documentKind,\n documentManifestBundle: resolveNullableDocumentRuntimeField(\n patch,\n \"documentManifestBundle\",\n currentRecord?.documentManifestBundle,\n securityContextChanged,\n ),\n lastCommitLsn: resolveNullableDocumentRuntimeField(\n patch,\n \"lastCommitLsn\",\n currentRecord?.lastCommitLsn,\n documentIdChanged,\n ),\n snapshotEndVersion:\n patch.snapshotEndVersion ?? currentRecord?.snapshotEndVersion ?? \"\",\n pendingBaseVersion:\n patch.pendingBaseVersion !== undefined\n ? patch.pendingBaseVersion\n : (currentRecord?.pendingBaseVersion ?? null),\n recoveryGeneration:\n patch.recoveryGeneration ?? currentRecord?.recoveryGeneration ?? 0,\n ...resolveStoredDocumentPullState({\n currentRecord,\n patch,\n securityContextChanged,\n }),\n text: patch.text ?? getTextValue(currentDoc),\n title: patch.title ?? documentState.title,\n };\n return { documentState, record };\n}\n\nasync function saveDocumentClientProjection(input: {\n currentRecord: StoredDocumentRecord | null;\n documentProjectors: DocumentProjectorRegistry;\n documentState: ReturnType<typeof readStoredDocumentState>;\n execSql: ExecSql;\n localId: string;\n record: StoredDocumentRecord;\n updatedAt: string;\n}): Promise<void> {\n const previousKind =\n input.currentRecord?.documentKind ?? DEFAULT_DOCUMENT_KIND;\n const nextKind = input.record.documentKind ?? DEFAULT_DOCUMENT_KIND;\n if (previousKind !== nextKind) {\n await input.documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: previousKind,\n execSql: input.execSql,\n localId: input.localId,\n });\n }\n await input.documentProjectors.saveStoredDocumentClientProjection({\n containerId: input.record.containerId,\n documentId: input.record.documentId,\n documentKind: nextKind,\n execSql: input.execSql,\n localId: input.record.id,\n structuredFields: input.documentState.structuredFields,\n text: input.record.text,\n title: input.record.title ?? input.documentState.title,\n updatedAt: input.updatedAt,\n });\n}\n\nasync function settleSupersededDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n lockedExecSql: ExecSql;\n mutation: Awaited<ReturnType<typeof prepareDocumentMutation>>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { mutation, persistInput } = input;\n if (!mutation.mutationCurrentRecord) return null;\n const authoritativeRecord = persistInput.expectedSyncState\n ? await persistInput.persistence.settleAcceptedPendingUpdates(\n input.lockedExecSql,\n {\n expectedRecord: persistInput.expectedSyncState.record,\n pendingUpdateIds: input.acceptedPendingUpdateIds,\n },\n )\n : mutation.mutationCurrentRecord;\n if (!authoritativeRecord) return null;\n return loadSupersededPersistedDocumentState({\n creationSuperseded: mutation.creationSuperseded,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: authoritativeRecord,\n syncIdentitySuperseded: !mutation.securityContextMatches,\n });\n}\n\nasync function loadConcurrentCreationWinner(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState> {\n const winningRecord = await input.persistInput.persistence.loadDocument(\n input.execSql,\n input.persistInput.localId,\n );\n if (!winningRecord) {\n throw new Error(\"Concurrent document creation lost without a winner\");\n }\n const winner = await loadSupersededPersistedDocumentState({\n creationSuperseded: true,\n execSql: input.execSql,\n localId: input.persistInput.localId,\n persistence: input.persistInput.persistence,\n record: winningRecord,\n syncIdentitySuperseded: true,\n });\n if (!winner) {\n throw new Error(\"Concurrent document creation winner disappeared\");\n }\n return winner;\n}\n\nasync function resolveInitialDocumentCreation(input: {\n execSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n savedAt: string | null;\n}): Promise<PersistedDocumentState | null> {\n if (input.savedAt !== null) {\n return { record: input.record, updatedAt: input.savedAt };\n }\n if (\n input.persistInput.canStartDurableMutation &&\n !input.persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n return loadConcurrentCreationWinner({\n execSql: input.execSql,\n persistInput: input.persistInput,\n });\n}\n\nasync function resolveDocumentMutationCommit(input: {\n committed: Awaited<\n ReturnType<DocumentsPersistence[\"commitDocumentMutation\"]>\n >;\n lockedExecSql: ExecSql;\n persistInput: PersistDocumentStateInput;\n record: StoredDocumentRecord;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { committed, persistInput, record } = input;\n if (\n persistInput.canStartDurableMutation &&\n !persistInput.canStartDurableMutation()\n ) {\n return null;\n }\n if (committed.committed) return { record, updatedAt: committed.updatedAt };\n if (!committed.currentRecord) return null;\n if (persistInput.expectedSyncState === undefined) return \"retry\";\n return loadSupersededPersistedDocumentState({\n creationSuperseded: false,\n execSql: input.lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n record: committed.currentRecord,\n syncIdentitySuperseded: !documentSyncSecurityContextMatches(\n committed.currentRecord,\n persistInput.expectedSyncState.record,\n ),\n });\n}\n\nasync function commitOnePreparedDocumentMutation(input: {\n acceptedPendingUpdateIds: readonly string[];\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n mutation: Exclude<\n Awaited<ReturnType<typeof prepareDocumentMutation>>,\n { pullContinuationSuperseded: true }\n >;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null | \"retry\"> {\n const { mutation, persistInput } = input;\n const { documentState, record } = buildStoredDocumentRecord({\n containerId: persistInput.containerId,\n currentDoc: persistInput.currentDoc,\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n localId: persistInput.localId,\n patch: mutation.resolvedPatch,\n });\n if (!mutation.mutationCurrentRecord) {\n const savedAt = await createInitialDocumentRows({\n currentDoc: persistInput.currentDoc,\n execSql: input.lockedExecSql,\n pendingUpdate: persistInput.pendingUpdate,\n persistence: persistInput.persistence,\n record,\n stillCurrent: persistInput.canStartDurableMutation,\n saveClientProjection: (transactionExecSql, updatedAt) =>\n saveDocumentClientProjection({\n currentRecord: null,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n }),\n });\n return resolveInitialDocumentCreation({\n execSql: input.lockedExecSql,\n persistInput,\n record,\n savedAt,\n });\n }\n\n const committed = await persistInput.persistence.commitDocumentMutation(\n input.lockedExecSql,\n {\n acceptedPendingUpdateIds: input.acceptedPendingUpdateIds,\n clearSyncFailure: persistInput.clearSyncFailure,\n ...(persistInput.attachmentRemoval\n ? { attachmentRemoval: persistInput.attachmentRemoval }\n : {}),\n ...(persistInput.attachmentStaging\n ? { attachmentStaging: persistInput.attachmentStaging }\n : {}),\n document: record,\n expectedRecord: mutation.mutationCurrentRecord,\n ...(persistInput.historyCheckpoint\n ? { historyCheckpoint: persistInput.historyCheckpoint }\n : {}),\n ...(persistInput.historyUpdateOrigin\n ? { historyUpdateOrigin: persistInput.historyUpdateOrigin }\n : {}),\n ...(persistInput.historyUpdates\n ? { historyUpdates: persistInput.historyUpdates }\n : {}),\n ...(persistInput.pendingUpdate\n ? { pendingUpdate: persistInput.pendingUpdate }\n : {}),\n settleAcceptedPendingOnConflict:\n persistInput.expectedSyncState !== undefined,\n ...(persistInput.canStartDurableMutation\n ? { stillCurrent: persistInput.canStartDurableMutation }\n : {}),\n },\n async (transactionExecSql, updatedAt) => {\n await saveDocumentClientProjection({\n currentRecord: mutation.mutationCurrentRecord,\n documentProjectors: input.documentProjectors,\n documentState,\n execSql: transactionExecSql,\n localId: persistInput.localId,\n record,\n updatedAt,\n });\n await persistInput.commitSideEffect?.(transactionExecSql);\n },\n );\n return resolveDocumentMutationCommit({\n committed,\n lockedExecSql: input.lockedExecSql,\n persistInput,\n record,\n });\n}\n\nexport async function commitPreparedDocumentState(input: {\n documentProjectors: DocumentProjectorRegistry;\n lockedExecSql: ExecSql;\n patch: Partial<StoredDocumentRecord>;\n persistInput: PersistDocumentStateInput;\n}): Promise<PersistedDocumentState | null> {\n const { lockedExecSql, persistInput } = input;\n if (\n await refuseDeletedDocumentPersist({\n currentRecord: persistInput.currentRecord,\n documentProjectors: input.documentProjectors,\n execSql: lockedExecSql,\n localId: persistInput.localId,\n persistence: persistInput.persistence,\n })\n ) {\n return null;\n }\n const acceptedPendingUpdateIds = persistInput.acceptedPendingUpdateIds ?? [];\n for (\n let attempt = 0;\n attempt < MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS;\n attempt += 1\n ) {\n const mutation = await prepareDocumentMutation(\n persistInput,\n lockedExecSql,\n input.patch,\n );\n if (mutation.pullContinuationSuperseded) {\n return settleSupersededDocumentMutation({\n acceptedPendingUpdateIds,\n lockedExecSql,\n mutation,\n persistInput,\n });\n }\n const result = await commitOnePreparedDocumentMutation({\n acceptedPendingUpdateIds,\n documentProjectors: input.documentProjectors,\n lockedExecSql,\n mutation,\n persistInput,\n });\n if (result !== \"retry\") return result;\n }\n throw new Error(\n `Document mutation commit gave up after ${MAX_DOCUMENT_MUTATION_COMMIT_ATTEMPTS} concurrent conflicts`,\n );\n}\n"]}
|
|
@@ -4,8 +4,8 @@ export { selectDocumentSyncOutgoingBatch } from "../../data/documents/shared/syn
|
|
|
4
4
|
export { type DocumentSyncUpdateIsolationError, type IncomingDocumentSyncUpdateValidator, isDocumentSyncUpdateIsolationError, validateDocumentSyncUpdateImports, } from "../../data/documents/shared/sync/documentSyncUpdateIsolation.js";
|
|
5
5
|
export { type DocumentSyncPullContinuation, documentSyncPullContinuationsEqual, readPullContinuation, } from "../../data/documents/shared/sync/syncPagination.js";
|
|
6
6
|
export type { DocumentCreateAuthor, DocumentLinkSetFailureHandler, DocumentLinkSetMutationFailure, RelinkRemoteDocumentResult, } from "../../data/documents/shared/types.js";
|
|
7
|
-
export { clearDocumentSyncFailure, invalidateDocumentSyncPullContinuation, recordDocumentSyncFailure, } from "../../data/
|
|
8
|
-
export { DOCUMENT_HISTORY_COMPACTION_MAX_BYTES, DOCUMENT_HISTORY_COMPACTION_MAX_ROWS, } from "../../data/
|
|
7
|
+
export { clearDocumentSyncFailure, invalidateDocumentSyncPullContinuation, recordDocumentSyncFailure, } from "../../data/persistence/documents/records/index.js";
|
|
8
|
+
export { DOCUMENT_HISTORY_COMPACTION_MAX_BYTES, DOCUMENT_HISTORY_COMPACTION_MAX_ROWS, } from "../../data/persistence/documents/records/documentHistoryPersistence.js";
|
|
9
9
|
export type { ExecSql } from "../../data/sqlite/sqlSchema.js";
|
|
10
10
|
export { settleOutgoingPassAndDecideReArm } from "../../data/sync/outgoingUpdateSettlement.js";
|
|
11
11
|
export { didRegainSyncPrerequisites, isDatabaseUnavailableError, } from "../../data/sync/syncCoordinator.js";
|
|
@@ -3,8 +3,8 @@ export { persistedDocumentCreateStateFromResponse } from "../../data/documents/s
|
|
|
3
3
|
export { selectDocumentSyncOutgoingBatch } from "../../data/documents/shared/sync/documentSyncOutgoingBatch.js";
|
|
4
4
|
export { isDocumentSyncUpdateIsolationError, validateDocumentSyncUpdateImports, } from "../../data/documents/shared/sync/documentSyncUpdateIsolation.js";
|
|
5
5
|
export { documentSyncPullContinuationsEqual, readPullContinuation, } from "../../data/documents/shared/sync/syncPagination.js";
|
|
6
|
-
export { clearDocumentSyncFailure, invalidateDocumentSyncPullContinuation, recordDocumentSyncFailure, } from "../../data/
|
|
7
|
-
export { DOCUMENT_HISTORY_COMPACTION_MAX_BYTES, DOCUMENT_HISTORY_COMPACTION_MAX_ROWS, } from "../../data/
|
|
6
|
+
export { clearDocumentSyncFailure, invalidateDocumentSyncPullContinuation, recordDocumentSyncFailure, } from "../../data/persistence/documents/records/index.js";
|
|
7
|
+
export { DOCUMENT_HISTORY_COMPACTION_MAX_BYTES, DOCUMENT_HISTORY_COMPACTION_MAX_ROWS, } from "../../data/persistence/documents/records/documentHistoryPersistence.js";
|
|
8
8
|
export { settleOutgoingPassAndDecideReArm } from "../../data/sync/outgoingUpdateSettlement.js";
|
|
9
9
|
export { didRegainSyncPrerequisites, isDatabaseUnavailableError, } from "../../data/sync/syncCoordinator.js";
|
|
10
10
|
export { deleteLocalDocumentAttachment, deletePendingDocumentAttachment, markLocalDocumentAttachmentDetached, saveLocalDocumentAttachments, savePendingDocumentAttachment, } from "./attachments/attachmentPersistence.js";
|