@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.
Files changed (113) hide show
  1. package/data/persistence/container-contents/containerContentsPersistence.js +2 -3
  2. package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
  3. package/data/persistence/container-contents/containerCreateIntentSettlement.js +16 -16
  4. package/data/persistence/container-contents/containerCreateIntentSettlement.js.map +1 -1
  5. package/data/persistence/container-contents/containerDeletionPersistence.js +5 -11
  6. package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
  7. package/data/persistence/container-contents/containerDocumentReassignment.js +13 -13
  8. package/data/persistence/container-contents/containerDocumentReassignment.js.map +1 -1
  9. package/data/persistence/container-contents/containerHydrationPersistence.js +7 -4
  10. package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
  11. package/data/persistence/container-contents/containerIntentPersistence.js +43 -42
  12. package/data/persistence/container-contents/containerIntentPersistence.js.map +1 -1
  13. package/data/persistence/container-contents/containerMetadataMutationPersistence.js +15 -20
  14. package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
  15. package/data/persistence/container-contents/containerMoveAbandonPersistence.js +1 -6
  16. package/data/persistence/container-contents/containerMoveAbandonPersistence.js.map +1 -1
  17. package/data/persistence/container-contents/containerMoveIntentRows.js +9 -8
  18. package/data/persistence/container-contents/containerMoveIntentRows.js.map +1 -1
  19. package/data/persistence/container-contents/containerReconcilePersistence.js +4 -8
  20. package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
  21. package/data/persistence/container-contents/containerRecoveryPersistence.js +20 -19
  22. package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
  23. package/data/persistence/container-contents/containerRemovalWork.js +10 -10
  24. package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
  25. package/data/persistence/container-contents/containerStructuralRepair.js +21 -44
  26. package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
  27. package/data/persistence/container-contents/documentLinkRemovalRepair.js +12 -11
  28. package/data/persistence/container-contents/documentLinkRemovalRepair.js.map +1 -1
  29. package/data/persistence/container-contents/documentMoveIntentPersistence.js +53 -28
  30. package/data/persistence/container-contents/documentMoveIntentPersistence.js.map +1 -1
  31. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js +9 -8
  32. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js.map +1 -1
  33. package/data/persistence/container-contents/documentPurgePlacement.js +6 -6
  34. package/data/persistence/container-contents/documentPurgePlacement.js.map +1 -1
  35. package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
  36. package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
  37. package/data/persistence/container-contents/pendingContainerCreate.js +5 -5
  38. package/data/persistence/container-contents/pendingContainerCreate.js.map +1 -1
  39. package/data/persistence/containers/containerPersistence.js +10 -27
  40. package/data/persistence/containers/containerPersistence.js.map +1 -1
  41. package/data/persistence/containers/documentContainerProjectionPersistence.js +2 -2
  42. package/data/persistence/containers/documentContainerProjectionPersistence.js.map +1 -1
  43. package/data/persistence/containers/documentPlacement.js +10 -10
  44. package/data/persistence/containers/documentPlacement.js.map +1 -1
  45. package/data/persistence/documents/internal/discardDocument.js +5 -5
  46. package/data/persistence/documents/internal/discardDocument.js.map +1 -1
  47. package/data/persistence/documents/internal/documentDeletionPersistence.js +7 -9
  48. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  49. package/data/persistence/documents/internal/documentMutationPersistence.js +6 -8
  50. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  51. package/data/persistence/documents/internal/ensureDocumentsSchema.js +2 -2
  52. package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
  53. package/data/persistence/documents/internal/orphanSideRows.js +3 -22
  54. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  55. package/data/persistence/organizations/organizationDataUsagePersistence.js +31 -64
  56. package/data/persistence/organizations/organizationDataUsagePersistence.js.map +1 -1
  57. package/data/persistence/organizations/organizationReadModelPurge.js +1 -5
  58. package/data/persistence/organizations/organizationReadModelPurge.js.map +1 -1
  59. package/data/persistence/principalCurrentAcknowledgementPersistence.js +24 -17
  60. package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -1
  61. package/data/persistence/principalHistoryIncompleteRetention.js +3 -9
  62. package/data/persistence/principalHistoryIncompleteRetention.js.map +1 -1
  63. package/data/persistence/principalHistoryStagePersistence.d.ts +3 -9
  64. package/data/persistence/principalHistoryStagePersistence.js +15 -25
  65. package/data/persistence/principalHistoryStagePersistence.js.map +1 -1
  66. package/data/persistence/principalHistoryStageRetention.js +16 -15
  67. package/data/persistence/principalHistoryStageRetention.js.map +1 -1
  68. package/data/persistence/principalHistoryUnpublishedRetention.js +6 -13
  69. package/data/persistence/principalHistoryUnpublishedRetention.js.map +1 -1
  70. package/data/sqlite/containerSchema.d.ts +84 -180
  71. package/data/sqlite/containerSchema.js +14 -23
  72. package/data/sqlite/containerSchema.js.map +1 -1
  73. package/data/sqlite/documentPlacementIntentSchema.js +3 -50
  74. package/data/sqlite/documentPlacementIntentSchema.js.map +1 -1
  75. package/data/sqlite/documentSyncFailurePersistence.d.ts +16 -6
  76. package/data/sqlite/documentSyncFailurePersistence.js +44 -54
  77. package/data/sqlite/documentSyncFailurePersistence.js.map +1 -1
  78. package/data/sqlite/{documentPlacementIntentSchema.d.ts → localIntentSchema.d.ts} +162 -88
  79. package/data/sqlite/localIntentSchema.js +90 -0
  80. package/data/sqlite/localIntentSchema.js.map +1 -0
  81. package/data/sqlite/organizationDataUsageSchema.js +11 -17
  82. package/data/sqlite/organizationDataUsageSchema.js.map +1 -1
  83. package/data/sqlite/principalHistoryRetentionSchema.js +0 -15
  84. package/data/sqlite/principalHistoryRetentionSchema.js.map +1 -1
  85. package/data/sqlite/principalHistoryStageSchema.d.ts +44 -2
  86. package/data/sqlite/principalHistoryStageSchema.js +14 -2
  87. package/data/sqlite/principalHistoryStageSchema.js.map +1 -1
  88. package/data/sqlite/schema.d.ts +947 -2112
  89. package/data/sqlite/schema.js +26 -134
  90. package/data/sqlite/schema.js.map +1 -1
  91. package/package.json +1 -1
  92. package/workflows/container-contents/documentPriming.js +6 -10
  93. package/workflows/container-contents/documentPriming.js.map +1 -1
  94. package/workflows/container-contents/documentQueries/sql.js +11 -10
  95. package/workflows/container-contents/documentQueries/sql.js.map +1 -1
  96. package/workflows/container-contents/documentQueries.js +2 -2
  97. package/workflows/container-contents/documentQueries.js.map +1 -1
  98. package/workflows/container-contents/pendingDownloads.js +2 -5
  99. package/workflows/container-contents/pendingDownloads.js.map +1 -1
  100. package/workflows/container-contents/pendingWrites/deferredTails.js +3 -11
  101. package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
  102. package/workflows/container-contents/pendingWrites/sources.js +56 -80
  103. package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
  104. package/workflows/container-contents/pendingWrites.js +6 -4
  105. package/workflows/container-contents/pendingWrites.js.map +1 -1
  106. package/workflows/container-contents/remoteContainerState.js +2 -1
  107. package/workflows/container-contents/remoteContainerState.js.map +1 -1
  108. package/workflows/sync/remoteReset.js +16 -23
  109. package/workflows/sync/remoteReset.js.map +1 -1
  110. package/workflows/sync/remoteResetPrincipalScope.js +1 -2
  111. package/workflows/sync/remoteResetPrincipalScope.js.map +1 -1
  112. package/workflows/sync/remoteResetScope.js +15 -8
  113. package/workflows/sync/remoteResetScope.js.map +1 -1
@@ -1,5 +1,5 @@
1
1
  import { and, asc, eq, inArray } from "drizzle-orm";
2
- import { containerCreateIntents, containerMoveIntents, } from "../../sqlite/schema.js";
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(containerCreateIntents)
46
+ .insert(localIntents)
47
47
  .values({
48
48
  id,
49
- containerId,
50
- parentContainerId: createIntent.parentContainerId,
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: containerCreateIntents.containerId,
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
- parentContainerId: createIntent.parentContainerId,
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(containerMoveIntents)
88
- .where(and(eq(containerMoveIntents.containerId, input.containerId), eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE), eq(containerMoveIntents.id, input.expectedIntentId), eq(containerMoveIntents.updatedAt, input.expectedUpdatedAt)))
89
- .returning({ containerId: containerMoveIntents.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(containerCreateIntents)
101
+ .update(localIntents)
101
102
  .set({
102
103
  lastAttemptedAt: updatedAt,
103
104
  lastError: message,
104
105
  updatedAt,
105
106
  })
106
- .where(and(eq(containerCreateIntents.containerId, containerId), eq(containerCreateIntents.syncStatus, "pending"), eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE), eq(containerCreateIntents.id, expectedIntentId), eq(containerCreateIntents.updatedAt, expectedUpdatedAt)))
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: containerCreateIntents.id,
133
- containerId: containerCreateIntents.containerId,
134
- parentContainerId: containerCreateIntents.parentContainerId,
135
- syncStatus: containerCreateIntents.syncStatus,
136
- remoteContainerId: containerCreateIntents.remoteContainerId,
137
- remoteMetadataDocumentId: containerCreateIntents.remoteMetadataDocumentId,
138
- remoteMetadataAccessStateHash: containerCreateIntents.remoteMetadataAccessStateHash,
139
- lastError: containerCreateIntents.lastError,
140
- lastAttemptedAt: containerCreateIntents.lastAttemptedAt,
141
- createdAt: containerCreateIntents.createdAt,
142
- updatedAt: containerCreateIntents.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(containerCreateIntents)
145
- .where(and(eq(containerCreateIntents.syncStatus, "pending"), eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE)))
146
- .orderBy(asc(containerCreateIntents.createdAt));
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: containerMoveIntents.id,
159
- containerId: containerMoveIntents.containerId,
160
- parentContainerId: containerMoveIntents.parentContainerId,
161
- previousParentContainerId: containerMoveIntents.previousParentContainerId,
162
- syncStatus: containerMoveIntents.syncStatus,
163
- lastError: containerMoveIntents.lastError,
164
- lastAttemptedAt: containerMoveIntents.lastAttemptedAt,
165
- createdAt: containerMoveIntents.createdAt,
166
- updatedAt: containerMoveIntents.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(containerMoveIntents)
169
- .where(eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE))
170
- .orderBy(asc(containerMoveIntents.createdAt));
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(containerMoveIntents)
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(containerMoveIntents.containerId, input.containerId),
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(containerMoveIntents.syncStatus, ["pending", "blocked"]), eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE), ...(input.expectedIntentId
190
- ? [eq(containerMoveIntents.id, input.expectedIntentId)]
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(containerMoveIntents.updatedAt, input.expectedUpdatedAt)]
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 { containerCreateIntents, containerMoveIntents, documentSyncFailures, } from "../../sqlite/schema.js";
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
- async function clearSyncFailure(tx, containerId) {
72
- await tx
73
- .delete(documentSyncFailures)
74
- .where(and(eq(documentSyncFailures.appKind, CONTAINER_METADATA_APP_KIND), eq(documentSyncFailures.localId, containerId)))
75
- .run();
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
- const pendingCreates = await tx
82
- .select({ id: containerCreateIntents.id })
83
- .from(containerCreateIntents)
84
- .where(and(eq(containerCreateIntents.containerId, containerId), eq(containerCreateIntents.syncStatus, "pending")))
85
- .limit(1);
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 unsyncedMoves.length > 0;
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 clearSyncFailure(tx, input.container.id);
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 { containerProjection, containers } from "../../sqlite/schema.js";
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,mBAAmB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtE,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,MAAM,EAAE;aACL,MAAM,CAAC,mBAAmB,CAAC;aAC3B,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;aAC5C,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;aAC7D,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 { containerProjection, 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 await tx\n .update(containerProjection)\n .set({ updatedAt: new Date().toISOString() })\n .where(eq(containerProjection.containerId, 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
+ {"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 { containerMoveIntents } from "../../sqlite/schema.js";
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(containerMoveIntents)
8
+ .insert(localIntents)
9
9
  .values({
10
10
  id,
11
- containerId,
12
- parentContainerId: moveIntent.parentContainerId,
13
- previousParentContainerId: moveIntent.previousParentContainerId ?? null,
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: containerMoveIntents.containerId,
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
- parentContainerId: moveIntent.parentContainerId,
28
- previousParentContainerId: sql `coalesce(${containerMoveIntents.previousParentContainerId}, ${moveIntent.previousParentContainerId ?? null})`,
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,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,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,oBAAoB,CAAC;SAC5B,MAAM,CAAC;QACN,EAAE;QACF,WAAW;QACX,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,yBAAyB,EAAE,UAAU,CAAC,yBAAyB,IAAI,IAAI;QACvE,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,CAAC,WAAW;QACxC,GAAG,EAAE;YACH,mEAAmE;YACnE,2DAA2D;YAC3D,EAAE;YACF,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;YAC/C,yBAAyB,EAAE,GAAG,CAAA,YAAY,oBAAoB,CAAC,yBAAyB,KAAK,UAAU,CAAC,yBAAyB,IAAI,IAAI,GAAG;YAC5I,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 { containerMoveIntents } 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(containerMoveIntents)\n .values({\n id,\n containerId,\n parentContainerId: moveIntent.parentContainerId,\n previousParentContainerId: 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: containerMoveIntents.containerId,\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 parentContainerId: moveIntent.parentContainerId,\n previousParentContainerId: sql`coalesce(${containerMoveIntents.previousParentContainerId}, ${moveIntent.previousParentContainerId ?? null})`,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: \"pending\",\n lastError: null,\n updatedAt,\n },\n })\n .run();\n}\n"]}
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 { containerCreateIntentTables, containerMoveIntentTables, documentContainerProjectionTables, documentMoveIntentTables, documentProjectionTables, } from "../../sqlite/schema.js";
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
- ...documentMoveIntentTables,
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
- ...documentMoveIntentTables,
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
- ...documentMoveIntentTables,
102
+ ...documentPlacementIntentTables,
107
103
  ...documentProjectionTables,
108
104
  ]);
109
105
  await ensureContainerTables(lockedExecSql);