@tearleads/client-sdk 0.1.44 → 0.1.45
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/persistence/container-contents/containerContentsPersistence.js +2 -3
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerCreateIntentSettlement.js +16 -16
- package/data/persistence/container-contents/containerCreateIntentSettlement.js.map +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js +5 -11
- package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerDocumentReassignment.js +13 -13
- package/data/persistence/container-contents/containerDocumentReassignment.js.map +1 -1
- package/data/persistence/container-contents/containerHydrationPersistence.js +7 -4
- package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerIntentPersistence.js +43 -42
- package/data/persistence/container-contents/containerIntentPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +15 -20
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMoveAbandonPersistence.js +1 -6
- package/data/persistence/container-contents/containerMoveAbandonPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMoveIntentRows.js +9 -8
- package/data/persistence/container-contents/containerMoveIntentRows.js.map +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js +4 -8
- package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRecoveryPersistence.js +20 -19
- package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRemovalWork.js +10 -10
- package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js +21 -44
- package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
- package/data/persistence/container-contents/documentLinkRemovalRepair.js +12 -11
- package/data/persistence/container-contents/documentLinkRemovalRepair.js.map +1 -1
- package/data/persistence/container-contents/documentMoveIntentPersistence.js +53 -28
- package/data/persistence/container-contents/documentMoveIntentPersistence.js.map +1 -1
- package/data/persistence/container-contents/documentPlacementIntentEnqueue.js +9 -8
- package/data/persistence/container-contents/documentPlacementIntentEnqueue.js.map +1 -1
- package/data/persistence/container-contents/documentPurgePlacement.js +6 -6
- package/data/persistence/container-contents/documentPurgePlacement.js.map +1 -1
- package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
- package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
- package/data/persistence/container-contents/pendingContainerCreate.js +5 -5
- package/data/persistence/container-contents/pendingContainerCreate.js.map +1 -1
- package/data/persistence/containers/containerPersistence.js +10 -27
- package/data/persistence/containers/containerPersistence.js.map +1 -1
- package/data/persistence/containers/documentContainerProjectionPersistence.js +2 -2
- package/data/persistence/containers/documentContainerProjectionPersistence.js.map +1 -1
- package/data/persistence/containers/documentPlacement.js +10 -10
- package/data/persistence/containers/documentPlacement.js.map +1 -1
- package/data/persistence/documents/internal/discardDocument.js +5 -5
- package/data/persistence/documents/internal/discardDocument.js.map +1 -1
- package/data/persistence/documents/internal/documentDeletionPersistence.js +7 -9
- package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentMutationPersistence.js +6 -8
- package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/ensureDocumentsSchema.js +2 -2
- package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js +3 -22
- package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
- package/data/persistence/organizations/organizationDataUsagePersistence.js +31 -64
- package/data/persistence/organizations/organizationDataUsagePersistence.js.map +1 -1
- package/data/persistence/organizations/organizationReadModelPurge.js +1 -5
- package/data/persistence/organizations/organizationReadModelPurge.js.map +1 -1
- package/data/persistence/principalCurrentAcknowledgementPersistence.js +24 -17
- package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -1
- package/data/persistence/principalHistoryIncompleteRetention.js +3 -9
- package/data/persistence/principalHistoryIncompleteRetention.js.map +1 -1
- package/data/persistence/principalHistoryStagePersistence.d.ts +3 -9
- package/data/persistence/principalHistoryStagePersistence.js +15 -25
- package/data/persistence/principalHistoryStagePersistence.js.map +1 -1
- package/data/persistence/principalHistoryStageRetention.js +16 -15
- package/data/persistence/principalHistoryStageRetention.js.map +1 -1
- package/data/persistence/principalHistoryUnpublishedRetention.js +6 -13
- package/data/persistence/principalHistoryUnpublishedRetention.js.map +1 -1
- package/data/sqlite/containerSchema.d.ts +84 -180
- package/data/sqlite/containerSchema.js +14 -23
- package/data/sqlite/containerSchema.js.map +1 -1
- package/data/sqlite/documentPlacementIntentSchema.js +3 -50
- package/data/sqlite/documentPlacementIntentSchema.js.map +1 -1
- package/data/sqlite/documentSyncFailurePersistence.d.ts +16 -6
- package/data/sqlite/documentSyncFailurePersistence.js +44 -54
- package/data/sqlite/documentSyncFailurePersistence.js.map +1 -1
- package/data/sqlite/{documentPlacementIntentSchema.d.ts → localIntentSchema.d.ts} +162 -88
- package/data/sqlite/localIntentSchema.js +90 -0
- package/data/sqlite/localIntentSchema.js.map +1 -0
- package/data/sqlite/organizationDataUsageSchema.js +11 -17
- package/data/sqlite/organizationDataUsageSchema.js.map +1 -1
- package/data/sqlite/principalHistoryRetentionSchema.js +0 -15
- package/data/sqlite/principalHistoryRetentionSchema.js.map +1 -1
- package/data/sqlite/principalHistoryStageSchema.d.ts +44 -2
- package/data/sqlite/principalHistoryStageSchema.js +14 -2
- package/data/sqlite/principalHistoryStageSchema.js.map +1 -1
- package/data/sqlite/schema.d.ts +947 -2112
- package/data/sqlite/schema.js +26 -134
- package/data/sqlite/schema.js.map +1 -1
- package/package.json +1 -1
- package/workflows/container-contents/documentPriming.js +6 -10
- package/workflows/container-contents/documentPriming.js.map +1 -1
- package/workflows/container-contents/documentQueries/sql.js +11 -10
- package/workflows/container-contents/documentQueries/sql.js.map +1 -1
- package/workflows/container-contents/documentQueries.js +2 -2
- package/workflows/container-contents/documentQueries.js.map +1 -1
- package/workflows/container-contents/pendingDownloads.js +2 -5
- package/workflows/container-contents/pendingDownloads.js.map +1 -1
- package/workflows/container-contents/pendingWrites/deferredTails.js +3 -11
- package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
- package/workflows/container-contents/pendingWrites/sources.js +56 -80
- package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
- package/workflows/container-contents/pendingWrites.js +6 -4
- package/workflows/container-contents/pendingWrites.js.map +1 -1
- package/workflows/container-contents/remoteContainerState.js +2 -1
- package/workflows/container-contents/remoteContainerState.js.map +1 -1
- package/workflows/sync/remoteReset.js +16 -23
- package/workflows/sync/remoteReset.js.map +1 -1
- package/workflows/sync/remoteResetPrincipalScope.js +1 -2
- package/workflows/sync/remoteResetPrincipalScope.js.map +1 -1
- package/workflows/sync/remoteResetScope.js +15 -8
- package/workflows/sync/remoteResetScope.js.map +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { and, asc, eq, inArray } from "drizzle-orm";
|
|
2
|
-
import {
|
|
2
|
+
import { inLocalIntentLane, LOCAL_INTENT_LANES, LOCAL_INTENT_SUBJECT, localIntents, } from "../../sqlite/schema.js";
|
|
3
3
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
4
|
import { CONTAINER_CREATE_INTENT_TYPE, CONTAINER_MOVE_INTENT_TYPE, } from "./containerContentsPersistenceTypes.js";
|
|
5
5
|
import { settleContainerCreateIntentRevision } from "./containerCreateIntentSettlement.js";
|
|
@@ -43,11 +43,12 @@ export async function saveContainerCreateIntent(input) {
|
|
|
43
43
|
const { containerId, createIntent, tx, updatedAt } = input;
|
|
44
44
|
const id = createIntent.id ?? crypto.randomUUID();
|
|
45
45
|
await tx
|
|
46
|
-
.insert(
|
|
46
|
+
.insert(localIntents)
|
|
47
47
|
.values({
|
|
48
48
|
id,
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
lane: LOCAL_INTENT_LANES.containerCreate,
|
|
50
|
+
subjectId: containerId,
|
|
51
|
+
targetContainerId: createIntent.parentContainerId,
|
|
51
52
|
intentType: CONTAINER_CREATE_INTENT_TYPE,
|
|
52
53
|
syncStatus: "pending",
|
|
53
54
|
remoteContainerId: null,
|
|
@@ -59,12 +60,12 @@ export async function saveContainerCreateIntent(input) {
|
|
|
59
60
|
updatedAt,
|
|
60
61
|
})
|
|
61
62
|
.onConflictDoUpdate({
|
|
62
|
-
target:
|
|
63
|
+
target: LOCAL_INTENT_SUBJECT,
|
|
63
64
|
set: {
|
|
64
65
|
// Timestamps can collide when a create is re-queued in one clock tick,
|
|
65
66
|
// so every enqueue owns a fresh revision token too.
|
|
66
67
|
id,
|
|
67
|
-
|
|
68
|
+
targetContainerId: createIntent.parentContainerId,
|
|
68
69
|
intentType: CONTAINER_CREATE_INTENT_TYPE,
|
|
69
70
|
syncStatus: "pending",
|
|
70
71
|
remoteContainerId: null,
|
|
@@ -84,9 +85,9 @@ export class ContainerCreateIntentSupersededError extends Error {
|
|
|
84
85
|
}
|
|
85
86
|
export async function deleteContainerMoveIntentRevision(input) {
|
|
86
87
|
const deleted = await input.tx
|
|
87
|
-
.delete(
|
|
88
|
-
.where(and(eq(
|
|
89
|
-
.returning({ containerId:
|
|
88
|
+
.delete(localIntents)
|
|
89
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerMove), eq(localIntents.subjectId, input.containerId), eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE), eq(localIntents.id, input.expectedIntentId), eq(localIntents.updatedAt, input.expectedUpdatedAt)))
|
|
90
|
+
.returning({ containerId: localIntents.subjectId });
|
|
90
91
|
return deleted.length > 0;
|
|
91
92
|
}
|
|
92
93
|
async function recordCreateIntentErrorAttempt(execSql, input) {
|
|
@@ -97,13 +98,13 @@ async function recordCreateIntentErrorAttempt(execSql, input) {
|
|
|
97
98
|
const record = async (tx) => {
|
|
98
99
|
const updatedAt = new Date().toISOString();
|
|
99
100
|
await tx
|
|
100
|
-
.update(
|
|
101
|
+
.update(localIntents)
|
|
101
102
|
.set({
|
|
102
103
|
lastAttemptedAt: updatedAt,
|
|
103
104
|
lastError: message,
|
|
104
105
|
updatedAt,
|
|
105
106
|
})
|
|
106
|
-
.where(and(eq(
|
|
107
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate), eq(localIntents.subjectId, containerId), eq(localIntents.syncStatus, "pending"), eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE), eq(localIntents.id, expectedIntentId), eq(localIntents.updatedAt, expectedUpdatedAt)))
|
|
107
108
|
.run();
|
|
108
109
|
};
|
|
109
110
|
if (stillCurrent) {
|
|
@@ -129,21 +130,21 @@ export const containerIntentPersistence = {
|
|
|
129
130
|
const { db } = getClientSQLitePersistenceRuntime(execSql);
|
|
130
131
|
const rows = await db
|
|
131
132
|
.select({
|
|
132
|
-
id:
|
|
133
|
-
containerId:
|
|
134
|
-
parentContainerId:
|
|
135
|
-
syncStatus:
|
|
136
|
-
remoteContainerId:
|
|
137
|
-
remoteMetadataDocumentId:
|
|
138
|
-
remoteMetadataAccessStateHash:
|
|
139
|
-
lastError:
|
|
140
|
-
lastAttemptedAt:
|
|
141
|
-
createdAt:
|
|
142
|
-
updatedAt:
|
|
133
|
+
id: localIntents.id,
|
|
134
|
+
containerId: localIntents.subjectId,
|
|
135
|
+
parentContainerId: localIntents.targetContainerId,
|
|
136
|
+
syncStatus: localIntents.syncStatus,
|
|
137
|
+
remoteContainerId: localIntents.remoteContainerId,
|
|
138
|
+
remoteMetadataDocumentId: localIntents.remoteMetadataDocumentId,
|
|
139
|
+
remoteMetadataAccessStateHash: localIntents.remoteMetadataAccessStateHash,
|
|
140
|
+
lastError: localIntents.lastError,
|
|
141
|
+
lastAttemptedAt: localIntents.lastAttemptedAt,
|
|
142
|
+
createdAt: localIntents.createdAt,
|
|
143
|
+
updatedAt: localIntents.updatedAt,
|
|
143
144
|
})
|
|
144
|
-
.from(
|
|
145
|
-
.where(and(eq(
|
|
146
|
-
.orderBy(asc(
|
|
145
|
+
.from(localIntents)
|
|
146
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate), eq(localIntents.syncStatus, "pending"), eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE)))
|
|
147
|
+
.orderBy(asc(localIntents.createdAt));
|
|
147
148
|
return rows.map((row) => mapContainerCreateIntentRecord(row));
|
|
148
149
|
},
|
|
149
150
|
async listUnsyncedMoveIntents(execSql) {
|
|
@@ -155,19 +156,19 @@ export const containerIntentPersistence = {
|
|
|
155
156
|
// the move completes — and hydration must still not revert them.
|
|
156
157
|
const rows = await db
|
|
157
158
|
.select({
|
|
158
|
-
id:
|
|
159
|
-
containerId:
|
|
160
|
-
parentContainerId:
|
|
161
|
-
previousParentContainerId:
|
|
162
|
-
syncStatus:
|
|
163
|
-
lastError:
|
|
164
|
-
lastAttemptedAt:
|
|
165
|
-
createdAt:
|
|
166
|
-
updatedAt:
|
|
159
|
+
id: localIntents.id,
|
|
160
|
+
containerId: localIntents.subjectId,
|
|
161
|
+
parentContainerId: localIntents.targetContainerId,
|
|
162
|
+
previousParentContainerId: localIntents.sourceContainerId,
|
|
163
|
+
syncStatus: localIntents.syncStatus,
|
|
164
|
+
lastError: localIntents.lastError,
|
|
165
|
+
lastAttemptedAt: localIntents.lastAttemptedAt,
|
|
166
|
+
createdAt: localIntents.createdAt,
|
|
167
|
+
updatedAt: localIntents.updatedAt,
|
|
167
168
|
})
|
|
168
|
-
.from(
|
|
169
|
-
.where(eq(
|
|
170
|
-
.orderBy(asc(
|
|
169
|
+
.from(localIntents)
|
|
170
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerMove), eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE)))
|
|
171
|
+
.orderBy(asc(localIntents.createdAt));
|
|
171
172
|
return rows.map((row) => mapContainerMoveIntentRecord(row));
|
|
172
173
|
},
|
|
173
174
|
recordCreateIntentRevisionError: (execSql, input) => recordCreateIntentErrorAttempt(execSql, input),
|
|
@@ -176,20 +177,20 @@ export const containerIntentPersistence = {
|
|
|
176
177
|
const record = async (tx) => {
|
|
177
178
|
const updatedAt = new Date().toISOString();
|
|
178
179
|
await tx
|
|
179
|
-
.update(
|
|
180
|
+
.update(localIntents)
|
|
180
181
|
.set({
|
|
181
182
|
lastAttemptedAt: updatedAt,
|
|
182
183
|
lastError: input.message,
|
|
183
184
|
syncStatus: input.blocked ? "blocked" : "pending",
|
|
184
185
|
updatedAt,
|
|
185
186
|
})
|
|
186
|
-
.where(and(eq(
|
|
187
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerMove), eq(localIntents.subjectId, input.containerId),
|
|
187
188
|
// Blocked rows stay updatable so a retried intent records its
|
|
188
189
|
// fresh outcome and a transient failure unblocks it.
|
|
189
|
-
inArray(
|
|
190
|
-
? [eq(
|
|
190
|
+
inArray(localIntents.syncStatus, ["pending", "blocked"]), eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE), ...(input.expectedIntentId
|
|
191
|
+
? [eq(localIntents.id, input.expectedIntentId)]
|
|
191
192
|
: []), ...(input.expectedUpdatedAt
|
|
192
|
-
? [eq(
|
|
193
|
+
? [eq(localIntents.updatedAt, input.expectedUpdatedAt)]
|
|
193
194
|
: [])))
|
|
194
195
|
.run();
|
|
195
196
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerIntentPersistence.js","sourceRoot":"","sources":["containerIntentPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray } from \"drizzle-orm\";\nimport {\n containerCreateIntents,\n containerMoveIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport {\n CONTAINER_CREATE_INTENT_TYPE,\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerContentsPersistence,\n type ContainerCreateIntentErrorInput,\n type ContainerCreateIntentInput,\n type ContainerCreateIntentRecord,\n type ContainerCreateIntentRevisionInput,\n type ContainerCreateIntentSyncStatus,\n type ContainerMoveIntentRecord,\n type ContainerMoveIntentRevisionInput,\n type ContainerMoveIntentSyncStatus,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\n\nfunction parseCreateIntentSyncStatus(\n value: unknown,\n): ContainerCreateIntentSyncStatus {\n return value === \"synced\" ? \"synced\" : \"pending\";\n}\n\nfunction parseMoveIntentSyncStatus(\n value: unknown,\n): ContainerMoveIntentSyncStatus {\n return value === \"blocked\" ? \"blocked\" : \"pending\";\n}\n\ninterface SelectedContainerCreateIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n syncStatus: string;\n remoteContainerId: string | null;\n remoteMetadataDocumentId: string | null;\n remoteMetadataAccessStateHash: string | null;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface SelectedContainerMoveIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n previousParentContainerId: string | null;\n syncStatus: string;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nfunction mapContainerCreateIntentRecord(\n row: SelectedContainerCreateIntentRecord,\n): ContainerCreateIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: parseCreateIntentSyncStatus(row.syncStatus),\n remoteContainerId: row.remoteContainerId,\n remoteMetadataDocumentId: row.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash: row.remoteMetadataAccessStateHash,\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapContainerMoveIntentRecord(\n row: SelectedContainerMoveIntentRecord,\n): ContainerMoveIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n previousParentContainerId: row.previousParentContainerId,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: parseMoveIntentSyncStatus(row.syncStatus),\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport async function saveContainerCreateIntent(input: {\n tx: ClientSQLiteTransactionScope;\n containerId: string;\n createIntent: ContainerCreateIntentInput;\n updatedAt: string;\n}) {\n const { containerId, createIntent, tx, updatedAt } = input;\n const id = createIntent.id ?? crypto.randomUUID();\n await tx\n .insert(containerCreateIntents)\n .values({\n id,\n containerId,\n parentContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n createdAt: updatedAt,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: containerCreateIntents.containerId,\n set: {\n // Timestamps can collide when a create is re-queued in one clock tick,\n // so every enqueue owns a fresh revision token too.\n id,\n parentContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n updatedAt,\n },\n })\n .run();\n}\n\nexport class ContainerCreateIntentSupersededError extends Error {\n constructor() {\n super(\"Container create intent was superseded before local settlement\");\n }\n}\n\nexport async function deleteContainerMoveIntentRevision(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const deleted = await input.tx\n .delete(containerMoveIntents)\n .where(\n and(\n eq(containerMoveIntents.containerId, input.containerId),\n eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n eq(containerMoveIntents.id, input.expectedIntentId),\n eq(containerMoveIntents.updatedAt, input.expectedUpdatedAt),\n ),\n )\n .returning({ containerId: containerMoveIntents.containerId });\n return deleted.length > 0;\n}\n\nasync function recordCreateIntentErrorAttempt(\n execSql: ExecSql,\n input: ContainerCreateIntentErrorInput,\n): Promise<void> {\n const {\n containerId,\n expectedIntentId,\n expectedUpdatedAt,\n message,\n stillCurrent,\n } = input;\n if (!message) throw new Error(\"Container create intent error is required\");\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(containerCreateIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: message,\n updatedAt,\n })\n .where(\n and(\n eq(containerCreateIntents.containerId, containerId),\n eq(containerCreateIntents.syncStatus, \"pending\"),\n eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(containerCreateIntents.id, expectedIntentId),\n eq(containerCreateIntents.updatedAt, expectedUpdatedAt),\n ),\n )\n .run();\n };\n if (stillCurrent) {\n await runtime.guardedTransaction(record, stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n}\n\nasync function markMoveIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerMoveIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => {\n return deleteContainerMoveIntentRevision({ ...input, tx });\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result === true;\n}\n\nasync function markCreateIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerCreateIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => settleContainerCreateIntentRevision({ ...input, tx }),\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result !== \"superseded\";\n}\n\ntype ContainerIntentPersistence = Pick<\n ContainerContentsPersistence,\n | \"listPendingCreateIntents\"\n | \"listUnsyncedMoveIntents\"\n | \"recordCreateIntentRevisionError\"\n | \"recordMoveIntentError\"\n | \"markCreateIntentRevisionSynced\"\n | \"markMoveIntentRevisionSynced\"\n>;\n\nexport const containerIntentPersistence = {\n async listPendingCreateIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: containerCreateIntents.id,\n containerId: containerCreateIntents.containerId,\n parentContainerId: containerCreateIntents.parentContainerId,\n syncStatus: containerCreateIntents.syncStatus,\n remoteContainerId: containerCreateIntents.remoteContainerId,\n remoteMetadataDocumentId:\n containerCreateIntents.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash:\n containerCreateIntents.remoteMetadataAccessStateHash,\n lastError: containerCreateIntents.lastError,\n lastAttemptedAt: containerCreateIntents.lastAttemptedAt,\n createdAt: containerCreateIntents.createdAt,\n updatedAt: containerCreateIntents.updatedAt,\n })\n .from(containerCreateIntents)\n .where(\n and(\n eq(containerCreateIntents.syncStatus, \"pending\"),\n eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n ),\n )\n .orderBy(asc(containerCreateIntents.createdAt));\n\n return rows.map((row) => mapContainerCreateIntentRecord(row));\n },\n async listUnsyncedMoveIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n // No status filter: markMoveIntentRevisionSynced deletes settled rows,\n // so every surviving row is unsynced. Blocked intents replay too: \"blocked\"\n // names the reason the last attempt could not proceed, not a terminal\n // verdict — the missing container can appear via hydration, after which\n // the move completes — and hydration must still not revert them.\n const rows = await db\n .select({\n id: containerMoveIntents.id,\n containerId: containerMoveIntents.containerId,\n parentContainerId: containerMoveIntents.parentContainerId,\n previousParentContainerId:\n containerMoveIntents.previousParentContainerId,\n syncStatus: containerMoveIntents.syncStatus,\n lastError: containerMoveIntents.lastError,\n lastAttemptedAt: containerMoveIntents.lastAttemptedAt,\n createdAt: containerMoveIntents.createdAt,\n updatedAt: containerMoveIntents.updatedAt,\n })\n .from(containerMoveIntents)\n .where(eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE))\n .orderBy(asc(containerMoveIntents.createdAt));\n\n return rows.map((row) => mapContainerMoveIntentRecord(row));\n },\n recordCreateIntentRevisionError: (execSql, input) =>\n recordCreateIntentErrorAttempt(execSql, input),\n async recordMoveIntentError(execSql, input) {\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(containerMoveIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: input.message,\n syncStatus: input.blocked ? \"blocked\" : \"pending\",\n updatedAt,\n })\n .where(\n and(\n eq(containerMoveIntents.containerId, input.containerId),\n // Blocked rows stay updatable so a retried intent records its\n // fresh outcome and a transient failure unblocks it.\n inArray(containerMoveIntents.syncStatus, [\"pending\", \"blocked\"]),\n eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n ...(input.expectedIntentId\n ? [eq(containerMoveIntents.id, input.expectedIntentId)]\n : []),\n ...(input.expectedUpdatedAt\n ? [eq(containerMoveIntents.updatedAt, input.expectedUpdatedAt)]\n : []),\n ),\n )\n .run();\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(record, input.stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n },\n markCreateIntentRevisionSynced,\n markMoveIntentRevisionSynced,\n} satisfies ContainerIntentPersistence;\n"]}
|
|
1
|
+
{"version":3,"file":"containerIntentPersistence.js","sourceRoot":"","sources":["containerIntentPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray } from \"drizzle-orm\";\nimport {\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n LOCAL_INTENT_SUBJECT,\n localIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport {\n CONTAINER_CREATE_INTENT_TYPE,\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerContentsPersistence,\n type ContainerCreateIntentErrorInput,\n type ContainerCreateIntentInput,\n type ContainerCreateIntentRecord,\n type ContainerCreateIntentRevisionInput,\n type ContainerCreateIntentSyncStatus,\n type ContainerMoveIntentRecord,\n type ContainerMoveIntentRevisionInput,\n type ContainerMoveIntentSyncStatus,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\n\nfunction parseCreateIntentSyncStatus(\n value: unknown,\n): ContainerCreateIntentSyncStatus {\n return value === \"synced\" ? \"synced\" : \"pending\";\n}\n\nfunction parseMoveIntentSyncStatus(\n value: unknown,\n): ContainerMoveIntentSyncStatus {\n return value === \"blocked\" ? \"blocked\" : \"pending\";\n}\n\ninterface SelectedContainerCreateIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n syncStatus: string;\n remoteContainerId: string | null;\n remoteMetadataDocumentId: string | null;\n remoteMetadataAccessStateHash: string | null;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface SelectedContainerMoveIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n previousParentContainerId: string | null;\n syncStatus: string;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nfunction mapContainerCreateIntentRecord(\n row: SelectedContainerCreateIntentRecord,\n): ContainerCreateIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: parseCreateIntentSyncStatus(row.syncStatus),\n remoteContainerId: row.remoteContainerId,\n remoteMetadataDocumentId: row.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash: row.remoteMetadataAccessStateHash,\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapContainerMoveIntentRecord(\n row: SelectedContainerMoveIntentRecord,\n): ContainerMoveIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n previousParentContainerId: row.previousParentContainerId,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: parseMoveIntentSyncStatus(row.syncStatus),\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport async function saveContainerCreateIntent(input: {\n tx: ClientSQLiteTransactionScope;\n containerId: string;\n createIntent: ContainerCreateIntentInput;\n updatedAt: string;\n}) {\n const { containerId, createIntent, tx, updatedAt } = input;\n const id = createIntent.id ?? crypto.randomUUID();\n await tx\n .insert(localIntents)\n .values({\n id,\n lane: LOCAL_INTENT_LANES.containerCreate,\n subjectId: containerId,\n targetContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n createdAt: updatedAt,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: LOCAL_INTENT_SUBJECT,\n set: {\n // Timestamps can collide when a create is re-queued in one clock tick,\n // so every enqueue owns a fresh revision token too.\n id,\n targetContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n updatedAt,\n },\n })\n .run();\n}\n\nexport class ContainerCreateIntentSupersededError extends Error {\n constructor() {\n super(\"Container create intent was superseded before local settlement\");\n }\n}\n\nexport async function deleteContainerMoveIntentRevision(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const deleted = await input.tx\n .delete(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, input.containerId),\n eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n eq(localIntents.id, input.expectedIntentId),\n eq(localIntents.updatedAt, input.expectedUpdatedAt),\n ),\n )\n .returning({ containerId: localIntents.subjectId });\n return deleted.length > 0;\n}\n\nasync function recordCreateIntentErrorAttempt(\n execSql: ExecSql,\n input: ContainerCreateIntentErrorInput,\n): Promise<void> {\n const {\n containerId,\n expectedIntentId,\n expectedUpdatedAt,\n message,\n stillCurrent,\n } = input;\n if (!message) throw new Error(\"Container create intent error is required\");\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(localIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: message,\n updatedAt,\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.subjectId, containerId),\n eq(localIntents.syncStatus, \"pending\"),\n eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(localIntents.id, expectedIntentId),\n eq(localIntents.updatedAt, expectedUpdatedAt),\n ),\n )\n .run();\n };\n if (stillCurrent) {\n await runtime.guardedTransaction(record, stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n}\n\nasync function markMoveIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerMoveIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => {\n return deleteContainerMoveIntentRevision({ ...input, tx });\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result === true;\n}\n\nasync function markCreateIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerCreateIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => settleContainerCreateIntentRevision({ ...input, tx }),\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result !== \"superseded\";\n}\n\ntype ContainerIntentPersistence = Pick<\n ContainerContentsPersistence,\n | \"listPendingCreateIntents\"\n | \"listUnsyncedMoveIntents\"\n | \"recordCreateIntentRevisionError\"\n | \"recordMoveIntentError\"\n | \"markCreateIntentRevisionSynced\"\n | \"markMoveIntentRevisionSynced\"\n>;\n\nexport const containerIntentPersistence = {\n async listPendingCreateIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: localIntents.id,\n containerId: localIntents.subjectId,\n parentContainerId: localIntents.targetContainerId,\n syncStatus: localIntents.syncStatus,\n remoteContainerId: localIntents.remoteContainerId,\n remoteMetadataDocumentId: localIntents.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash:\n localIntents.remoteMetadataAccessStateHash,\n lastError: localIntents.lastError,\n lastAttemptedAt: localIntents.lastAttemptedAt,\n createdAt: localIntents.createdAt,\n updatedAt: localIntents.updatedAt,\n })\n .from(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.syncStatus, \"pending\"),\n eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n ),\n )\n .orderBy(asc(localIntents.createdAt));\n\n return rows.map((row) => mapContainerCreateIntentRecord(row));\n },\n async listUnsyncedMoveIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n // No status filter: markMoveIntentRevisionSynced deletes settled rows,\n // so every surviving row is unsynced. Blocked intents replay too: \"blocked\"\n // names the reason the last attempt could not proceed, not a terminal\n // verdict — the missing container can appear via hydration, after which\n // the move completes — and hydration must still not revert them.\n const rows = await db\n .select({\n id: localIntents.id,\n containerId: localIntents.subjectId,\n parentContainerId: localIntents.targetContainerId,\n previousParentContainerId: localIntents.sourceContainerId,\n syncStatus: localIntents.syncStatus,\n lastError: localIntents.lastError,\n lastAttemptedAt: localIntents.lastAttemptedAt,\n createdAt: localIntents.createdAt,\n updatedAt: localIntents.updatedAt,\n })\n .from(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n ),\n )\n .orderBy(asc(localIntents.createdAt));\n\n return rows.map((row) => mapContainerMoveIntentRecord(row));\n },\n recordCreateIntentRevisionError: (execSql, input) =>\n recordCreateIntentErrorAttempt(execSql, input),\n async recordMoveIntentError(execSql, input) {\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(localIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: input.message,\n syncStatus: input.blocked ? \"blocked\" : \"pending\",\n updatedAt,\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, input.containerId),\n // Blocked rows stay updatable so a retried intent records its\n // fresh outcome and a transient failure unblocks it.\n inArray(localIntents.syncStatus, [\"pending\", \"blocked\"]),\n eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n ...(input.expectedIntentId\n ? [eq(localIntents.id, input.expectedIntentId)]\n : []),\n ...(input.expectedUpdatedAt\n ? [eq(localIntents.updatedAt, input.expectedUpdatedAt)]\n : []),\n ),\n )\n .run();\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(record, input.stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n },\n markCreateIntentRevisionSynced,\n markMoveIntentRevisionSynced,\n} satisfies ContainerIntentPersistence;\n"]}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { and, eq } from "drizzle-orm";
|
|
1
|
+
import { and, eq, or } from "drizzle-orm";
|
|
2
2
|
import { assertHeldContainerBinding, heldContainerBinding, } from "../../containers/containerBinding.js";
|
|
3
3
|
import { documentSyncPullContinuationsEqual } from "../../documents/shared/pullContinuation.js";
|
|
4
4
|
import { hasQueuedDocumentUpdates, settleQueuedDocumentUpdatesInTransaction, } from "../../sqlite/documentPendingUpdatePersistence.js";
|
|
5
5
|
import { enqueueDocumentPendingUpdate, } from "../../sqlite/documentPersistence.js";
|
|
6
|
-
import {
|
|
6
|
+
import { clearDocumentSyncFailureInTransaction } from "../../sqlite/documentSyncFailurePersistence.js";
|
|
7
|
+
import { inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema.js";
|
|
7
8
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
8
9
|
import { runSerializedSqlMutation } from "../../sqlite/sqlSchema.js";
|
|
9
10
|
import { loadContainerById, } from "../containers/containerPersistence.js";
|
|
@@ -68,29 +69,23 @@ async function loadStoredContainerState(execSql, containerId) {
|
|
|
68
69
|
async function deleteAcceptedPendingUpdates(tx, containerId, ids) {
|
|
69
70
|
await settleQueuedDocumentUpdatesInTransaction(tx, getContainerMetadataScope(containerId), ids);
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
function clearMetadataSyncFailure(tx, containerId) {
|
|
73
|
+
return clearDocumentSyncFailureInTransaction(tx, {
|
|
74
|
+
appKind: CONTAINER_METADATA_APP_KIND,
|
|
75
|
+
localId: containerId,
|
|
76
|
+
});
|
|
76
77
|
}
|
|
77
78
|
async function hasPendingUpdates(tx, containerId) {
|
|
78
79
|
return hasQueuedDocumentUpdates(tx, getContainerMetadataScope(containerId));
|
|
79
80
|
}
|
|
80
81
|
async function hasPendingStructuralIntent(tx, containerId) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
.
|
|
85
|
-
.
|
|
86
|
-
if (pendingCreates.length > 0)
|
|
87
|
-
return true;
|
|
88
|
-
const unsyncedMoves = await tx
|
|
89
|
-
.select({ id: containerMoveIntents.id })
|
|
90
|
-
.from(containerMoveIntents)
|
|
91
|
-
.where(eq(containerMoveIntents.containerId, containerId))
|
|
82
|
+
// A pending create or any surviving (unsynced) move of this container.
|
|
83
|
+
const structural = await tx
|
|
84
|
+
.select({ id: localIntents.id })
|
|
85
|
+
.from(localIntents)
|
|
86
|
+
.where(and(eq(localIntents.subjectId, containerId), or(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate), eq(localIntents.syncStatus, "pending")), inLocalIntentLane(LOCAL_INTENT_LANES.containerMove))))
|
|
92
87
|
.limit(1);
|
|
93
|
-
return
|
|
88
|
+
return structural.length > 0;
|
|
94
89
|
}
|
|
95
90
|
async function enqueuePendingUpdate(execSql, containerId, pendingUpdate) {
|
|
96
91
|
if (!pendingUpdate)
|
|
@@ -187,7 +182,7 @@ export async function commitStoredMetadataMutation(execSql, input) {
|
|
|
187
182
|
await enqueuePendingUpdate(lockedExecSql, input.container.id, input.pendingUpdate);
|
|
188
183
|
await deleteAcceptedPendingUpdates(tx, input.container.id, input.acceptedPendingUpdateIds);
|
|
189
184
|
if (input.clearSyncFailure) {
|
|
190
|
-
await
|
|
185
|
+
await clearMetadataSyncFailure(tx, input.container.id);
|
|
191
186
|
}
|
|
192
187
|
const { container, localUpdatedAt } = await prepareContainerMutationWrite({
|
|
193
188
|
currentContainer: currentState.container,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerMetadataMutationPersistence.js","sourceRoot":"","sources":["containerMetadataMutationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport {\n assertHeldContainerBinding,\n heldContainerBinding,\n} from \"../../containers/containerBinding\";\nimport { documentSyncPullContinuationsEqual } from \"../../documents/shared/pullContinuation\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../sqlite/documentPendingUpdatePersistence\";\nimport {\n enqueueDocumentPendingUpdate,\n type PendingUpdateFields,\n} from \"../../sqlite/documentPersistence\";\nimport {\n containerCreateIntents,\n containerMoveIntents,\n documentSyncFailures,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport {\n type ContainerRecord,\n loadContainerById,\n} from \"../containers/containerPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\nimport {\n ContainerCreateIntentSupersededError,\n deleteContainerMoveIntentRevision,\n} from \"./containerIntentPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nfunction sameNullableValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nfunction committedMetadataMutationResult(input: {\n container: ContainerRecord;\n createIntentSettled: boolean;\n moveIntentSettled: boolean;\n}) {\n return {\n committed: true as const,\n container: input.container,\n ...(input.createIntentSettled\n ? { createIntentSettled: true as const }\n : {}),\n ...(input.moveIntentSettled ? { moveIntentSettled: true as const } : {}),\n };\n}\n\nfunction sameMetadataSecurityIdentity(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableValue(current.accessStateHash, expected.accessStateHash) &&\n sameNullableValue(current.contentKeyBundle, expected.contentKeyBundle) &&\n sameNullableValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n )\n );\n}\n\nfunction sameMetadataRecord(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n sameMetadataSecurityIdentity(current, expected) &&\n sameNullableValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n current.metadataUpdates === expected.metadataUpdates &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired)\n );\n}\n\nfunction sameContainerRecord(\n current: ContainerRecord,\n expected: ContainerRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.parentId === expected.parentId &&\n current.organizationId === expected.organizationId &&\n current.metadataDocumentId === expected.metadataDocumentId &&\n (current.systemSlot ?? null) === (expected.systemSlot ?? null) &&\n (current.effectiveAccessLevel ?? null) ===\n (expected.effectiveAccessLevel ?? null) &&\n (current.localUpdatedAt ?? null) === (expected.localUpdatedAt ?? null) &&\n (current.serverCreatedAt ?? null) === (expected.serverCreatedAt ?? null) &&\n (current.serverUpdatedAt ?? null) === (expected.serverUpdatedAt ?? null) &&\n current.name === expected.name &&\n (current.icon ?? null) === (expected.icon ?? null)\n );\n}\n\nasync function loadStoredContainerState(\n execSql: Parameters<\n ContainerContentsPersistence[\"loadContainerMetadataState\"]\n >[0],\n containerId: string,\n): Promise<StoredContainerState | null> {\n const container = await loadContainerById(execSql, containerId);\n if (!container) return null;\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n}\n\nasync function deleteAcceptedPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n ids: readonly string[],\n): Promise<void> {\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n getContainerMetadataScope(containerId),\n ids,\n );\n}\n\nasync function clearSyncFailure(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<void> {\n await tx\n .delete(documentSyncFailures)\n .where(\n and(\n eq(documentSyncFailures.appKind, CONTAINER_METADATA_APP_KIND),\n eq(documentSyncFailures.localId, containerId),\n ),\n )\n .run();\n}\n\nasync function hasPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n return hasQueuedDocumentUpdates(tx, getContainerMetadataScope(containerId));\n}\n\nasync function hasPendingStructuralIntent(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n const pendingCreates = await tx\n .select({ id: containerCreateIntents.id })\n .from(containerCreateIntents)\n .where(\n and(\n eq(containerCreateIntents.containerId, containerId),\n eq(containerCreateIntents.syncStatus, \"pending\"),\n ),\n )\n .limit(1);\n if (pendingCreates.length > 0) return true;\n\n const unsyncedMoves = await tx\n .select({ id: containerMoveIntents.id })\n .from(containerMoveIntents)\n .where(eq(containerMoveIntents.containerId, containerId))\n .limit(1);\n return unsyncedMoves.length > 0;\n}\n\nasync function enqueuePendingUpdate(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n containerId: string,\n pendingUpdate: PendingUpdateFields | undefined,\n): Promise<void> {\n if (!pendingUpdate) return;\n await enqueueDocumentPendingUpdate(\n execSql,\n getContainerMetadataScope(containerId),\n pendingUpdate,\n );\n}\n\ntype CommitMetadataMutationInput = Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n>[1];\n\nfunction staleServerMutationResult(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n) {\n const incomingServerUpdatedAt =\n input.saveOptions?.serverTimestamps?.updatedAt;\n const hasOlderContainerTimestamp =\n incomingServerUpdatedAt != null &&\n currentState?.container.serverUpdatedAt != null &&\n currentState.container.serverUpdatedAt > incomingServerUpdatedAt;\n const hasOlderMetadataAccessEpoch =\n currentState?.record != null &&\n currentState.record.documentId === input.record.documentId &&\n currentState.record.accessEpoch > input.record.accessEpoch;\n return currentState?.record &&\n (hasOlderContainerTimestamp || hasOlderMetadataAccessEpoch)\n ? {\n committed: false as const,\n currentState,\n staleServerState: true as const,\n }\n : null;\n}\n\nfunction metadataMutationStateMatches(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n): currentState is StoredContainerState & {\n record: ContainerMetadataRecord;\n} {\n return Boolean(\n currentState?.record &&\n sameContainerRecord(currentState.container, input.expectedContainer) &&\n sameMetadataRecord(currentState.record, input.expectedRecord),\n );\n}\n\nasync function rejectMetadataMutationConflict(input: {\n currentState: StoredContainerState | null;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}) {\n const { currentState, mutation, tx } = input;\n if (\n currentState?.record &&\n mutation.settleAcceptedPendingOnConflict &&\n sameMetadataSecurityIdentity(currentState.record, mutation.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n mutation.container.id,\n mutation.acceptedPendingUpdateIds,\n );\n }\n return { committed: false as const, currentState };\n}\n\nasync function prepareContainerMutationWrite(input: {\n currentContainer: ContainerRecord;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}): Promise<{ container: ContainerRecord; localUpdatedAt: string }> {\n const { currentContainer, mutation, tx } = input;\n const requestedLocalUpdatedAt =\n mutation.saveOptions?.localUpdatedAt ??\n mutation.saveOptions?.updatedAt ??\n new Date().toISOString();\n const preserveDurableStructure =\n mutation.preserveDurableStructureWhenPending === true &&\n (await hasPendingStructuralIntent(tx, mutation.container.id));\n // Syncing metadata is not a local edit. Preserve the durable edit clock,\n // including an edit another pane made while this request was in flight.\n const localUpdatedAt =\n preserveDurableStructure || mutation.settleAcceptedPendingOnConflict\n ? (currentContainer.localUpdatedAt ?? requestedLocalUpdatedAt)\n : requestedLocalUpdatedAt;\n const structurallyRebasedContainer = preserveDurableStructure\n ? { ...mutation.container, parentId: currentContainer.parentId }\n : mutation.container;\n const didSettleOutgoing =\n mutation.acceptedPendingUpdateIds.length > 0 &&\n !(await hasPendingUpdates(tx, mutation.container.id)) &&\n !(await hasPendingStructuralIntent(tx, mutation.container.id));\n // Only container responses establish the server's structural clock. A\n // metadata acknowledgement supplies no such timestamp; marking it with our\n // wall clock would make later valid listings appear stale forever.\n return {\n container: structurallyRebasedContainer,\n localUpdatedAt: didSettleOutgoing\n ? (currentContainer.serverUpdatedAt ?? localUpdatedAt)\n : localUpdatedAt,\n };\n}\n\n/** Server acknowledgements and listings cannot rebind a held folder. */\nfunction assertMutationKeepsHeldBinding(\n currentState: StoredContainerState & { record: ContainerMetadataRecord },\n input: CommitMetadataMutationInput,\n): void {\n const recordDocumentIds =\n input.record.documentId === currentState.record.documentId\n ? []\n : [input.record.documentId];\n assertHeldContainerBinding(heldContainerBinding(currentState), {\n organizationId: input.container.organizationId,\n metadataDocumentIds: [\n input.container.metadataDocumentId,\n ...recordDocumentIds,\n ],\n });\n}\n\nexport async function commitStoredMetadataMutation(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n input: Parameters<ContainerContentsPersistence[\"commitMetadataMutation\"]>[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n );\n const staleServerResult = staleServerMutationResult(\n currentState,\n input,\n );\n if (staleServerResult) return staleServerResult;\n if (!metadataMutationStateMatches(currentState, input)) {\n return rejectMetadataMutationConflict({\n currentState,\n mutation: input,\n tx,\n });\n }\n assertMutationKeepsHeldBinding(currentState, input);\n\n await enqueuePendingUpdate(\n lockedExecSql,\n input.container.id,\n input.pendingUpdate,\n );\n await deleteAcceptedPendingUpdates(\n tx,\n input.container.id,\n input.acceptedPendingUpdateIds,\n );\n if (input.clearSyncFailure) {\n await clearSyncFailure(tx, input.container.id);\n }\n const { container, localUpdatedAt } =\n await prepareContainerMutationWrite({\n currentContainer: currentState.container,\n mutation: input,\n tx,\n });\n const savedContainer = await saveContainerContentsContainerRows({\n container,\n createIntent: input.saveOptions?.createIntent,\n localUpdatedAt,\n moveIntent: input.saveOptions?.moveIntent,\n record: input.record,\n serverTimestamps: input.saveOptions?.serverTimestamps,\n tx,\n });\n if (\n input.createIntentSettlement &&\n (await settleContainerCreateIntentRevision({\n ...input.createIntentSettlement,\n tx,\n })) === \"superseded\"\n ) {\n throw new ContainerCreateIntentSupersededError();\n }\n if (input.moveIntentSettlement) {\n if (\n !(await deleteContainerMoveIntentRevision({\n ...input.moveIntentSettlement,\n tx,\n }))\n ) {\n throw new Error(\n \"Container move intent was superseded before local settlement\",\n );\n }\n }\n return committedMetadataMutationResult({\n container: savedContainer,\n createIntentSettled: input.createIntentSettlement !== undefined,\n moveIntentSettled: input.moveIntentSettlement !== undefined,\n });\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n if (outcome.committed && outcome.result) {\n return outcome.result;\n }\n return {\n committed: false as const,\n currentState: await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n ),\n };\n });\n}\n\nexport async function settleStoredMetadataPendingUpdates(\n execSql: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[0],\n input: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.containerId,\n );\n if (\n currentState?.record &&\n sameMetadataSecurityIdentity(\n currentState.record,\n input.expectedRecord,\n )\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n input.containerId,\n input.pendingUpdateIds,\n );\n }\n return currentState;\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n return outcome.committed ? outcome.result : null;\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerMetadataMutationPersistence.js","sourceRoot":"","sources":["containerMetadataMutationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, or } from \"drizzle-orm\";\nimport {\n assertHeldContainerBinding,\n heldContainerBinding,\n} from \"../../containers/containerBinding\";\nimport { documentSyncPullContinuationsEqual } from \"../../documents/shared/pullContinuation\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../sqlite/documentPendingUpdatePersistence\";\nimport {\n enqueueDocumentPendingUpdate,\n type PendingUpdateFields,\n} from \"../../sqlite/documentPersistence\";\nimport { clearDocumentSyncFailureInTransaction } from \"../../sqlite/documentSyncFailurePersistence\";\nimport {\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport {\n type ContainerRecord,\n loadContainerById,\n} from \"../containers/containerPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\nimport {\n ContainerCreateIntentSupersededError,\n deleteContainerMoveIntentRevision,\n} from \"./containerIntentPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nfunction sameNullableValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nfunction committedMetadataMutationResult(input: {\n container: ContainerRecord;\n createIntentSettled: boolean;\n moveIntentSettled: boolean;\n}) {\n return {\n committed: true as const,\n container: input.container,\n ...(input.createIntentSettled\n ? { createIntentSettled: true as const }\n : {}),\n ...(input.moveIntentSettled ? { moveIntentSettled: true as const } : {}),\n };\n}\n\nfunction sameMetadataSecurityIdentity(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableValue(current.accessStateHash, expected.accessStateHash) &&\n sameNullableValue(current.contentKeyBundle, expected.contentKeyBundle) &&\n sameNullableValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n )\n );\n}\n\nfunction sameMetadataRecord(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n sameMetadataSecurityIdentity(current, expected) &&\n sameNullableValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n current.metadataUpdates === expected.metadataUpdates &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired)\n );\n}\n\nfunction sameContainerRecord(\n current: ContainerRecord,\n expected: ContainerRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.parentId === expected.parentId &&\n current.organizationId === expected.organizationId &&\n current.metadataDocumentId === expected.metadataDocumentId &&\n (current.systemSlot ?? null) === (expected.systemSlot ?? null) &&\n (current.effectiveAccessLevel ?? null) ===\n (expected.effectiveAccessLevel ?? null) &&\n (current.localUpdatedAt ?? null) === (expected.localUpdatedAt ?? null) &&\n (current.serverCreatedAt ?? null) === (expected.serverCreatedAt ?? null) &&\n (current.serverUpdatedAt ?? null) === (expected.serverUpdatedAt ?? null) &&\n current.name === expected.name &&\n (current.icon ?? null) === (expected.icon ?? null)\n );\n}\n\nasync function loadStoredContainerState(\n execSql: Parameters<\n ContainerContentsPersistence[\"loadContainerMetadataState\"]\n >[0],\n containerId: string,\n): Promise<StoredContainerState | null> {\n const container = await loadContainerById(execSql, containerId);\n if (!container) return null;\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n}\n\nasync function deleteAcceptedPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n ids: readonly string[],\n): Promise<void> {\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n getContainerMetadataScope(containerId),\n ids,\n );\n}\n\nfunction clearMetadataSyncFailure(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<void> {\n return clearDocumentSyncFailureInTransaction(tx, {\n appKind: CONTAINER_METADATA_APP_KIND,\n localId: containerId,\n });\n}\n\nasync function hasPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n return hasQueuedDocumentUpdates(tx, getContainerMetadataScope(containerId));\n}\n\nasync function hasPendingStructuralIntent(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n // A pending create or any surviving (unsynced) move of this container.\n const structural = await tx\n .select({ id: localIntents.id })\n .from(localIntents)\n .where(\n and(\n eq(localIntents.subjectId, containerId),\n or(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.syncStatus, \"pending\"),\n ),\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n ),\n ),\n )\n .limit(1);\n return structural.length > 0;\n}\n\nasync function enqueuePendingUpdate(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n containerId: string,\n pendingUpdate: PendingUpdateFields | undefined,\n): Promise<void> {\n if (!pendingUpdate) return;\n await enqueueDocumentPendingUpdate(\n execSql,\n getContainerMetadataScope(containerId),\n pendingUpdate,\n );\n}\n\ntype CommitMetadataMutationInput = Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n>[1];\n\nfunction staleServerMutationResult(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n) {\n const incomingServerUpdatedAt =\n input.saveOptions?.serverTimestamps?.updatedAt;\n const hasOlderContainerTimestamp =\n incomingServerUpdatedAt != null &&\n currentState?.container.serverUpdatedAt != null &&\n currentState.container.serverUpdatedAt > incomingServerUpdatedAt;\n const hasOlderMetadataAccessEpoch =\n currentState?.record != null &&\n currentState.record.documentId === input.record.documentId &&\n currentState.record.accessEpoch > input.record.accessEpoch;\n return currentState?.record &&\n (hasOlderContainerTimestamp || hasOlderMetadataAccessEpoch)\n ? {\n committed: false as const,\n currentState,\n staleServerState: true as const,\n }\n : null;\n}\n\nfunction metadataMutationStateMatches(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n): currentState is StoredContainerState & {\n record: ContainerMetadataRecord;\n} {\n return Boolean(\n currentState?.record &&\n sameContainerRecord(currentState.container, input.expectedContainer) &&\n sameMetadataRecord(currentState.record, input.expectedRecord),\n );\n}\n\nasync function rejectMetadataMutationConflict(input: {\n currentState: StoredContainerState | null;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}) {\n const { currentState, mutation, tx } = input;\n if (\n currentState?.record &&\n mutation.settleAcceptedPendingOnConflict &&\n sameMetadataSecurityIdentity(currentState.record, mutation.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n mutation.container.id,\n mutation.acceptedPendingUpdateIds,\n );\n }\n return { committed: false as const, currentState };\n}\n\nasync function prepareContainerMutationWrite(input: {\n currentContainer: ContainerRecord;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}): Promise<{ container: ContainerRecord; localUpdatedAt: string }> {\n const { currentContainer, mutation, tx } = input;\n const requestedLocalUpdatedAt =\n mutation.saveOptions?.localUpdatedAt ??\n mutation.saveOptions?.updatedAt ??\n new Date().toISOString();\n const preserveDurableStructure =\n mutation.preserveDurableStructureWhenPending === true &&\n (await hasPendingStructuralIntent(tx, mutation.container.id));\n // Syncing metadata is not a local edit. Preserve the durable edit clock,\n // including an edit another pane made while this request was in flight.\n const localUpdatedAt =\n preserveDurableStructure || mutation.settleAcceptedPendingOnConflict\n ? (currentContainer.localUpdatedAt ?? requestedLocalUpdatedAt)\n : requestedLocalUpdatedAt;\n const structurallyRebasedContainer = preserveDurableStructure\n ? { ...mutation.container, parentId: currentContainer.parentId }\n : mutation.container;\n const didSettleOutgoing =\n mutation.acceptedPendingUpdateIds.length > 0 &&\n !(await hasPendingUpdates(tx, mutation.container.id)) &&\n !(await hasPendingStructuralIntent(tx, mutation.container.id));\n // Only container responses establish the server's structural clock. A\n // metadata acknowledgement supplies no such timestamp; marking it with our\n // wall clock would make later valid listings appear stale forever.\n return {\n container: structurallyRebasedContainer,\n localUpdatedAt: didSettleOutgoing\n ? (currentContainer.serverUpdatedAt ?? localUpdatedAt)\n : localUpdatedAt,\n };\n}\n\n/** Server acknowledgements and listings cannot rebind a held folder. */\nfunction assertMutationKeepsHeldBinding(\n currentState: StoredContainerState & { record: ContainerMetadataRecord },\n input: CommitMetadataMutationInput,\n): void {\n const recordDocumentIds =\n input.record.documentId === currentState.record.documentId\n ? []\n : [input.record.documentId];\n assertHeldContainerBinding(heldContainerBinding(currentState), {\n organizationId: input.container.organizationId,\n metadataDocumentIds: [\n input.container.metadataDocumentId,\n ...recordDocumentIds,\n ],\n });\n}\n\nexport async function commitStoredMetadataMutation(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n input: Parameters<ContainerContentsPersistence[\"commitMetadataMutation\"]>[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n );\n const staleServerResult = staleServerMutationResult(\n currentState,\n input,\n );\n if (staleServerResult) return staleServerResult;\n if (!metadataMutationStateMatches(currentState, input)) {\n return rejectMetadataMutationConflict({\n currentState,\n mutation: input,\n tx,\n });\n }\n assertMutationKeepsHeldBinding(currentState, input);\n\n await enqueuePendingUpdate(\n lockedExecSql,\n input.container.id,\n input.pendingUpdate,\n );\n await deleteAcceptedPendingUpdates(\n tx,\n input.container.id,\n input.acceptedPendingUpdateIds,\n );\n if (input.clearSyncFailure) {\n await clearMetadataSyncFailure(tx, input.container.id);\n }\n const { container, localUpdatedAt } =\n await prepareContainerMutationWrite({\n currentContainer: currentState.container,\n mutation: input,\n tx,\n });\n const savedContainer = await saveContainerContentsContainerRows({\n container,\n createIntent: input.saveOptions?.createIntent,\n localUpdatedAt,\n moveIntent: input.saveOptions?.moveIntent,\n record: input.record,\n serverTimestamps: input.saveOptions?.serverTimestamps,\n tx,\n });\n if (\n input.createIntentSettlement &&\n (await settleContainerCreateIntentRevision({\n ...input.createIntentSettlement,\n tx,\n })) === \"superseded\"\n ) {\n throw new ContainerCreateIntentSupersededError();\n }\n if (input.moveIntentSettlement) {\n if (\n !(await deleteContainerMoveIntentRevision({\n ...input.moveIntentSettlement,\n tx,\n }))\n ) {\n throw new Error(\n \"Container move intent was superseded before local settlement\",\n );\n }\n }\n return committedMetadataMutationResult({\n container: savedContainer,\n createIntentSettled: input.createIntentSettlement !== undefined,\n moveIntentSettled: input.moveIntentSettlement !== undefined,\n });\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n if (outcome.committed && outcome.result) {\n return outcome.result;\n }\n return {\n committed: false as const,\n currentState: await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n ),\n };\n });\n}\n\nexport async function settleStoredMetadataPendingUpdates(\n execSql: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[0],\n input: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.containerId,\n );\n if (\n currentState?.record &&\n sameMetadataSecurityIdentity(\n currentState.record,\n input.expectedRecord,\n )\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n input.containerId,\n input.pendingUpdateIds,\n );\n }\n return currentState;\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n return outcome.committed ? outcome.result : null;\n });\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { eq } from "drizzle-orm";
|
|
2
|
-
import {
|
|
2
|
+
import { containers } from "../../sqlite/schema.js";
|
|
3
3
|
import { getClientSQLitePersistenceRuntime } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
4
|
import { deleteContainerMoveIntentRevision } from "./containerIntentPersistence.js";
|
|
5
5
|
/**
|
|
@@ -17,11 +17,6 @@ export async function abandonStoredMoveIntentRevision(execSql, input) {
|
|
|
17
17
|
.set({ parentId: input.previousParentContainerId })
|
|
18
18
|
.where(eq(containers.id, input.containerId))
|
|
19
19
|
.run();
|
|
20
|
-
await tx
|
|
21
|
-
.update(containerProjection)
|
|
22
|
-
.set({ updatedAt: new Date().toISOString() })
|
|
23
|
-
.where(eq(containerProjection.containerId, input.containerId))
|
|
24
|
-
.run();
|
|
25
20
|
return true;
|
|
26
21
|
}, input.stillCurrent, { behavior: "immediate" });
|
|
27
22
|
return outcome.committed && outcome.result === true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerMoveAbandonPersistence.js","sourceRoot":"","sources":["containerMoveAbandonPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"containerMoveAbandonPersistence.js","sourceRoot":"","sources":["containerMoveAbandonPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,iCAAiC,EAAE,MAAM,uCAAuC,CAAC;AAG1F,OAAO,EAAE,iCAAiC,EAAE,MAAM,8BAA8B,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,OAAgB,EAChB,KAEC;IAED,MAAM,OAAO,GAAG,MAAM,iCAAiC,CACrD,OAAO,CACR,CAAC,kBAAkB,CAClB,KAAK,EAAE,EAAE,EAAE,EAAE;QACX,IAAI,CAAC,CAAC,MAAM,iCAAiC,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9D,OAAO,KAAK,CAAC;QACf,MAAM,EAAE;aACL,MAAM,CAAC,UAAU,CAAC;aAClB,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,yBAAyB,EAAE,CAAC;aAClD,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;aAC3C,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC,EACD,KAAK,CAAC,YAAY,EAClB,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;IACF,OAAO,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC;AACtD,CAAC","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport { containers } from \"../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport type { ContainerMoveIntentRevisionInput } from \"./containerContentsPersistenceTypes\";\nimport { deleteContainerMoveIntentRevision } from \"./containerIntentPersistence\";\n\n/**\n * Drop a queued move the server will never accept and put the folder back\n * under the parent it left, atomically. The server row never changed, so no\n * listing would ever restore the placement. Returns false, changing nothing,\n * when a newer local move superseded the revision.\n */\nexport async function abandonStoredMoveIntentRevision(\n execSql: ExecSql,\n input: ContainerMoveIntentRevisionInput & {\n previousParentContainerId: string;\n },\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => {\n if (!(await deleteContainerMoveIntentRevision({ ...input, tx })))\n return false;\n await tx\n .update(containers)\n .set({ parentId: input.previousParentContainerId })\n .where(eq(containers.id, input.containerId))\n .run();\n return true;\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result === true;\n}\n"]}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { sql } from "drizzle-orm";
|
|
2
|
-
import {
|
|
2
|
+
import { LOCAL_INTENT_LANES, LOCAL_INTENT_SUBJECT, localIntents, } from "../../sqlite/schema.js";
|
|
3
3
|
import { CONTAINER_MOVE_INTENT_TYPE, } from "./containerContentsPersistenceTypes.js";
|
|
4
4
|
export async function saveContainerMoveIntent(input) {
|
|
5
5
|
const { containerId, moveIntent, tx, updatedAt } = input;
|
|
6
6
|
const id = moveIntent.id ?? crypto.randomUUID();
|
|
7
7
|
await tx
|
|
8
|
-
.insert(
|
|
8
|
+
.insert(localIntents)
|
|
9
9
|
.values({
|
|
10
10
|
id,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
lane: LOCAL_INTENT_LANES.containerMove,
|
|
12
|
+
subjectId: containerId,
|
|
13
|
+
targetContainerId: moveIntent.parentContainerId,
|
|
14
|
+
sourceContainerId: moveIntent.previousParentContainerId ?? null,
|
|
14
15
|
intentType: CONTAINER_MOVE_INTENT_TYPE,
|
|
15
16
|
syncStatus: "pending",
|
|
16
17
|
lastError: null,
|
|
@@ -19,13 +20,13 @@ export async function saveContainerMoveIntent(input) {
|
|
|
19
20
|
updatedAt,
|
|
20
21
|
})
|
|
21
22
|
.onConflictDoUpdate({
|
|
22
|
-
target:
|
|
23
|
+
target: LOCAL_INTENT_SUBJECT,
|
|
23
24
|
set: {
|
|
24
25
|
// The timestamp can collide when two moves are queued in one clock
|
|
25
26
|
// tick, so every enqueue also owns a fresh revision token.
|
|
26
27
|
id,
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
targetContainerId: moveIntent.parentContainerId,
|
|
29
|
+
sourceContainerId: sql `coalesce(${localIntents.sourceContainerId}, ${moveIntent.previousParentContainerId ?? null})`,
|
|
29
30
|
intentType: CONTAINER_MOVE_INTENT_TYPE,
|
|
30
31
|
syncStatus: "pending",
|
|
31
32
|
lastError: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerMoveIntentRows.js","sourceRoot":"","sources":["containerMoveIntentRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"containerMoveIntentRows.js","sourceRoot":"","sources":["containerMoveIntentRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,0BAA0B,GAE3B,MAAM,qCAAqC,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAK7C;IACC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACzD,MAAM,EAAE,GAAG,UAAU,CAAC,EAAE,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;IAChD,MAAM,EAAE;SACL,MAAM,CAAC,YAAY,CAAC;SACpB,MAAM,CAAC;QACN,EAAE;QACF,IAAI,EAAE,kBAAkB,CAAC,aAAa;QACtC,SAAS,EAAE,WAAW;QACtB,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,iBAAiB,EAAE,UAAU,CAAC,yBAAyB,IAAI,IAAI;QAC/D,UAAU,EAAE,0BAA0B;QACtC,UAAU,EAAE,SAAS;QACrB,SAAS,EAAE,IAAI;QACf,eAAe,EAAE,IAAI;QACrB,SAAS,EAAE,SAAS;QACpB,SAAS;KACV,CAAC;SACD,kBAAkB,CAAC;QAClB,MAAM,EAAE,oBAAoB;QAC5B,GAAG,EAAE;YACH,mEAAmE;YACnE,2DAA2D;YAC3D,EAAE;YACF,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;YAC/C,iBAAiB,EAAE,GAAG,CAAA,YAAY,YAAY,CAAC,iBAAiB,KAAK,UAAU,CAAC,yBAAyB,IAAI,IAAI,GAAG;YACpH,UAAU,EAAE,0BAA0B;YACtC,UAAU,EAAE,SAAS;YACrB,SAAS,EAAE,IAAI;YACf,SAAS;SACV;KACF,CAAC;SACD,GAAG,EAAE,CAAC;AACX,CAAC","sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n LOCAL_INTENT_LANES,\n LOCAL_INTENT_SUBJECT,\n localIntents,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerMoveIntentInput,\n} from \"./containerContentsPersistenceTypes\";\n\nexport async function saveContainerMoveIntent(input: {\n tx: ClientSQLiteTransactionScope;\n containerId: string;\n moveIntent: ContainerMoveIntentInput;\n updatedAt: string;\n}) {\n const { containerId, moveIntent, tx, updatedAt } = input;\n const id = moveIntent.id ?? crypto.randomUUID();\n await tx\n .insert(localIntents)\n .values({\n id,\n lane: LOCAL_INTENT_LANES.containerMove,\n subjectId: containerId,\n targetContainerId: moveIntent.parentContainerId,\n sourceContainerId: moveIntent.previousParentContainerId ?? null,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: \"pending\",\n lastError: null,\n lastAttemptedAt: null,\n createdAt: updatedAt,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: LOCAL_INTENT_SUBJECT,\n set: {\n // The timestamp can collide when two moves are queued in one clock\n // tick, so every enqueue also owns a fresh revision token.\n id,\n targetContainerId: moveIntent.parentContainerId,\n sourceContainerId: sql`coalesce(${localIntents.sourceContainerId}, ${moveIntent.previousParentContainerId ?? null})`,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: \"pending\",\n lastError: null,\n updatedAt,\n },\n })\n .run();\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ensureDocumentTables } from "../../sqlite/documentPersistence.js";
|
|
2
|
-
import {
|
|
2
|
+
import { documentContainerProjectionTables, documentPlacementIntentTables, documentProjectionTables, } from "../../sqlite/schema.js";
|
|
3
3
|
import { getClientSQLitePersistenceRuntime } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
4
|
import { ensureSqlTables, runSerializedSqlMutation, } from "../../sqlite/sqlSchema.js";
|
|
5
5
|
import { ensureContainerTables } from "../containers/containerPersistence.js";
|
|
@@ -18,7 +18,7 @@ export const containerReconcilePersistence = {
|
|
|
18
18
|
const updatedAt = input.updatedAt ?? new Date().toISOString();
|
|
19
19
|
await ensureSqlTables(lockedExecSql, [
|
|
20
20
|
...documentContainerProjectionTables,
|
|
21
|
-
...
|
|
21
|
+
...documentPlacementIntentTables,
|
|
22
22
|
...documentProjectionTables,
|
|
23
23
|
]);
|
|
24
24
|
if (input.stillCurrent?.() === false) {
|
|
@@ -51,10 +51,8 @@ export const containerReconcilePersistence = {
|
|
|
51
51
|
await runSerializedSqlMutation(execSql, async (lockedExecSql) => {
|
|
52
52
|
const updatedAt = input.updatedAt ?? new Date().toISOString();
|
|
53
53
|
await ensureSqlTables(lockedExecSql, [
|
|
54
|
-
...containerCreateIntentTables,
|
|
55
|
-
...containerMoveIntentTables,
|
|
56
54
|
...documentContainerProjectionTables,
|
|
57
|
-
...
|
|
55
|
+
...documentPlacementIntentTables,
|
|
58
56
|
...documentProjectionTables,
|
|
59
57
|
]);
|
|
60
58
|
await ensureContainerTables(lockedExecSql);
|
|
@@ -100,10 +98,8 @@ export const containerReconcilePersistence = {
|
|
|
100
98
|
await runSerializedSqlMutation(execSql, async (lockedExecSql) => {
|
|
101
99
|
const updatedAt = input.updatedAt ?? new Date().toISOString();
|
|
102
100
|
await ensureSqlTables(lockedExecSql, [
|
|
103
|
-
...containerCreateIntentTables,
|
|
104
|
-
...containerMoveIntentTables,
|
|
105
101
|
...documentContainerProjectionTables,
|
|
106
|
-
...
|
|
102
|
+
...documentPlacementIntentTables,
|
|
107
103
|
...documentProjectionTables,
|
|
108
104
|
]);
|
|
109
105
|
await ensureContainerTables(lockedExecSql);
|