@tearleads/client-sdk 0.1.116 → 0.1.117
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 +14 -13
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/documents/internal/ensureDocumentsSchema.js +10 -12
- package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
- package/data/sqlite/schema/containerSchema.d.ts +1 -0
- package/data/sqlite/schema/containerSchema.js +8 -1
- package/data/sqlite/schema/containerSchema.js.map +1 -1
- package/data/sqlite/schema/documentAttachmentSchema.d.ts +0 -2
- package/data/sqlite/schema/documentAttachmentSchema.js +0 -4
- package/data/sqlite/schema/documentAttachmentSchema.js.map +1 -1
- package/data/sqlite/schema/index.d.ts +2 -0
- package/data/sqlite/schema/index.js +10 -1
- package/data/sqlite/schema/index.js.map +1 -1
- package/data/sqlite/schema/principalPolicySchema.js +0 -1
- package/data/sqlite/schema/principalPolicySchema.js.map +1 -1
- package/data/sqlite/schema/verifiedManifestBundleSchema.js +4 -2
- package/data/sqlite/schema/verifiedManifestBundleSchema.js.map +1 -1
- package/data/sqlite/sqlExec.d.ts +12 -0
- package/data/sqlite/sqlExec.js +47 -3
- package/data/sqlite/sqlExec.js.map +1 -1
- package/data/sqlite/sqlTableSchema.js +40 -15
- package/data/sqlite/sqlTableSchema.js.map +1 -1
- package/data/sqlite/sqlitePersistenceRuntime.js +18 -10
- package/data/sqlite/sqlitePersistenceRuntime.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { eq } from "drizzle-orm";
|
|
2
|
-
import { containerHydrationTombstones, containers, documentContainerProjectionTables, keyingCheckpointTables, localIntentTables, } from "../../sqlite/schema/index.js";
|
|
2
|
+
import { containerHydrationTombstones, containerSyncWatermarkTables, containers, containerTables, documentContainerProjectionTables, documentProjectionTables, documentTables, keyingCheckpointTables, localIntentTables, } from "../../sqlite/schema/index.js";
|
|
3
3
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
4
|
import { ensureSqlTables, runOncePerConnection, runSerializedSqlMutation, } from "../../sqlite/sqlSchema.js";
|
|
5
|
-
import { enqueueDocumentPendingUpdate
|
|
5
|
+
import { enqueueDocumentPendingUpdate } from "../documents/records/index.js";
|
|
6
6
|
import { hasQueuedDocumentUpdates, settleQueuedDocumentUpdatesInTransaction, } from "../documents/records/documentPendingUpdatePersistence.js";
|
|
7
7
|
import { getLatestTimestamp } from "../latestTimestamp.js";
|
|
8
|
-
import {
|
|
9
|
-
import { sqlContainerSyncWatermarkPersistence } from "./containerSyncWatermarkPersistence.js";
|
|
8
|
+
import { loadContainerById } from "./containerPersistence.js";
|
|
10
9
|
import { claimDormantMetadataSweepAttempt, completeDormantMetadataSweepRequest, listDormantMetadataSweepRequests, } from "./dormantMetadataSweep.js";
|
|
11
10
|
export { CONTAINER_METADATA_APP_KIND } from "./dormantContainerMetadata.js";
|
|
12
11
|
import { deleteStoredContainers } from "./containerDeletionPersistence.js";
|
|
@@ -86,16 +85,18 @@ export const sqlContainerContentsPersistence = {
|
|
|
86
85
|
// Once ensured on this connection, skip the outer mutation lock entirely:
|
|
87
86
|
// ensureSchema runs on every query path, and re-acquiring the lock just to
|
|
88
87
|
// no-op would queue reads behind unrelated writes.
|
|
89
|
-
await runOncePerConnection(execSql, "ensure:container-contents", () =>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
await runOncePerConnection(execSql, "ensure:container-contents", () =>
|
|
89
|
+
// One ensure, so a cold connection sends three DDL messages in total.
|
|
90
|
+
ensureSqlTables(execSql, [
|
|
91
|
+
...containerTables,
|
|
92
|
+
...documentTables,
|
|
93
|
+
...localIntentTables,
|
|
93
94
|
// Metadata rows consult document purge checkpoints before writing.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
...keyingCheckpointTables,
|
|
96
|
+
...documentContainerProjectionTables,
|
|
97
|
+
...documentProjectionTables,
|
|
98
|
+
...containerSyncWatermarkTables,
|
|
99
|
+
]));
|
|
99
100
|
},
|
|
100
101
|
async loadHeldContainerBinding(execSql, containerId) {
|
|
101
102
|
await sqlContainerContentsPersistence.ensureSchema(execSql);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerContentsPersistence.js","sourceRoot":"","sources":["containerContentsPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport {\n containerHydrationTombstones,\n containers,\n documentContainerProjectionTables,\n keyingCheckpointTables,\n localIntentTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runOncePerConnection,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport {\n enqueueDocumentPendingUpdate,\n ensureDocumentProjectionTables,\n ensureDocumentTables,\n} from \"../documents/records\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../documents/records/documentPendingUpdatePersistence\";\nimport { getLatestTimestamp } from \"../latestTimestamp\";\nimport {\n ensureContainerTables,\n loadContainerById,\n} from \"./containerPersistence\";\nimport { sqlContainerSyncWatermarkPersistence } from \"./containerSyncWatermarkPersistence\";\nimport {\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n listDormantMetadataSweepRequests,\n} from \"./dormantMetadataSweep\";\n\nexport type {\n ContainerContentsPersistence,\n ContainerCreateIntentRecord,\n ContainerHydrationTombstone,\n ContainerMetadataRecord,\n ContainerMoveIntentRecord,\n LocalRootDescendantReparentInput,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nexport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n SaveContainerOptions,\n SaveContainerWithPendingUpdateOptions,\n} from \"./containerContentsPersistenceTypes\";\nimport { deleteStoredContainers } from \"./containerDeletionPersistence\";\nimport {\n commitStoredHydratedContainer,\n loadStoredHeldContainerBinding,\n} from \"./containerHydrationPersistence\";\nimport { containerIntentPersistence } from \"./containerIntentPersistence\";\nimport {\n commitStoredMetadataMutation,\n settleStoredMetadataPendingUpdates,\n} from \"./containerMetadataMutationPersistence\";\nimport { containerMetadataPullContinuationPersistence } from \"./containerMetadataPullContinuationPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n selectContainersWithMetadataRecords,\n} from \"./containerMetadataRows\";\nimport { abandonStoredMoveIntentRevision } from \"./containerMoveAbandonPersistence\";\nimport { containerPendingUpdatePersistence } from \"./containerPendingUpdatePersistence\";\nimport { rebindStoredHeldContainer } from \"./containerRebindPersistence\";\nimport { containerReconcilePersistence } from \"./containerReconcilePersistence\";\nimport { isSupersededContainerBinding } from \"./supersededContainerBindings\";\n\nasync function saveStoredContainer(\n execSql: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[0],\n container: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[1],\n record: ContainerMetadataRecord | null,\n options?:\n | SaveContainerOptions\n | SaveContainerWithPendingUpdateOptions\n | undefined,\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt =\n options?.localUpdatedAt ?? options?.updatedAt ?? new Date().toISOString();\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const save = async (tx: ClientSQLiteTransactionScope) => {\n const saved = await saveContainerContentsContainerRows({\n container,\n createIntent: options?.createIntent,\n moveIntent: options?.moveIntent,\n record,\n serverTimestamps: options?.serverTimestamps,\n tx,\n localUpdatedAt,\n });\n if (options && \"pendingUpdate\" in options) {\n await enqueueDocumentPendingUpdate(\n lockedExecSql,\n getContainerMetadataScope(container.id),\n options.pendingUpdate,\n );\n }\n return saved;\n };\n if (!options?.stillCurrent) {\n return runtime.transaction(save);\n }\n const outcome = await runtime.guardedTransaction(\n save,\n options.stillCurrent,\n { behavior: \"immediate\" },\n );\n // Guarded callers recheck the same monotonic generation immediately after\n // this await. Returning the untouched candidate keeps the long-standing\n // non-null save contract while the transaction itself remains rolled back.\n return outcome.result ?? container;\n });\n}\n\nexport const sqlContainerContentsPersistence: ContainerContentsPersistence = {\n ...containerIntentPersistence,\n ...containerMetadataPullContinuationPersistence,\n commitHydratedContainer: commitStoredHydratedContainer,\n commitMetadataMutation: commitStoredMetadataMutation,\n settleAcceptedMetadataPendingUpdates: settleStoredMetadataPendingUpdates,\n listDormantMetadataSweepRequests,\n ...containerPendingUpdatePersistence,\n ...containerReconcilePersistence,\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n async containerExists(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ id: containers.id })\n .from(containers)\n .where(eq(containers.id, containerId))\n .limit(1);\n return rows.length > 0;\n },\n async deleteContainer(execSql, containerId, options) {\n await sqlContainerContentsPersistence.deleteContainers(execSql, [\n {\n containerId,\n reason: options?.reason ?? \"deleted\",\n updatedAt: options?.updatedAt ?? new Date().toISOString(),\n },\n ]);\n },\n async deleteContainers(execSql, removals, options) {\n return deleteStoredContainers(execSql, removals, options);\n },\n async ensureSchema(execSql) {\n // Once ensured on this connection, skip the outer mutation lock entirely:\n // ensureSchema runs on every query path, and re-acquiring the lock just to\n // no-op would queue reads behind unrelated writes.\n await runOncePerConnection(execSql, \"ensure:container-contents\", () =>\n runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentTables(lockedExecSql);\n await ensureSqlTables(lockedExecSql, localIntentTables);\n // Metadata rows consult document purge checkpoints before writing.\n await ensureSqlTables(lockedExecSql, keyingCheckpointTables);\n await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);\n await ensureDocumentProjectionTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n }),\n );\n },\n async loadHeldContainerBinding(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return loadStoredHeldContainerBinding(execSql, containerId);\n },\n async isSupersededContainerBinding(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return isSupersededContainerBinding(execSql, input);\n },\n async abandonMoveIntentRevision(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return abandonStoredMoveIntentRevision(execSql, input);\n },\n async rebindHeldContainer(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return rebindStoredHeldContainer(execSql, input);\n },\n async loadContainerMetadataRecord(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return selectContainerMetadataRecord(execSql, containerId);\n },\n async loadContainerHydrationTombstones(execSql) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n containerId: containerHydrationTombstones.containerId,\n generation: containerHydrationTombstones.generation,\n reason: containerHydrationTombstones.reason,\n updatedAt: containerHydrationTombstones.updatedAt,\n })\n .from(containerHydrationTombstones)\n .where(eq(containerHydrationTombstones.cleared, false));\n return rows.flatMap((row) =>\n row.reason === \"access_revoked\" || row.reason === \"deleted\"\n ? [{ ...row, reason: row.reason }]\n : [],\n );\n },\n async loadContainers(execSql) {\n return selectContainersWithMetadataRecords(execSql);\n },\n async loadContainerMetadataState(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const container = await loadContainerById(execSql, containerId);\n if (!container) {\n return null;\n }\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n },\n async saveContainer(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerWithPendingUpdate(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerAndDeletePendingUpdates(\n execSql,\n container,\n record,\n pendingUpdateIds,\n ) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const scope = getContainerMetadataScope(container.id);\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n scope,\n pendingUpdateIds,\n );\n const hasRemainingPendingUpdates = await hasQueuedDocumentUpdates(\n tx,\n scope,\n );\n const containerToSave = hasRemainingPendingUpdates\n ? container\n : {\n ...container,\n serverUpdatedAt: getLatestTimestamp(\n container.serverUpdatedAt,\n localUpdatedAt,\n ),\n };\n\n return saveContainerContentsContainerRows({\n container: containerToSave,\n record,\n tx,\n localUpdatedAt,\n });\n },\n );\n });\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"containerContentsPersistence.js","sourceRoot":"","sources":["containerContentsPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport {\n containerHydrationTombstones,\n containerSyncWatermarkTables,\n containers,\n containerTables,\n documentContainerProjectionTables,\n documentProjectionTables,\n documentTables,\n keyingCheckpointTables,\n localIntentTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runOncePerConnection,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport { enqueueDocumentPendingUpdate } from \"../documents/records\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../documents/records/documentPendingUpdatePersistence\";\nimport { getLatestTimestamp } from \"../latestTimestamp\";\nimport { loadContainerById } from \"./containerPersistence\";\nimport {\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n listDormantMetadataSweepRequests,\n} from \"./dormantMetadataSweep\";\n\nexport type {\n ContainerContentsPersistence,\n ContainerCreateIntentRecord,\n ContainerHydrationTombstone,\n ContainerMetadataRecord,\n ContainerMoveIntentRecord,\n LocalRootDescendantReparentInput,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nexport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n SaveContainerOptions,\n SaveContainerWithPendingUpdateOptions,\n} from \"./containerContentsPersistenceTypes\";\nimport { deleteStoredContainers } from \"./containerDeletionPersistence\";\nimport {\n commitStoredHydratedContainer,\n loadStoredHeldContainerBinding,\n} from \"./containerHydrationPersistence\";\nimport { containerIntentPersistence } from \"./containerIntentPersistence\";\nimport {\n commitStoredMetadataMutation,\n settleStoredMetadataPendingUpdates,\n} from \"./containerMetadataMutationPersistence\";\nimport { containerMetadataPullContinuationPersistence } from \"./containerMetadataPullContinuationPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n selectContainersWithMetadataRecords,\n} from \"./containerMetadataRows\";\nimport { abandonStoredMoveIntentRevision } from \"./containerMoveAbandonPersistence\";\nimport { containerPendingUpdatePersistence } from \"./containerPendingUpdatePersistence\";\nimport { rebindStoredHeldContainer } from \"./containerRebindPersistence\";\nimport { containerReconcilePersistence } from \"./containerReconcilePersistence\";\nimport { isSupersededContainerBinding } from \"./supersededContainerBindings\";\n\nasync function saveStoredContainer(\n execSql: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[0],\n container: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[1],\n record: ContainerMetadataRecord | null,\n options?:\n | SaveContainerOptions\n | SaveContainerWithPendingUpdateOptions\n | undefined,\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt =\n options?.localUpdatedAt ?? options?.updatedAt ?? new Date().toISOString();\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const save = async (tx: ClientSQLiteTransactionScope) => {\n const saved = await saveContainerContentsContainerRows({\n container,\n createIntent: options?.createIntent,\n moveIntent: options?.moveIntent,\n record,\n serverTimestamps: options?.serverTimestamps,\n tx,\n localUpdatedAt,\n });\n if (options && \"pendingUpdate\" in options) {\n await enqueueDocumentPendingUpdate(\n lockedExecSql,\n getContainerMetadataScope(container.id),\n options.pendingUpdate,\n );\n }\n return saved;\n };\n if (!options?.stillCurrent) {\n return runtime.transaction(save);\n }\n const outcome = await runtime.guardedTransaction(\n save,\n options.stillCurrent,\n { behavior: \"immediate\" },\n );\n // Guarded callers recheck the same monotonic generation immediately after\n // this await. Returning the untouched candidate keeps the long-standing\n // non-null save contract while the transaction itself remains rolled back.\n return outcome.result ?? container;\n });\n}\n\nexport const sqlContainerContentsPersistence: ContainerContentsPersistence = {\n ...containerIntentPersistence,\n ...containerMetadataPullContinuationPersistence,\n commitHydratedContainer: commitStoredHydratedContainer,\n commitMetadataMutation: commitStoredMetadataMutation,\n settleAcceptedMetadataPendingUpdates: settleStoredMetadataPendingUpdates,\n listDormantMetadataSweepRequests,\n ...containerPendingUpdatePersistence,\n ...containerReconcilePersistence,\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n async containerExists(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ id: containers.id })\n .from(containers)\n .where(eq(containers.id, containerId))\n .limit(1);\n return rows.length > 0;\n },\n async deleteContainer(execSql, containerId, options) {\n await sqlContainerContentsPersistence.deleteContainers(execSql, [\n {\n containerId,\n reason: options?.reason ?? \"deleted\",\n updatedAt: options?.updatedAt ?? new Date().toISOString(),\n },\n ]);\n },\n async deleteContainers(execSql, removals, options) {\n return deleteStoredContainers(execSql, removals, options);\n },\n async ensureSchema(execSql) {\n // Once ensured on this connection, skip the outer mutation lock entirely:\n // ensureSchema runs on every query path, and re-acquiring the lock just to\n // no-op would queue reads behind unrelated writes.\n await runOncePerConnection(execSql, \"ensure:container-contents\", () =>\n // One ensure, so a cold connection sends three DDL messages in total.\n ensureSqlTables(execSql, [\n ...containerTables,\n ...documentTables,\n ...localIntentTables,\n // Metadata rows consult document purge checkpoints before writing.\n ...keyingCheckpointTables,\n ...documentContainerProjectionTables,\n ...documentProjectionTables,\n ...containerSyncWatermarkTables,\n ]),\n );\n },\n async loadHeldContainerBinding(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return loadStoredHeldContainerBinding(execSql, containerId);\n },\n async isSupersededContainerBinding(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return isSupersededContainerBinding(execSql, input);\n },\n async abandonMoveIntentRevision(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return abandonStoredMoveIntentRevision(execSql, input);\n },\n async rebindHeldContainer(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return rebindStoredHeldContainer(execSql, input);\n },\n async loadContainerMetadataRecord(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return selectContainerMetadataRecord(execSql, containerId);\n },\n async loadContainerHydrationTombstones(execSql) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n containerId: containerHydrationTombstones.containerId,\n generation: containerHydrationTombstones.generation,\n reason: containerHydrationTombstones.reason,\n updatedAt: containerHydrationTombstones.updatedAt,\n })\n .from(containerHydrationTombstones)\n .where(eq(containerHydrationTombstones.cleared, false));\n return rows.flatMap((row) =>\n row.reason === \"access_revoked\" || row.reason === \"deleted\"\n ? [{ ...row, reason: row.reason }]\n : [],\n );\n },\n async loadContainers(execSql) {\n return selectContainersWithMetadataRecords(execSql);\n },\n async loadContainerMetadataState(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const container = await loadContainerById(execSql, containerId);\n if (!container) {\n return null;\n }\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n },\n async saveContainer(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerWithPendingUpdate(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerAndDeletePendingUpdates(\n execSql,\n container,\n record,\n pendingUpdateIds,\n ) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const scope = getContainerMetadataScope(container.id);\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n scope,\n pendingUpdateIds,\n );\n const hasRemainingPendingUpdates = await hasQueuedDocumentUpdates(\n tx,\n scope,\n );\n const containerToSave = hasRemainingPendingUpdates\n ? container\n : {\n ...container,\n serverUpdatedAt: getLatestTimestamp(\n container.serverUpdatedAt,\n localUpdatedAt,\n ),\n };\n\n return saveContainerContentsContainerRows({\n container: containerToSave,\n record,\n tx,\n localUpdatedAt,\n });\n },\n );\n });\n },\n};\n"]}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { documentContainerProjectionTables, documentPlacementIntentTables, keyingCheckpointTables, } from "../../../sqlite/schema/index.js";
|
|
2
|
-
import { ensureSqlTables, runOncePerConnection,
|
|
3
|
-
|
|
1
|
+
import { documentContainerProjectionTables, documentPlacementIntentTables, documentProjectionTables, documentTables, keyingCheckpointTables, } from "../../../sqlite/schema/index.js";
|
|
2
|
+
import { ensureSqlTables, runOncePerConnection, } from "../../../sqlite/sqlSchema.js";
|
|
3
|
+
// One ensure, so a cold connection sends three DDL messages in total.
|
|
4
4
|
export async function ensureDocumentsSchema(execSql) {
|
|
5
|
-
await runOncePerConnection(execSql, "ensure:documents", () =>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
]);
|
|
13
|
-
}));
|
|
5
|
+
await runOncePerConnection(execSql, "ensure:documents", () => ensureSqlTables(execSql, [
|
|
6
|
+
...documentTables,
|
|
7
|
+
...documentProjectionTables,
|
|
8
|
+
...documentContainerProjectionTables,
|
|
9
|
+
...documentPlacementIntentTables,
|
|
10
|
+
...keyingCheckpointTables,
|
|
11
|
+
]));
|
|
14
12
|
}
|
|
15
13
|
//# sourceMappingURL=ensureDocumentsSchema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensureDocumentsSchema.js","sourceRoot":"","sources":["ensureDocumentsSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,eAAe,EACf,oBAAoB,
|
|
1
|
+
{"version":3,"file":"ensureDocumentsSchema.js","sourceRoot":"","sources":["ensureDocumentsSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iCAAiC,EACjC,6BAA6B,EAC7B,wBAAwB,EACxB,cAAc,EACd,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,eAAe,EACf,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AAEnC,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,OAAgB;IAC1D,MAAM,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,CAC3D,eAAe,CAAC,OAAO,EAAE;QACvB,GAAG,cAAc;QACjB,GAAG,wBAAwB;QAC3B,GAAG,iCAAiC;QACpC,GAAG,6BAA6B;QAChC,GAAG,sBAAsB;KAC1B,CAAC,CACH,CAAC;AACJ,CAAC","sourcesContent":["import {\n documentContainerProjectionTables,\n documentPlacementIntentTables,\n documentProjectionTables,\n documentTables,\n keyingCheckpointTables,\n} from \"../../../sqlite/schema\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runOncePerConnection,\n} from \"../../../sqlite/sqlSchema\";\n\n// One ensure, so a cold connection sends three DDL messages in total.\nexport async function ensureDocumentsSchema(execSql: ExecSql): Promise<void> {\n await runOncePerConnection(execSql, \"ensure:documents\", () =>\n ensureSqlTables(execSql, [\n ...documentTables,\n ...documentProjectionTables,\n ...documentContainerProjectionTables,\n ...documentPlacementIntentTables,\n ...keyingCheckpointTables,\n ]),\n );\n}\n"]}
|
|
@@ -10,6 +10,7 @@ import { type SqlTableSchema } from "../sqlTableSchema.js";
|
|
|
10
10
|
* nullable so presentation falls back to `/` for a root and `Untitled`
|
|
11
11
|
* otherwise. Local timestamps track client storage/structural changes, while
|
|
12
12
|
* server timestamps are populated once the container has synced.
|
|
13
|
+
* `(parentId) where parentId is not null` serves child-folder listings.
|
|
13
14
|
*/
|
|
14
15
|
export declare const containers: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
15
16
|
name: "containers";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
1
2
|
import { index, integer, primaryKey, sqliteTable, text, } from "drizzle-orm/sqlite-core";
|
|
2
3
|
import { defineSqlTableSchema } from "../sqlTableSchema.js";
|
|
3
4
|
const accessLevelColumn = "effective_access_level";
|
|
@@ -12,6 +13,7 @@ const accessLevelColumn = "effective_access_level";
|
|
|
12
13
|
* nullable so presentation falls back to `/` for a root and `Untitled`
|
|
13
14
|
* otherwise. Local timestamps track client storage/structural changes, while
|
|
14
15
|
* server timestamps are populated once the container has synced.
|
|
16
|
+
* `(parentId) where parentId is not null` serves child-folder listings.
|
|
15
17
|
*/
|
|
16
18
|
export const containers = sqliteTable("containers", {
|
|
17
19
|
id: text("id"),
|
|
@@ -26,7 +28,12 @@ export const containers = sqliteTable("containers", {
|
|
|
26
28
|
localUpdatedAt: text("local_updated_at").notNull(),
|
|
27
29
|
serverCreatedAt: text("server_created_at"),
|
|
28
30
|
serverUpdatedAt: text("server_updated_at"),
|
|
29
|
-
}, (table) => [
|
|
31
|
+
}, (table) => [
|
|
32
|
+
primaryKey({ columns: [table.id] }),
|
|
33
|
+
index("containers_parent_idx")
|
|
34
|
+
.on(table.parentId)
|
|
35
|
+
.where(sql `${table.parentId} IS NOT NULL`),
|
|
36
|
+
]);
|
|
30
37
|
/**
|
|
31
38
|
* Latest removal observed for each container. Hydration must observe the same
|
|
32
39
|
* generation before fetching verified restoration evidence; unsigned clocks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerSchema.js","sourceRoot":"","sources":["containerSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,IAAI,GACL,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAuB,MAAM,mBAAmB,CAAC;AAE9E,MAAM,iBAAiB,GAAG,wBAAwB,CAAC;AAEnD
|
|
1
|
+
{"version":3,"file":"containerSchema.js","sourceRoot":"","sources":["containerSchema.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n} from \"drizzle-orm/sqlite-core\";\nimport { defineSqlTableSchema, type SqlTableSchema } from \"../sqlTableSchema\";\n\nconst accessLevelColumn = \"effective_access_level\";\n\n/**\n * Materialized local container tree.\n *\n * Container rows describe the tree and its encrypted metadata document;\n * metadata rows live in `documents`. `id` is the primary key for structural\n * lookups. `metadataDocumentId` is the server metadata-document id when known;\n * `systemSlot` is an optional opaque app-owned slot. `displayName` and `icon`\n * are the decrypted metadata projection lists read: `displayName` stays\n * nullable so presentation falls back to `/` for a root and `Untitled`\n * otherwise. Local timestamps track client storage/structural changes, while\n * server timestamps are populated once the container has synced.\n * `(parentId) where parentId is not null` serves child-folder listings.\n */\nexport const containers = sqliteTable(\n \"containers\",\n {\n id: text(\"id\"),\n organizationId: text(\"organization_id\").notNull(),\n parentId: text(\"parent_id\"),\n metadataDocumentId: text(\"metadata_document_id\"),\n systemSlot: text(\"system_slot\"),\n displayName: text(\"display_name\"),\n icon: text(\"icon\"),\n effectiveAccessLevel: text(accessLevelColumn).notNull().default(\"read\"),\n localCreatedAt: text(\"local_created_at\").notNull(),\n localUpdatedAt: text(\"local_updated_at\").notNull(),\n serverCreatedAt: text(\"server_created_at\"),\n serverUpdatedAt: text(\"server_updated_at\"),\n },\n (table) => [\n primaryKey({ columns: [table.id] }),\n index(\"containers_parent_idx\")\n .on(table.parentId)\n .where(sql`${table.parentId} IS NOT NULL`),\n ],\n);\n\n/**\n * Latest removal observed for each container. Hydration must observe the same\n * generation before fetching verified restoration evidence; unsigned clocks\n * never establish a terminal deletion or bypass a concurrent removal. Cleared\n * observations retain their generation so remove/restore/remove cannot reuse it.\n */\nexport const containerHydrationTombstones = sqliteTable(\n \"container_hydration_tombstones\",\n {\n containerId: text(\"container_id\").notNull(),\n generation: integer(\"generation\").notNull().default(1),\n cleared: integer(\"cleared\", { mode: \"boolean\" }).notNull().default(false),\n reason: text(\"reason\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.containerId] })],\n);\n\n/**\n * Organization attribution for container metadata retained after access loss.\n * The container row is removed on revocation, so this marker retains the\n * organization scope needed by a later access-restoration sweep.\n */\nexport const dormantContainerMetadata = sqliteTable(\n \"dormant_container_metadata\",\n {\n containerId: text(\"container_id\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n retainedAt: text(\"retained_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.containerId] }),\n index(\"dormant_container_metadata_organization_idx\").on(\n table.organizationId,\n table.containerId,\n ),\n ],\n);\n\n/**\n * Organizations a held folder was re-homed away from. Purged-organization\n * recovery re-creates folders under their existing ids and a purged\n * organization never returns, so a later proof binding the folder back to one\n * of these organizations is a replay. Retained across remote resets.\n */\nexport const supersededContainerBindings = sqliteTable(\n \"superseded_container_bindings\",\n {\n containerId: text(\"container_id\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n supersededAt: text(\"superseded_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.containerId, table.organizationId] }),\n ],\n);\n\n/**\n * Durable request for a post-access-restoration crawl and sweep. Attempt state\n * enforces exponential backoff and a bounded retry budget across restarts.\n */\nexport const dormantMetadataSweepRequests = sqliteTable(\n \"dormant_metadata_sweep_requests\",\n {\n organizationId: text(\"organization_id\").notNull(),\n requesterUserId: text(\"requester_user_id\").notNull(),\n generation: integer(\"generation\").notNull().default(1),\n attemptCount: integer(\"attempt_count\").notNull().default(0),\n lastAttemptedAt: text(\"last_attempted_at\"),\n requestedAt: text(\"requested_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.organizationId, table.requesterUserId] }),\n ],\n);\n\nexport const containerTableSchemas: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(containers),\n requiredColumns: [\"display_name\", \"icon\"],\n },\n {\n ...defineSqlTableSchema(containerHydrationTombstones),\n requiredColumns: [\"cleared\"],\n },\n defineSqlTableSchema(dormantContainerMetadata),\n defineSqlTableSchema(dormantMetadataSweepRequests),\n defineSqlTableSchema(supersededContainerBindings),\n];\n\nexport const containerSQLiteSchema = {\n containers,\n containerHydrationTombstones,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n supersededContainerBindings,\n};\n"]}
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
* Indexes:
|
|
18
18
|
* - `(localId, slotId)` is the primary key and keeps one pending blob per
|
|
19
19
|
* document attachment slot.
|
|
20
|
-
* - `mimeType` supports blob-browser MIME grouping and sorting.
|
|
21
20
|
*/
|
|
22
21
|
export declare const documentPendingAttachments: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
23
22
|
name: "document_pending_attachments";
|
|
@@ -333,7 +332,6 @@ export declare const documentPendingAttachments: import("drizzle-orm/sqlite-core
|
|
|
333
332
|
* Indexes:
|
|
334
333
|
* - `(localId, slotId)` is the primary key and keeps one projected blob per
|
|
335
334
|
* document attachment slot.
|
|
336
|
-
* - `mimeType` supports blob-browser MIME grouping and sorting.
|
|
337
335
|
*/
|
|
338
336
|
export declare const documentAttachmentBlobProjection: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
339
337
|
name: "document_attachment_blob_projection";
|
|
@@ -18,7 +18,6 @@ import { index, integer, primaryKey, sqliteTable, text, } from "drizzle-orm/sqli
|
|
|
18
18
|
* Indexes:
|
|
19
19
|
* - `(localId, slotId)` is the primary key and keeps one pending blob per
|
|
20
20
|
* document attachment slot.
|
|
21
|
-
* - `mimeType` supports blob-browser MIME grouping and sorting.
|
|
22
21
|
*/
|
|
23
22
|
export const documentPendingAttachments = sqliteTable("document_pending_attachments", {
|
|
24
23
|
localId: text("local_id").notNull(),
|
|
@@ -43,7 +42,6 @@ export const documentPendingAttachments = sqliteTable("document_pending_attachme
|
|
|
43
42
|
uploadStageId: text("upload_stage_id"),
|
|
44
43
|
}, (table) => [
|
|
45
44
|
primaryKey({ columns: [table.localId, table.slotId] }),
|
|
46
|
-
index("document_pending_attachments_mime_type_idx").on(table.mimeType),
|
|
47
45
|
index("document_pending_attachments_storage_key_idx").on(table.storageKey),
|
|
48
46
|
]);
|
|
49
47
|
/**
|
|
@@ -74,7 +72,6 @@ export const documentPendingAttachments = sqliteTable("document_pending_attachme
|
|
|
74
72
|
* Indexes:
|
|
75
73
|
* - `(localId, slotId)` is the primary key and keeps one projected blob per
|
|
76
74
|
* document attachment slot.
|
|
77
|
-
* - `mimeType` supports blob-browser MIME grouping and sorting.
|
|
78
75
|
*/
|
|
79
76
|
export const documentAttachmentBlobProjection = sqliteTable("document_attachment_blob_projection", {
|
|
80
77
|
localId: text("local_id").notNull(),
|
|
@@ -88,7 +85,6 @@ export const documentAttachmentBlobProjection = sqliteTable("document_attachment
|
|
|
88
85
|
detachedAt: text("detached_at"),
|
|
89
86
|
}, (table) => [
|
|
90
87
|
primaryKey({ columns: [table.localId, table.slotId] }),
|
|
91
|
-
index("document_attachment_blob_projection_mime_type_idx").on(table.mimeType),
|
|
92
88
|
index("document_attachment_blob_projection_storage_key_idx").on(table.storageKey),
|
|
93
89
|
]);
|
|
94
90
|
//# sourceMappingURL=documentAttachmentSchema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentAttachmentSchema.js","sourceRoot":"","sources":["documentAttachmentSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,IAAI,GACL,MAAM,yBAAyB,CAAC;AAEjC
|
|
1
|
+
{"version":3,"file":"documentAttachmentSchema.js","sourceRoot":"","sources":["documentAttachmentSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,IAAI,GACL,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,WAAW,CACnD,8BAA8B,EAC9B;IACE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE;IACnC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;IACjC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;IAC5B,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC;IAC3B,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IAC5C,aAAa,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE;IAC/C,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,4EAA4E;IAC5E,6EAA6E;IAC7E,0EAA0E;IAC1E,4EAA4E;IAC5E,iCAAiC;IACjC,YAAY,EAAE,IAAI,CAAC,gBAAgB,CAAC;IACpC,gBAAgB,EAAE,IAAI,CAAC,oBAAoB,CAAC;IAC5C,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC;IAC3B,qBAAqB,EAAE,OAAO,CAAC,0BAA0B,CAAC;IAC1D,cAAc,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAC3C,qBAAqB,EAAE,IAAI,CAAC,yBAAyB,CAAC;IACtD,aAAa,EAAE,IAAI,CAAC,iBAAiB,CAAC;CACvC,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;IACtD,KAAK,CAAC,8CAA8C,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC;CAC3E,CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,WAAW,CACzD,qCAAqC,EACrC;IACE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE;IACnC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;IACjC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;IACvB,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IAC5C,aAAa,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE;IAC/C,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC;CAChC,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;IACtD,KAAK,CAAC,qDAAqD,CAAC,CAAC,EAAE,CAC7D,KAAK,CAAC,UAAU,CACjB;CACF,CACF,CAAC","sourcesContent":["import {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n} from \"drizzle-orm/sqlite-core\";\n\n/**\n * Pending attachment uploads for local document changes.\n *\n * These rows describe attachment blobs referenced by local document mutations\n * that have not yet been folded into the synced attachment/blob projection.\n * Once the attachment is accepted or discarded, the pending row is removed.\n *\n * Columns:\n * - `localId`: Local document id that owns the attachment slot.\n * - `slotId`: Stable attachment slot id within the document.\n * - `name`: User-facing attachment filename.\n * - `mimeType`: Optional MIME type supplied for the blob.\n * - `storageKey`: Local blob storage key for upload/readback.\n * - `byteLength`: Blob size in bytes.\n * - `createdAt`: Queue insertion timestamp used for ordered display.\n *\n * Indexes:\n * - `(localId, slotId)` is the primary key and keeps one pending blob per\n * document attachment slot.\n */\nexport const documentPendingAttachments = sqliteTable(\n \"document_pending_attachments\",\n {\n localId: text(\"local_id\").notNull(),\n slotId: text(\"slot_id\").notNull(),\n name: text(\"name\").notNull(),\n mimeType: text(\"mime_type\"),\n storageKey: text(\"storage_key\").notNull(),\n byteLength: integer(\"byte_length\").notNull(),\n contentSha256: text(\"content_sha256\").notNull(),\n createdAt: text(\"created_at\").notNull(),\n // Upload-resume identity, set on the first upload attempt. Reusing the blob\n // id, content key and IV seed makes every encrypted chunk byte-identical, so\n // the persisted multipart stage can resume instead of being orphaned. All\n // nullable: only in-flight uploads have them, and they are dropped with the\n // row once the upload completes.\n uploadBlobId: text(\"upload_blob_id\"),\n uploadContentKey: text(\"upload_content_key\"),\n uploadIv: text(\"upload_iv\"),\n uploadContentKeyEpoch: integer(\"upload_content_key_epoch\"),\n uploadPartSize: integer(\"upload_part_size\"),\n uploadPlaintextSha256: text(\"upload_plaintext_sha256\"),\n uploadStageId: text(\"upload_stage_id\"),\n },\n (table) => [\n primaryKey({ columns: [table.localId, table.slotId] }),\n index(\"document_pending_attachments_storage_key_idx\").on(table.storageKey),\n ],\n);\n\n/**\n * Local attachment blob projection for stored documents.\n *\n * This table tracks the attachment blobs currently available to the client for\n * each document slot. `blobId` is optional because the local storage key can be\n * known before the server blob identity has been assigned or downloaded.\n *\n * Columns:\n * - `localId`: Local document id that owns the attachment slot.\n * - `slotId`: Stable attachment slot id within the document.\n * - `blobId`: Server blob id when known.\n * - `storageKey`: Local blob storage key for opening the attachment.\n * - `mimeType`: Optional MIME type associated with the blob.\n * - `byteLength`: Blob size in bytes.\n * - `contentSha256`: Plaintext digest of the bytes held at `storageKey`. The\n * document content records the digest it intends for the slot; a held copy\n * whose digest differs is a validly signed served binding the document has\n * not (yet) recorded, and read models flag it rather than hide it.\n * - `updatedAt`: Local timestamp for the attachment projection update.\n * - `detachedAt`: Local timestamp set when the slot is unlinked from a synced\n * document. The row outlives the unlink because it is also the durable\n * \"still needs a remote detach\" marker (see `syncDetachedAttachments`), so\n * read models that answer \"what references this blob\" must skip detached\n * rows instead of waiting for the detach to flush.\n *\n * Indexes:\n * - `(localId, slotId)` is the primary key and keeps one projected blob per\n * document attachment slot.\n */\nexport const documentAttachmentBlobProjection = sqliteTable(\n \"document_attachment_blob_projection\",\n {\n localId: text(\"local_id\").notNull(),\n slotId: text(\"slot_id\").notNull(),\n blobId: text(\"blob_id\"),\n storageKey: text(\"storage_key\").notNull(),\n mimeType: text(\"mime_type\"),\n byteLength: integer(\"byte_length\").notNull(),\n contentSha256: text(\"content_sha256\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n detachedAt: text(\"detached_at\"),\n },\n (table) => [\n primaryKey({ columns: [table.localId, table.slotId] }),\n index(\"document_attachment_blob_projection_storage_key_idx\").on(\n table.storageKey,\n ),\n ],\n);\n"]}
|
|
@@ -1298,6 +1298,8 @@ export declare const trustedUserIdentityPins: import("drizzle-orm/sqlite-core").
|
|
|
1298
1298
|
* Indexes:
|
|
1299
1299
|
* - `(documentId, containerId)` is the primary key and prevents duplicate
|
|
1300
1300
|
* links for the same document/container pair.
|
|
1301
|
+
* - `(containerId, documentId)` serves the container-filtered link scans
|
|
1302
|
+
* (folder item and sidebar windows) as a covering index search.
|
|
1301
1303
|
*/
|
|
1302
1304
|
export declare const documentContainerProjection: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
1303
1305
|
name: "document_container_projection";
|
|
@@ -176,6 +176,10 @@ export const documentHistoryUpdates = sqliteTable("document_history_updates", {
|
|
|
176
176
|
uniqueIndex("document_history_updates_update_id_idx")
|
|
177
177
|
.on(table.updateId)
|
|
178
178
|
.where(sql `${table.updateId} IS NOT NULL`),
|
|
179
|
+
// Queued rows only: pending counts and pending loads skip settled history.
|
|
180
|
+
index("document_history_updates_queued_scope_idx")
|
|
181
|
+
.on(table.appKind, table.localId, table.createdAt)
|
|
182
|
+
.where(sql `${table.updateId} IS NOT NULL`),
|
|
179
183
|
]);
|
|
180
184
|
/**
|
|
181
185
|
* Anti-rollback pin for verified access manifests.
|
|
@@ -280,12 +284,17 @@ export const trustedUserIdentityPins = sqliteTable("trusted_user_identity_pins",
|
|
|
280
284
|
* Indexes:
|
|
281
285
|
* - `(documentId, containerId)` is the primary key and prevents duplicate
|
|
282
286
|
* links for the same document/container pair.
|
|
287
|
+
* - `(containerId, documentId)` serves the container-filtered link scans
|
|
288
|
+
* (folder item and sidebar windows) as a covering index search.
|
|
283
289
|
*/
|
|
284
290
|
export const documentContainerProjection = sqliteTable("document_container_projection", {
|
|
285
291
|
documentId: text("document_id").notNull(),
|
|
286
292
|
containerId: text("container_id").notNull(),
|
|
287
293
|
updatedAt: text("updated_at").notNull(),
|
|
288
|
-
}, (table) => [
|
|
294
|
+
}, (table) => [
|
|
295
|
+
primaryKey({ columns: [table.documentId, table.containerId] }),
|
|
296
|
+
index("document_container_projection_container_idx").on(table.containerId, table.documentId),
|
|
297
|
+
]);
|
|
289
298
|
/**
|
|
290
299
|
* Queryable document summary and detail projection.
|
|
291
300
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n uniqueIndex,\n} from \"drizzle-orm/sqlite-core\";\nimport { defineSqlTableSchema, type SqlTableSchema } from \"../sqlTableSchema\";\nimport { containerDocumentTombstoneHolds } from \"./containerDocumentTombstoneHoldSchema\";\nimport {\n containerSQLiteSchema,\n containerTableSchemas,\n} from \"./containerSchema\";\nimport {\n documentAttachmentBlobProjection,\n documentPendingAttachments,\n} from \"./documentAttachmentSchema\";\nimport {\n documentDiscoveryHeads,\n documentDiscoverySequence,\n pendingDocumentDiscoveries,\n} from \"./documentDiscoveryEvidenceSchema\";\nimport {\n documentOrphanBlobReclaims,\n documentOrphanBlobReclaimTable,\n} from \"./documentOrphanBlobReclaimSchema\";\nimport { documentIntentLinkTargets } from \"./documentPlacementIntentSchema\";\nimport { localIntents } from \"./localIntentSchema\";\nimport * as organizationDataUsage from \"./organizationDataUsageSchema\";\nimport { organizationFounders } from \"./organizationFounderSchema\";\nimport * as provisioningAttempt from \"./organizationProvisioningAttemptSchema\";\nimport {\n organizationReadModelSQLiteSchema,\n organizationReadModelTables,\n} from \"./organizationReadModelTableRegistry\";\nimport * as organizationSyncPause from \"./organizationSyncPauseSchema\";\nimport { principalGrantRetirements } from \"./principalGrantRetirementSchema\";\nimport {\n principalHistoryEntries,\n principalHistoryEvidenceTables,\n principalHistoryNodes,\n principalHistoryPrefixes,\n} from \"./principalHistoryEvidenceSchema\";\nimport {\n principalHistoryNodeReferences,\n principalHistoryRootOwners,\n} from \"./principalHistoryNodeRetentionSchema\";\nimport { principalKeyEnvelopeArchive } from \"./principalHistoryRetentionSchema\";\nimport {\n principalHistoryStages,\n principalHistoryStageTables,\n} from \"./principalHistoryStageSchema\";\nimport {\n principalMutationJournal,\n principalMutationJournalTables,\n} from \"./principalMutationJournalSchema\";\nimport {\n principalPolicies,\n principalPolicyBundleHistory,\n principalPolicyBundleReferences,\n principalPolicyCheckpoints,\n principalPolicyOrganizations,\n} from \"./principalPolicySchema\";\nimport {\n securityIncidents,\n securityIncidentTable,\n} from \"./securityIncidentSchema\";\nimport {\n verifiedAccessManifestBundles,\n verifiedManifestBundleTables,\n} from \"./verifiedManifestBundleSchema\";\n\nexport {\n containerHydrationTombstones,\n containers,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n supersededContainerBindings,\n} from \"./containerSchema\";\nexport {\n documentAttachmentBlobProjection,\n documentPendingAttachments,\n} from \"./documentAttachmentSchema\";\nexport {\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n LOCAL_INTENT_SUBJECT,\n localIntents,\n} from \"./localIntentSchema\";\nexport {\n principalPolicies,\n principalPolicyBundleHistory,\n principalPolicyBundleReferences,\n principalPolicyCheckpoints,\n principalPolicyOrganizations,\n} from \"./principalPolicySchema\";\nexport { securityIncidents } from \"./securityIncidentSchema\";\nexport { containerDocumentTombstoneHolds, organizationReadModelTables };\n\nconst accessLevelColumn = \"effective_access_level\";\n\n/**\n * Durable Loro-backed document records shared by app features.\n *\n * This table stores encrypted document runtime state for multiple app domains.\n * `appKind` namespaces records for documents and container metadata. User-facing\n * list data is projected into feature-specific read models.\n *\n * Columns:\n * - `appKind`: Local domain namespace for the row, such as `documents` or\n * `container-metadata`.\n * - `localId`: Stable local id inside `appKind`. It may be created before a\n * server `documentId` exists.\n * - `documentId`: Server document id once the record is known remotely, or\n * `null` while the document is local-only.\n * - `accessEpoch`: Latest access epoch persisted for the document. Defaults to\n * the initial epoch.\n * - `accessStateHash`: Current document access/manifest state hash returned by\n * sync, when known.\n * - `lastCommitLsn`: Last remote commit cursor applied to this local document.\n * - `documentManifestBundle`: Serialized document manifest bundle used for\n * encrypted document sync.\n * - `contentKeyBundle`: Serialized content-key material needed to open the\n * local document.\n * - `documentKekTargets`: Serialized KEK target state for document key wraps.\n * - `pendingBaseVersion`: Encoded oplog version through which every persisted\n * op is already enqueued or synced. Persisted so a restart restores the\n * outgoing-delta marker instead of re-seeding it past a device-first\n * `deferRemoteSync` write's un-advanced op. `null` when unset.\n * - `snapshotEndVersion`: Encoded end version vector of the persisted content\n * (which lives in the durable-history tables, never on this row), written on\n * every content persist. Lets the pending-write queue's deferred-tail scan\n * compare version coverage without loading content. Empty string when the\n * document has never hydrated content, which readers treat as \"no deferred\n * tail claimable\".\n * - `recoveryGeneration`: Atomic raw-history recovery writer fence.\n * - `recoveryDocumentId`: Former server id for cross-client post-purge recreation.\n * - `pullContinuation`: Durable progress for the next bounded remote pull.\n * - `syncFailureStatus`, `syncFailureMessage`, `syncFailureAttemptedAt`: The\n * last terminal sync failure or quarantined incoming update for this scope.\n * The durable write queue (queued rows of `documentHistoryUpdates`) has no\n * status columns, so these let the write-queue view and footer explain why\n * the document is blocked. `syncFailureMessage` is non-null exactly when a\n * failure is recorded; a newer failure replaces the old, and a later fully\n * validated sync pass, a remote reset, or the scope's teardown clears all\n * three.\n * - `updatedAt`: Local timestamp for the last persisted runtime-state update.\n *\n * Indexes:\n * - `(appKind, localId)` is the primary key and scopes local document lookups.\n * - `(appKind, documentId) where documentId is not null` supports resolving a\n * server document id back to the local row during discovery and relinking.\n */\nexport const documents = sqliteTable(\n \"documents\",\n {\n appKind: text(\"app_kind\").notNull(),\n localId: text(\"local_id\").notNull(),\n documentId: text(\"document_id\"),\n accessEpoch: integer(\"access_epoch\").notNull().default(1),\n accessStateHash: text(\"access_state_hash\"),\n effectiveAccessLevel: text(accessLevelColumn).notNull().default(\"read\"),\n lastCommitLsn: text(\"last_commit_lsn\"),\n documentManifestBundle: text(\"document_manifest_bundle\"),\n contentKeyBundle: text(\"content_key_bundle\"),\n documentKekTargets: text(\"document_kek_targets\"),\n pendingBaseVersion: text(\"pending_base_version\"),\n pullContinuation: text(\"pull_continuation\"),\n recoveryGeneration: integer(\"recovery_generation\").notNull().default(0),\n recoveryDocumentId: text(\"recovery_document_id\"),\n snapshotEndVersion: text(\"snapshot_end_version\").notNull().default(\"\"),\n syncFailureStatus: integer(\"sync_failure_status\"),\n syncFailureMessage: text(\"sync_failure_message\"),\n syncFailureAttemptedAt: text(\"sync_failure_attempted_at\"),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.appKind, table.localId] }),\n index(\"documents_app_document_idx\")\n .on(table.appKind, table.documentId)\n .where(sql`${table.documentId} IS NOT NULL`),\n ],\n);\n\n/**\n * Full-history persistence for local documents (checkpoint + tail) — the ONLY\n * durable content source. Record rows in `documents` carry runtime metadata\n * and the content frontier (`snapshotEndVersion`), never content. The\n * checkpoint holds a full-history snapshot refreshed only at compaction, and\n * the tail appends every update (local deltas and decrypted remote updates)\n * written since. Restore = import checkpoint + replay tail; compaction =\n * export full history from the live doc, replace the checkpoint, clear the\n * tail — all bounded and amortized. Container metadata stores its content (an\n * exported-updates blob) as its checkpoint row, with no tail.\n */\nexport const documentHistoryCheckpoints = sqliteTable(\n \"document_history_checkpoints\",\n {\n appKind: text(\"app_kind\").notNull(),\n localId: text(\"local_id\").notNull(),\n snapshot: text(\"snapshot\").notNull(),\n endVersionVector: text(\"end_version_vector\").notNull(),\n revision: text(\"revision\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.appKind, table.localId] })],\n);\n\n/**\n * The local update log: one row per Loro update, serving as both the history\n * tail (restore = checkpoint + tail) and the outbound write queue.\n *\n * Every locally authored update is stored once. While it waits for sync it\n * carries an `updateId` (the id submitted to the server) and the version-vector\n * metadata the submission needs; settlement clears them, leaving the row as\n * ordinary tail history until compaction folds it into a checkpoint.\n *\n * Columns:\n * - `id`: Row id; tail compaction deletes by it.\n * - `appKind`, `localId`: Document scope matching `documents`.\n * - `updateData`: Serialized Loro update payload.\n * - `origin`: \"local\" (authored on this device) or \"remote\" (decrypted\n * pulled update) for tail rows. Restores use it to advance the\n * outgoing-delta marker across remote rows — their ops are already\n * server-side — while a local row left behind by a crash stays below the\n * marker so the next edit re-derives and sends it. \"outbox\" marks a queued\n * update with no tail role (container metadata, whose content is its\n * checkpoint, and full-state re-uploads after a remote reset); restores and\n * compaction never see it and settlement deletes it.\n * - `createdAt`: Insertion timestamp; with `rowid`, deterministic replay order.\n * - `updateId`: Present exactly while the row is queued for sync; rekeyed\n * after a lost acknowledgement poisons the submitted id.\n * - `partialStartVersionVector` / `partialEndVersionVector`: Version vectors\n * around a queued partial update.\n * - `sourceVersionVector`: Present on a queued rotation baseline checkpoint.\n * - `rekeyCount`: Durable bound on rekeys of a queued row.\n *\n * Invariant: compaction never deletes a queued row, so a checkpoint can cover\n * a queued update's operations without removing it from the queue.\n */\nexport const documentHistoryUpdates = sqliteTable(\n \"document_history_updates\",\n {\n id: text(\"id\"),\n appKind: text(\"app_kind\").notNull(),\n localId: text(\"local_id\").notNull(),\n updateData: text(\"update_data\").notNull(),\n origin: text(\"origin\").notNull(),\n createdAt: text(\"created_at\").notNull(),\n updateId: text(\"update_id\"),\n partialStartVersionVector: text(\"partial_start_version_vector\"),\n partialEndVersionVector: text(\"partial_end_version_vector\"),\n sourceVersionVector: text(\"source_version_vector\"),\n rekeyCount: integer(\"rekey_count\").notNull().default(0),\n },\n (table) => [\n primaryKey({ columns: [table.id] }),\n index(\"document_history_updates_scope_created_idx\").on(\n table.appKind,\n table.localId,\n table.createdAt,\n ),\n uniqueIndex(\"document_history_updates_update_id_idx\")\n .on(table.updateId)\n .where(sql`${table.updateId} IS NOT NULL`),\n ],\n);\n\n/**\n * Anti-rollback pin for verified access manifests.\n *\n * Records the highest access-manifest epoch this client has verified for each\n * object, so a later projection that serves an older epoch (rollback) or a\n * conflicting manifest at the same epoch (equivocation) is detected before any\n * key is unwrapped. Updated monotonically after a projection verifies cleanly.\n *\n * Columns:\n * - `objectKind`: Access object kind (`container`, `document`, ...).\n * - `organizationId`: Organization boundary that owns the object.\n * - `objectId`: Stable object id.\n * - `epoch`: Highest verified manifest epoch.\n * - `manifestHash`: Manifest hash pinned at that epoch.\n * - `updatedAt`: Local timestamp for the pin.\n *\n * Indexes:\n * - `(objectKind, organizationId, objectId)` is the primary key and gives one\n * pin per object.\n */\nexport const accessManifestCheckpoints = sqliteTable(\n \"access_manifest_checkpoints\",\n {\n objectKind: text(\"object_kind\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n objectId: text(\"object_id\").notNull(),\n epoch: integer(\"epoch\").notNull(),\n manifestHash: text(\"manifest_hash\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.objectKind, table.organizationId, table.objectId],\n }),\n ],\n);\n\n/**\n * Durable terminal pins for documents whose signed purge proof was verified.\n * These survive remote-state resets so a dishonest API cannot later replay the\n * pre-purge writer projection and resurrect locally deleted content.\n */\nexport const documentPurgeCheckpoints = sqliteTable(\n \"document_purge_checkpoints\",\n {\n documentId: text(\"document_id\").primaryKey(),\n organizationId: text(\"organization_id\").notNull(),\n documentManifestHash: text(\"document_manifest_hash\").notNull(),\n purgeEventHash: text(\"purge_event_hash\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n);\n\n/**\n * Durable pins for user identity bundles.\n *\n * The first validated identity accepted for a user in a configured API trust\n * domain is inserted once. Later observations must match every suite, public\n * key, and fingerprint exactly; the persistence adapter never changes those\n * columns. `firstSeenAt` records when the local trust decision was made and is\n * likewise immutable. `provenance` (`self`, `link`, or `observed`) records how\n * the pin was established; only `self` and `link` admit a user, and it only\n * rises. A table without it is an obsolete local database.\n *\n * Indexes:\n * - `(identityTrustDomain, userId)` is the primary key and scopes a user pin to\n * the host-configured API authority that supplied it.\n * - `(identityTrustDomain, signingKeyFingerprint)` binds the reverse identity\n * mapping durably, including across session recreation. There is no\n * migration for a table that already violates it. Earlier builds pinned a\n * registration's user id before the server confirmed it, so a device that\n * ran one may hold two users on one key; deployments are greenfield, and\n * such a device clears its local data, which recreates this table empty. A\n * device that used an environment before a reset does the same (see\n * docs/developer/greenfield-reset.md).\n */\nexport const trustedUserIdentityPins = sqliteTable(\n \"trusted_user_identity_pins\",\n {\n identityTrustDomain: text(\"identity_trust_domain\").notNull(),\n userId: text(\"user_id\").notNull(),\n formatVersion: integer(\"format_version\").notNull(),\n signingSuite: text(\"signing_suite\").notNull(),\n signingPublicKey: text(\"signing_public_key\").notNull(),\n signingKeyFingerprint: text(\"signing_key_fingerprint\").notNull(),\n encapsulationSuite: text(\"encapsulation_suite\").notNull(),\n encapsulationPublicKey: text(\"encapsulation_public_key\").notNull(),\n encapsulationKeyFingerprint: text(\n \"encapsulation_key_fingerprint\",\n ).notNull(),\n firstSeenAt: text(\"first_seen_at\").notNull(),\n provenance: text(\"provenance\", {\n enum: [\"self\", \"link\", \"observed\"],\n }).notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.identityTrustDomain, table.userId],\n }),\n uniqueIndex(\"trusted_user_identity_pins_domain_signing_fingerprint_idx\").on(\n table.identityTrustDomain,\n table.signingKeyFingerprint,\n ),\n ],\n);\n\n/**\n * Local many-to-many projection between documents and containers.\n *\n * The document summary row stores one selected `containerId` for primary list\n * placement, while this table keeps the full set of linked containers returned\n * by container/document sync. Removing a container deletes its links and may\n * repair affected document summary rows to point at another remaining link.\n *\n * Columns:\n * - `documentId`: Server document id whose container links are projected.\n * - `containerId`: Linked container id.\n * - `updatedAt`: Local timestamp for the last replacement of the link set.\n *\n * Indexes:\n * - `(documentId, containerId)` is the primary key and prevents duplicate\n * links for the same document/container pair.\n */\nexport const documentContainerProjection = sqliteTable(\n \"document_container_projection\",\n {\n documentId: text(\"document_id\").notNull(),\n containerId: text(\"container_id\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.documentId, table.containerId] })],\n);\n\n/**\n * Queryable document summary and detail projection.\n *\n * The durable Loro state lives in `documents`. This table stores the fields the\n * app needs for document lists, summaries, and fast detail hydration without\n * opening the full Loro snapshot on every read.\n *\n * Columns:\n * - `localId`: Stable local document id. This joins to `documents.localId` for\n * rows where `documents.appKind = documents`.\n * - `documentId`: Server document id when known.\n * - `containerId`: Selected container for primary document placement, or\n * `null` if the document is not currently linked to a visible container.\n * - `organizationId`: Last-known owning organization. Stamped from the\n * container row when the document is detached because its container was\n * removed locally (e.g. access to a shared org was revoked and the container\n * tombstoned), so pending writes keep their org attribution after the\n * `containers` join source disappears. Read as a fallback only — a live\n * container join always wins.\n * - `documentKind`: Stored document kind. Defaults to `note`.\n * - `title`: Plain projected title. Defaults to the note fallback title.\n * - `updatedAt`: Timestamp used for document list ordering.\n *\n * The projected full text lives in `documentProjectionText`, keyed by the same\n * `localId`. Keeping it out of this row keeps list/window scans narrow: the\n * sidebar and summary queries read titles and placement from rows whose size\n * does not grow with document content.\n *\n * Indexes:\n * - `localId` is the primary key for document projection lookups.\n * - `(containerId) where containerId is not null` serves container-scoped\n * window/count scans without walking the whole table.\n * - `(organizationId) where containerId is null` serves the orphan-recovery\n * existence and window scans.\n * - `(documentId) where documentId is not null` serves the linked-placement\n * join from `documentContainerProjection` and server-id lookups.\n */\nexport const documentProjection = sqliteTable(\n \"document_projection\",\n {\n localId: text(\"local_id\"),\n documentId: text(\"document_id\"),\n containerId: text(\"container_id\"),\n organizationId: text(\"organization_id\"),\n documentKind: text(\"document_kind\").notNull().default(\"note\"),\n title: text(\"title\").notNull().default(\"Untitled note\"),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.localId] }),\n index(\"document_projection_container_idx\")\n .on(table.containerId)\n .where(sql`${table.containerId} IS NOT NULL`),\n index(\"document_projection_orphan_organization_idx\")\n .on(table.organizationId)\n .where(sql`${table.containerId} IS NULL`),\n index(\"document_projection_document_idx\")\n .on(table.documentId)\n .where(sql`${table.documentId} IS NOT NULL`),\n ],\n);\n\n/**\n * Projected document text, split from `documentProjection` so content size\n * never bloats the rows that list/window queries scan. Loaded only by detail\n * reads (`loadDocument`) and the save-timestamp change check.\n *\n * Columns:\n * - `localId`: Stable local document id, matching `documentProjection.localId`.\n * - `text`: Plain projected text used to rebuild summaries/details.\n */\nexport const documentProjectionText = sqliteTable(\n \"document_projection_text\",\n {\n localId: text(\"local_id\"),\n text: text(\"text\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.localId] })],\n);\n\n/**\n * Per-lane sync state for container data: the server cursor and the local\n * freshness marker share one row per lane.\n *\n * Container sync is split into lanes, such as a parent-container child lane or\n * a container-document membership lane. The cursor lets the next request\n * resume without replaying the entire tree. The freshness marker records the\n * last fully drained check independently of the cursor: empty server\n * responses do not always carry a new watermark, but startup still needs to\n * know that it recently checked the lane before polling again.\n *\n * Columns:\n * - `laneKind`: Sync lane category, such as `container_parent` or\n * `container_documents`.\n * - `laneId`: Lane identity. Root parent sync uses `root`, child sync uses a\n * parent-prefixed container id, and document lanes use the container id.\n * - `watermarkUpdatedAt`: Server `updatedAt` value for the stored watermark;\n * null until a watermark is saved.\n * - `watermarkId`: Server id tie-breaker for the stored watermark; null\n * exactly when `watermarkUpdatedAt` is.\n * - `updatedAt`: Local timestamp for when the cursor was saved.\n * - `checkedAt`: Local timestamp for the most recent fully drained lane check;\n * null until one completes.\n *\n * Indexes:\n * - `(laneKind, laneId)` is the primary key and stores one row per lane.\n */\nexport const containerSyncWatermarks = sqliteTable(\n \"container_sync_watermarks\",\n {\n laneKind: text(\"lane_kind\").notNull(),\n laneId: text(\"lane_id\").notNull(),\n watermarkUpdatedAt: text(\"watermark_updated_at\"),\n watermarkId: text(\"watermark_id\"),\n updatedAt: text(\"updated_at\"),\n checkedAt: text(\"checked_at\"),\n },\n (table) => [primaryKey({ columns: [table.laneKind, table.laneId] })],\n);\n\nexport const documentTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(documents),\n requiredColumns: [\n \"pull_continuation\",\n \"recovery_generation\",\n \"recovery_document_id\",\n \"sync_failure_status\",\n \"sync_failure_message\",\n \"sync_failure_attempted_at\",\n ],\n },\n defineSqlTableSchema(documentHistoryCheckpoints),\n {\n ...defineSqlTableSchema(documentHistoryUpdates),\n requiredColumns: [\"update_id\"],\n },\n];\n\nexport const principalPolicyTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(principalPolicies),\n requiredColumns: [\"current_grants_json\"],\n },\n {\n ...defineSqlTableSchema(principalPolicyBundleHistory),\n requiredColumns: [\"current_grants_json\"],\n },\n defineSqlTableSchema(principalPolicyBundleReferences),\n defineSqlTableSchema(principalPolicyOrganizations),\n ...principalHistoryStageTables,\n ...principalHistoryEvidenceTables,\n];\n\nexport const keyingCheckpointTables: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(organizationFounders),\n defineSqlTableSchema(accessManifestCheckpoints),\n defineSqlTableSchema(principalGrantRetirements),\n defineSqlTableSchema(documentPurgeCheckpoints),\n defineSqlTableSchema(principalPolicyCheckpoints),\n];\n\nexport const trustedUserIdentityPinTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(trustedUserIdentityPins),\n requiredColumns: [\"provenance\"],\n },\n];\n\nconst securityIncidentTables: ReadonlyArray<SqlTableSchema> = [\n securityIncidentTable,\n];\n\nexport const containerTables = containerTableSchemas;\n\nexport const documentContainerProjectionTables: ReadonlyArray<SqlTableSchema> =\n [\n defineSqlTableSchema(documentContainerProjection),\n {\n ...defineSqlTableSchema(containerDocumentTombstoneHolds),\n requiredColumns: [\"hidden\"],\n },\n defineSqlTableSchema(pendingDocumentDiscoveries),\n {\n ...defineSqlTableSchema(documentDiscoveryHeads),\n requiredColumns: [\"organization_id\"],\n },\n defineSqlTableSchema(documentDiscoverySequence),\n ];\n\nexport const localIntentTables: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(localIntents),\n];\n\nexport const documentPlacementIntentTables: ReadonlyArray<SqlTableSchema> = [\n ...localIntentTables,\n defineSqlTableSchema(documentIntentLinkTargets),\n];\n\nexport const documentProjectionTables: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(documentProjection),\n defineSqlTableSchema(documentProjectionText),\n {\n ...defineSqlTableSchema(documentPendingAttachments),\n requiredColumns: [\"content_sha256\"],\n },\n {\n ...defineSqlTableSchema(documentAttachmentBlobProjection),\n requiredColumns: [\"content_sha256\"],\n },\n documentOrphanBlobReclaimTable,\n];\n\nexport const containerSyncWatermarkTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(containerSyncWatermarks),\n requiredColumns: [\"checked_at\"],\n },\n];\n\nexport const clientSqlTables: ReadonlyArray<SqlTableSchema> = [\n ...principalMutationJournalTables,\n ...documentTables,\n ...principalPolicyTables,\n ...keyingCheckpointTables,\n ...verifiedManifestBundleTables,\n ...trustedUserIdentityPinTables,\n ...securityIncidentTables,\n ...containerTables,\n ...documentContainerProjectionTables,\n ...documentPlacementIntentTables,\n ...documentProjectionTables,\n ...containerSyncWatermarkTables,\n ...organizationReadModelTables,\n ...organizationDataUsage.organizationDataUsageTables,\n ...provisioningAttempt.organizationProvisioningAttemptTables,\n ...organizationSyncPause.organizationSyncPauseTables,\n];\n\nexport const clientSQLiteSchema = {\n principalHistoryNodeReferences,\n principalHistoryRootOwners,\n principalKeyEnvelopeArchive,\n principalMutationJournal,\n principalHistoryEntries,\n principalHistoryNodes,\n principalHistoryPrefixes,\n principalHistoryStages,\n organizationFounders,\n principalGrantRetirements,\n documents,\n principalPolicies,\n principalPolicyBundleHistory,\n principalPolicyBundleReferences,\n principalPolicyOrganizations,\n accessManifestCheckpoints,\n documentPurgeCheckpoints,\n principalPolicyCheckpoints,\n verifiedAccessManifestBundles,\n trustedUserIdentityPins,\n securityIncidents,\n ...containerSQLiteSchema,\n documentContainerProjection,\n localIntents,\n documentIntentLinkTargets,\n documentProjection,\n documentPendingAttachments,\n documentAttachmentBlobProjection,\n documentOrphanBlobReclaims: documentOrphanBlobReclaims,\n containerSyncWatermarks,\n ...organizationReadModelSQLiteSchema,\n ...organizationDataUsage.organizationDataUsageSQLiteSchema,\n ...provisioningAttempt.organizationProvisioningAttemptSQLiteSchema,\n ...organizationSyncPause.organizationSyncPauseSQLiteSchema,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n uniqueIndex,\n} from \"drizzle-orm/sqlite-core\";\nimport { defineSqlTableSchema, type SqlTableSchema } from \"../sqlTableSchema\";\nimport { containerDocumentTombstoneHolds } from \"./containerDocumentTombstoneHoldSchema\";\nimport {\n containerSQLiteSchema,\n containerTableSchemas,\n} from \"./containerSchema\";\nimport {\n documentAttachmentBlobProjection,\n documentPendingAttachments,\n} from \"./documentAttachmentSchema\";\nimport {\n documentDiscoveryHeads,\n documentDiscoverySequence,\n pendingDocumentDiscoveries,\n} from \"./documentDiscoveryEvidenceSchema\";\nimport {\n documentOrphanBlobReclaims,\n documentOrphanBlobReclaimTable,\n} from \"./documentOrphanBlobReclaimSchema\";\nimport { documentIntentLinkTargets } from \"./documentPlacementIntentSchema\";\nimport { localIntents } from \"./localIntentSchema\";\nimport * as organizationDataUsage from \"./organizationDataUsageSchema\";\nimport { organizationFounders } from \"./organizationFounderSchema\";\nimport * as provisioningAttempt from \"./organizationProvisioningAttemptSchema\";\nimport {\n organizationReadModelSQLiteSchema,\n organizationReadModelTables,\n} from \"./organizationReadModelTableRegistry\";\nimport * as organizationSyncPause from \"./organizationSyncPauseSchema\";\nimport { principalGrantRetirements } from \"./principalGrantRetirementSchema\";\nimport {\n principalHistoryEntries,\n principalHistoryEvidenceTables,\n principalHistoryNodes,\n principalHistoryPrefixes,\n} from \"./principalHistoryEvidenceSchema\";\nimport {\n principalHistoryNodeReferences,\n principalHistoryRootOwners,\n} from \"./principalHistoryNodeRetentionSchema\";\nimport { principalKeyEnvelopeArchive } from \"./principalHistoryRetentionSchema\";\nimport {\n principalHistoryStages,\n principalHistoryStageTables,\n} from \"./principalHistoryStageSchema\";\nimport {\n principalMutationJournal,\n principalMutationJournalTables,\n} from \"./principalMutationJournalSchema\";\nimport {\n principalPolicies,\n principalPolicyBundleHistory,\n principalPolicyBundleReferences,\n principalPolicyCheckpoints,\n principalPolicyOrganizations,\n} from \"./principalPolicySchema\";\nimport {\n securityIncidents,\n securityIncidentTable,\n} from \"./securityIncidentSchema\";\nimport {\n verifiedAccessManifestBundles,\n verifiedManifestBundleTables,\n} from \"./verifiedManifestBundleSchema\";\n\nexport {\n containerHydrationTombstones,\n containers,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n supersededContainerBindings,\n} from \"./containerSchema\";\nexport {\n documentAttachmentBlobProjection,\n documentPendingAttachments,\n} from \"./documentAttachmentSchema\";\nexport {\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n LOCAL_INTENT_SUBJECT,\n localIntents,\n} from \"./localIntentSchema\";\nexport {\n principalPolicies,\n principalPolicyBundleHistory,\n principalPolicyBundleReferences,\n principalPolicyCheckpoints,\n principalPolicyOrganizations,\n} from \"./principalPolicySchema\";\nexport { securityIncidents } from \"./securityIncidentSchema\";\nexport { containerDocumentTombstoneHolds, organizationReadModelTables };\n\nconst accessLevelColumn = \"effective_access_level\";\n\n/**\n * Durable Loro-backed document records shared by app features.\n *\n * This table stores encrypted document runtime state for multiple app domains.\n * `appKind` namespaces records for documents and container metadata. User-facing\n * list data is projected into feature-specific read models.\n *\n * Columns:\n * - `appKind`: Local domain namespace for the row, such as `documents` or\n * `container-metadata`.\n * - `localId`: Stable local id inside `appKind`. It may be created before a\n * server `documentId` exists.\n * - `documentId`: Server document id once the record is known remotely, or\n * `null` while the document is local-only.\n * - `accessEpoch`: Latest access epoch persisted for the document. Defaults to\n * the initial epoch.\n * - `accessStateHash`: Current document access/manifest state hash returned by\n * sync, when known.\n * - `lastCommitLsn`: Last remote commit cursor applied to this local document.\n * - `documentManifestBundle`: Serialized document manifest bundle used for\n * encrypted document sync.\n * - `contentKeyBundle`: Serialized content-key material needed to open the\n * local document.\n * - `documentKekTargets`: Serialized KEK target state for document key wraps.\n * - `pendingBaseVersion`: Encoded oplog version through which every persisted\n * op is already enqueued or synced. Persisted so a restart restores the\n * outgoing-delta marker instead of re-seeding it past a device-first\n * `deferRemoteSync` write's un-advanced op. `null` when unset.\n * - `snapshotEndVersion`: Encoded end version vector of the persisted content\n * (which lives in the durable-history tables, never on this row), written on\n * every content persist. Lets the pending-write queue's deferred-tail scan\n * compare version coverage without loading content. Empty string when the\n * document has never hydrated content, which readers treat as \"no deferred\n * tail claimable\".\n * - `recoveryGeneration`: Atomic raw-history recovery writer fence.\n * - `recoveryDocumentId`: Former server id for cross-client post-purge recreation.\n * - `pullContinuation`: Durable progress for the next bounded remote pull.\n * - `syncFailureStatus`, `syncFailureMessage`, `syncFailureAttemptedAt`: The\n * last terminal sync failure or quarantined incoming update for this scope.\n * The durable write queue (queued rows of `documentHistoryUpdates`) has no\n * status columns, so these let the write-queue view and footer explain why\n * the document is blocked. `syncFailureMessage` is non-null exactly when a\n * failure is recorded; a newer failure replaces the old, and a later fully\n * validated sync pass, a remote reset, or the scope's teardown clears all\n * three.\n * - `updatedAt`: Local timestamp for the last persisted runtime-state update.\n *\n * Indexes:\n * - `(appKind, localId)` is the primary key and scopes local document lookups.\n * - `(appKind, documentId) where documentId is not null` supports resolving a\n * server document id back to the local row during discovery and relinking.\n */\nexport const documents = sqliteTable(\n \"documents\",\n {\n appKind: text(\"app_kind\").notNull(),\n localId: text(\"local_id\").notNull(),\n documentId: text(\"document_id\"),\n accessEpoch: integer(\"access_epoch\").notNull().default(1),\n accessStateHash: text(\"access_state_hash\"),\n effectiveAccessLevel: text(accessLevelColumn).notNull().default(\"read\"),\n lastCommitLsn: text(\"last_commit_lsn\"),\n documentManifestBundle: text(\"document_manifest_bundle\"),\n contentKeyBundle: text(\"content_key_bundle\"),\n documentKekTargets: text(\"document_kek_targets\"),\n pendingBaseVersion: text(\"pending_base_version\"),\n pullContinuation: text(\"pull_continuation\"),\n recoveryGeneration: integer(\"recovery_generation\").notNull().default(0),\n recoveryDocumentId: text(\"recovery_document_id\"),\n snapshotEndVersion: text(\"snapshot_end_version\").notNull().default(\"\"),\n syncFailureStatus: integer(\"sync_failure_status\"),\n syncFailureMessage: text(\"sync_failure_message\"),\n syncFailureAttemptedAt: text(\"sync_failure_attempted_at\"),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.appKind, table.localId] }),\n index(\"documents_app_document_idx\")\n .on(table.appKind, table.documentId)\n .where(sql`${table.documentId} IS NOT NULL`),\n ],\n);\n\n/**\n * Full-history persistence for local documents (checkpoint + tail) — the ONLY\n * durable content source. Record rows in `documents` carry runtime metadata\n * and the content frontier (`snapshotEndVersion`), never content. The\n * checkpoint holds a full-history snapshot refreshed only at compaction, and\n * the tail appends every update (local deltas and decrypted remote updates)\n * written since. Restore = import checkpoint + replay tail; compaction =\n * export full history from the live doc, replace the checkpoint, clear the\n * tail — all bounded and amortized. Container metadata stores its content (an\n * exported-updates blob) as its checkpoint row, with no tail.\n */\nexport const documentHistoryCheckpoints = sqliteTable(\n \"document_history_checkpoints\",\n {\n appKind: text(\"app_kind\").notNull(),\n localId: text(\"local_id\").notNull(),\n snapshot: text(\"snapshot\").notNull(),\n endVersionVector: text(\"end_version_vector\").notNull(),\n revision: text(\"revision\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.appKind, table.localId] })],\n);\n\n/**\n * The local update log: one row per Loro update, serving as both the history\n * tail (restore = checkpoint + tail) and the outbound write queue.\n *\n * Every locally authored update is stored once. While it waits for sync it\n * carries an `updateId` (the id submitted to the server) and the version-vector\n * metadata the submission needs; settlement clears them, leaving the row as\n * ordinary tail history until compaction folds it into a checkpoint.\n *\n * Columns:\n * - `id`: Row id; tail compaction deletes by it.\n * - `appKind`, `localId`: Document scope matching `documents`.\n * - `updateData`: Serialized Loro update payload.\n * - `origin`: \"local\" (authored on this device) or \"remote\" (decrypted\n * pulled update) for tail rows. Restores use it to advance the\n * outgoing-delta marker across remote rows — their ops are already\n * server-side — while a local row left behind by a crash stays below the\n * marker so the next edit re-derives and sends it. \"outbox\" marks a queued\n * update with no tail role (container metadata, whose content is its\n * checkpoint, and full-state re-uploads after a remote reset); restores and\n * compaction never see it and settlement deletes it.\n * - `createdAt`: Insertion timestamp; with `rowid`, deterministic replay order.\n * - `updateId`: Present exactly while the row is queued for sync; rekeyed\n * after a lost acknowledgement poisons the submitted id.\n * - `partialStartVersionVector` / `partialEndVersionVector`: Version vectors\n * around a queued partial update.\n * - `sourceVersionVector`: Present on a queued rotation baseline checkpoint.\n * - `rekeyCount`: Durable bound on rekeys of a queued row.\n *\n * Invariant: compaction never deletes a queued row, so a checkpoint can cover\n * a queued update's operations without removing it from the queue.\n */\nexport const documentHistoryUpdates = sqliteTable(\n \"document_history_updates\",\n {\n id: text(\"id\"),\n appKind: text(\"app_kind\").notNull(),\n localId: text(\"local_id\").notNull(),\n updateData: text(\"update_data\").notNull(),\n origin: text(\"origin\").notNull(),\n createdAt: text(\"created_at\").notNull(),\n updateId: text(\"update_id\"),\n partialStartVersionVector: text(\"partial_start_version_vector\"),\n partialEndVersionVector: text(\"partial_end_version_vector\"),\n sourceVersionVector: text(\"source_version_vector\"),\n rekeyCount: integer(\"rekey_count\").notNull().default(0),\n },\n (table) => [\n primaryKey({ columns: [table.id] }),\n index(\"document_history_updates_scope_created_idx\").on(\n table.appKind,\n table.localId,\n table.createdAt,\n ),\n uniqueIndex(\"document_history_updates_update_id_idx\")\n .on(table.updateId)\n .where(sql`${table.updateId} IS NOT NULL`),\n // Queued rows only: pending counts and pending loads skip settled history.\n index(\"document_history_updates_queued_scope_idx\")\n .on(table.appKind, table.localId, table.createdAt)\n .where(sql`${table.updateId} IS NOT NULL`),\n ],\n);\n\n/**\n * Anti-rollback pin for verified access manifests.\n *\n * Records the highest access-manifest epoch this client has verified for each\n * object, so a later projection that serves an older epoch (rollback) or a\n * conflicting manifest at the same epoch (equivocation) is detected before any\n * key is unwrapped. Updated monotonically after a projection verifies cleanly.\n *\n * Columns:\n * - `objectKind`: Access object kind (`container`, `document`, ...).\n * - `organizationId`: Organization boundary that owns the object.\n * - `objectId`: Stable object id.\n * - `epoch`: Highest verified manifest epoch.\n * - `manifestHash`: Manifest hash pinned at that epoch.\n * - `updatedAt`: Local timestamp for the pin.\n *\n * Indexes:\n * - `(objectKind, organizationId, objectId)` is the primary key and gives one\n * pin per object.\n */\nexport const accessManifestCheckpoints = sqliteTable(\n \"access_manifest_checkpoints\",\n {\n objectKind: text(\"object_kind\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n objectId: text(\"object_id\").notNull(),\n epoch: integer(\"epoch\").notNull(),\n manifestHash: text(\"manifest_hash\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.objectKind, table.organizationId, table.objectId],\n }),\n ],\n);\n\n/**\n * Durable terminal pins for documents whose signed purge proof was verified.\n * These survive remote-state resets so a dishonest API cannot later replay the\n * pre-purge writer projection and resurrect locally deleted content.\n */\nexport const documentPurgeCheckpoints = sqliteTable(\n \"document_purge_checkpoints\",\n {\n documentId: text(\"document_id\").primaryKey(),\n organizationId: text(\"organization_id\").notNull(),\n documentManifestHash: text(\"document_manifest_hash\").notNull(),\n purgeEventHash: text(\"purge_event_hash\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n);\n\n/**\n * Durable pins for user identity bundles.\n *\n * The first validated identity accepted for a user in a configured API trust\n * domain is inserted once. Later observations must match every suite, public\n * key, and fingerprint exactly; the persistence adapter never changes those\n * columns. `firstSeenAt` records when the local trust decision was made and is\n * likewise immutable. `provenance` (`self`, `link`, or `observed`) records how\n * the pin was established; only `self` and `link` admit a user, and it only\n * rises. A table without it is an obsolete local database.\n *\n * Indexes:\n * - `(identityTrustDomain, userId)` is the primary key and scopes a user pin to\n * the host-configured API authority that supplied it.\n * - `(identityTrustDomain, signingKeyFingerprint)` binds the reverse identity\n * mapping durably, including across session recreation. There is no\n * migration for a table that already violates it. Earlier builds pinned a\n * registration's user id before the server confirmed it, so a device that\n * ran one may hold two users on one key; deployments are greenfield, and\n * such a device clears its local data, which recreates this table empty. A\n * device that used an environment before a reset does the same (see\n * docs/developer/greenfield-reset.md).\n */\nexport const trustedUserIdentityPins = sqliteTable(\n \"trusted_user_identity_pins\",\n {\n identityTrustDomain: text(\"identity_trust_domain\").notNull(),\n userId: text(\"user_id\").notNull(),\n formatVersion: integer(\"format_version\").notNull(),\n signingSuite: text(\"signing_suite\").notNull(),\n signingPublicKey: text(\"signing_public_key\").notNull(),\n signingKeyFingerprint: text(\"signing_key_fingerprint\").notNull(),\n encapsulationSuite: text(\"encapsulation_suite\").notNull(),\n encapsulationPublicKey: text(\"encapsulation_public_key\").notNull(),\n encapsulationKeyFingerprint: text(\n \"encapsulation_key_fingerprint\",\n ).notNull(),\n firstSeenAt: text(\"first_seen_at\").notNull(),\n provenance: text(\"provenance\", {\n enum: [\"self\", \"link\", \"observed\"],\n }).notNull(),\n },\n (table) => [\n primaryKey({\n columns: [table.identityTrustDomain, table.userId],\n }),\n uniqueIndex(\"trusted_user_identity_pins_domain_signing_fingerprint_idx\").on(\n table.identityTrustDomain,\n table.signingKeyFingerprint,\n ),\n ],\n);\n\n/**\n * Local many-to-many projection between documents and containers.\n *\n * The document summary row stores one selected `containerId` for primary list\n * placement, while this table keeps the full set of linked containers returned\n * by container/document sync. Removing a container deletes its links and may\n * repair affected document summary rows to point at another remaining link.\n *\n * Columns:\n * - `documentId`: Server document id whose container links are projected.\n * - `containerId`: Linked container id.\n * - `updatedAt`: Local timestamp for the last replacement of the link set.\n *\n * Indexes:\n * - `(documentId, containerId)` is the primary key and prevents duplicate\n * links for the same document/container pair.\n * - `(containerId, documentId)` serves the container-filtered link scans\n * (folder item and sidebar windows) as a covering index search.\n */\nexport const documentContainerProjection = sqliteTable(\n \"document_container_projection\",\n {\n documentId: text(\"document_id\").notNull(),\n containerId: text(\"container_id\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.documentId, table.containerId] }),\n index(\"document_container_projection_container_idx\").on(\n table.containerId,\n table.documentId,\n ),\n ],\n);\n\n/**\n * Queryable document summary and detail projection.\n *\n * The durable Loro state lives in `documents`. This table stores the fields the\n * app needs for document lists, summaries, and fast detail hydration without\n * opening the full Loro snapshot on every read.\n *\n * Columns:\n * - `localId`: Stable local document id. This joins to `documents.localId` for\n * rows where `documents.appKind = documents`.\n * - `documentId`: Server document id when known.\n * - `containerId`: Selected container for primary document placement, or\n * `null` if the document is not currently linked to a visible container.\n * - `organizationId`: Last-known owning organization. Stamped from the\n * container row when the document is detached because its container was\n * removed locally (e.g. access to a shared org was revoked and the container\n * tombstoned), so pending writes keep their org attribution after the\n * `containers` join source disappears. Read as a fallback only — a live\n * container join always wins.\n * - `documentKind`: Stored document kind. Defaults to `note`.\n * - `title`: Plain projected title. Defaults to the note fallback title.\n * - `updatedAt`: Timestamp used for document list ordering.\n *\n * The projected full text lives in `documentProjectionText`, keyed by the same\n * `localId`. Keeping it out of this row keeps list/window scans narrow: the\n * sidebar and summary queries read titles and placement from rows whose size\n * does not grow with document content.\n *\n * Indexes:\n * - `localId` is the primary key for document projection lookups.\n * - `(containerId) where containerId is not null` serves container-scoped\n * window/count scans without walking the whole table.\n * - `(organizationId) where containerId is null` serves the orphan-recovery\n * existence and window scans.\n * - `(documentId) where documentId is not null` serves the linked-placement\n * join from `documentContainerProjection` and server-id lookups.\n */\nexport const documentProjection = sqliteTable(\n \"document_projection\",\n {\n localId: text(\"local_id\"),\n documentId: text(\"document_id\"),\n containerId: text(\"container_id\"),\n organizationId: text(\"organization_id\"),\n documentKind: text(\"document_kind\").notNull().default(\"note\"),\n title: text(\"title\").notNull().default(\"Untitled note\"),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.localId] }),\n index(\"document_projection_container_idx\")\n .on(table.containerId)\n .where(sql`${table.containerId} IS NOT NULL`),\n index(\"document_projection_orphan_organization_idx\")\n .on(table.organizationId)\n .where(sql`${table.containerId} IS NULL`),\n index(\"document_projection_document_idx\")\n .on(table.documentId)\n .where(sql`${table.documentId} IS NOT NULL`),\n ],\n);\n\n/**\n * Projected document text, split from `documentProjection` so content size\n * never bloats the rows that list/window queries scan. Loaded only by detail\n * reads (`loadDocument`) and the save-timestamp change check.\n *\n * Columns:\n * - `localId`: Stable local document id, matching `documentProjection.localId`.\n * - `text`: Plain projected text used to rebuild summaries/details.\n */\nexport const documentProjectionText = sqliteTable(\n \"document_projection_text\",\n {\n localId: text(\"local_id\"),\n text: text(\"text\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.localId] })],\n);\n\n/**\n * Per-lane sync state for container data: the server cursor and the local\n * freshness marker share one row per lane.\n *\n * Container sync is split into lanes, such as a parent-container child lane or\n * a container-document membership lane. The cursor lets the next request\n * resume without replaying the entire tree. The freshness marker records the\n * last fully drained check independently of the cursor: empty server\n * responses do not always carry a new watermark, but startup still needs to\n * know that it recently checked the lane before polling again.\n *\n * Columns:\n * - `laneKind`: Sync lane category, such as `container_parent` or\n * `container_documents`.\n * - `laneId`: Lane identity. Root parent sync uses `root`, child sync uses a\n * parent-prefixed container id, and document lanes use the container id.\n * - `watermarkUpdatedAt`: Server `updatedAt` value for the stored watermark;\n * null until a watermark is saved.\n * - `watermarkId`: Server id tie-breaker for the stored watermark; null\n * exactly when `watermarkUpdatedAt` is.\n * - `updatedAt`: Local timestamp for when the cursor was saved.\n * - `checkedAt`: Local timestamp for the most recent fully drained lane check;\n * null until one completes.\n *\n * Indexes:\n * - `(laneKind, laneId)` is the primary key and stores one row per lane.\n */\nexport const containerSyncWatermarks = sqliteTable(\n \"container_sync_watermarks\",\n {\n laneKind: text(\"lane_kind\").notNull(),\n laneId: text(\"lane_id\").notNull(),\n watermarkUpdatedAt: text(\"watermark_updated_at\"),\n watermarkId: text(\"watermark_id\"),\n updatedAt: text(\"updated_at\"),\n checkedAt: text(\"checked_at\"),\n },\n (table) => [primaryKey({ columns: [table.laneKind, table.laneId] })],\n);\n\nexport const documentTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(documents),\n requiredColumns: [\n \"pull_continuation\",\n \"recovery_generation\",\n \"recovery_document_id\",\n \"sync_failure_status\",\n \"sync_failure_message\",\n \"sync_failure_attempted_at\",\n ],\n },\n defineSqlTableSchema(documentHistoryCheckpoints),\n {\n ...defineSqlTableSchema(documentHistoryUpdates),\n requiredColumns: [\"update_id\"],\n },\n];\n\nexport const principalPolicyTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(principalPolicies),\n requiredColumns: [\"current_grants_json\"],\n },\n {\n ...defineSqlTableSchema(principalPolicyBundleHistory),\n requiredColumns: [\"current_grants_json\"],\n },\n defineSqlTableSchema(principalPolicyBundleReferences),\n defineSqlTableSchema(principalPolicyOrganizations),\n ...principalHistoryStageTables,\n ...principalHistoryEvidenceTables,\n];\n\nexport const keyingCheckpointTables: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(organizationFounders),\n defineSqlTableSchema(accessManifestCheckpoints),\n defineSqlTableSchema(principalGrantRetirements),\n defineSqlTableSchema(documentPurgeCheckpoints),\n defineSqlTableSchema(principalPolicyCheckpoints),\n];\n\nexport const trustedUserIdentityPinTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(trustedUserIdentityPins),\n requiredColumns: [\"provenance\"],\n },\n];\n\nconst securityIncidentTables: ReadonlyArray<SqlTableSchema> = [\n securityIncidentTable,\n];\n\nexport const containerTables = containerTableSchemas;\n\nexport const documentContainerProjectionTables: ReadonlyArray<SqlTableSchema> =\n [\n defineSqlTableSchema(documentContainerProjection),\n {\n ...defineSqlTableSchema(containerDocumentTombstoneHolds),\n requiredColumns: [\"hidden\"],\n },\n defineSqlTableSchema(pendingDocumentDiscoveries),\n {\n ...defineSqlTableSchema(documentDiscoveryHeads),\n requiredColumns: [\"organization_id\"],\n },\n defineSqlTableSchema(documentDiscoverySequence),\n ];\n\nexport const localIntentTables: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(localIntents),\n];\n\nexport const documentPlacementIntentTables: ReadonlyArray<SqlTableSchema> = [\n ...localIntentTables,\n defineSqlTableSchema(documentIntentLinkTargets),\n];\n\nexport const documentProjectionTables: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(documentProjection),\n defineSqlTableSchema(documentProjectionText),\n {\n ...defineSqlTableSchema(documentPendingAttachments),\n requiredColumns: [\"content_sha256\"],\n },\n {\n ...defineSqlTableSchema(documentAttachmentBlobProjection),\n requiredColumns: [\"content_sha256\"],\n },\n documentOrphanBlobReclaimTable,\n];\n\nexport const containerSyncWatermarkTables: ReadonlyArray<SqlTableSchema> = [\n {\n ...defineSqlTableSchema(containerSyncWatermarks),\n requiredColumns: [\"checked_at\"],\n },\n];\n\nexport const clientSqlTables: ReadonlyArray<SqlTableSchema> = [\n ...principalMutationJournalTables,\n ...documentTables,\n ...principalPolicyTables,\n ...keyingCheckpointTables,\n ...verifiedManifestBundleTables,\n ...trustedUserIdentityPinTables,\n ...securityIncidentTables,\n ...containerTables,\n ...documentContainerProjectionTables,\n ...documentPlacementIntentTables,\n ...documentProjectionTables,\n ...containerSyncWatermarkTables,\n ...organizationReadModelTables,\n ...organizationDataUsage.organizationDataUsageTables,\n ...provisioningAttempt.organizationProvisioningAttemptTables,\n ...organizationSyncPause.organizationSyncPauseTables,\n];\n\nexport const clientSQLiteSchema = {\n principalHistoryNodeReferences,\n principalHistoryRootOwners,\n principalKeyEnvelopeArchive,\n principalMutationJournal,\n principalHistoryEntries,\n principalHistoryNodes,\n principalHistoryPrefixes,\n principalHistoryStages,\n organizationFounders,\n principalGrantRetirements,\n documents,\n principalPolicies,\n principalPolicyBundleHistory,\n principalPolicyBundleReferences,\n principalPolicyOrganizations,\n accessManifestCheckpoints,\n documentPurgeCheckpoints,\n principalPolicyCheckpoints,\n verifiedAccessManifestBundles,\n trustedUserIdentityPins,\n securityIncidents,\n ...containerSQLiteSchema,\n documentContainerProjection,\n localIntents,\n documentIntentLinkTargets,\n documentProjection,\n documentPendingAttachments,\n documentAttachmentBlobProjection,\n documentOrphanBlobReclaims: documentOrphanBlobReclaims,\n containerSyncWatermarks,\n ...organizationReadModelSQLiteSchema,\n ...organizationDataUsage.organizationDataUsageSQLiteSchema,\n ...provisioningAttempt.organizationProvisioningAttemptSQLiteSchema,\n ...organizationSyncPause.organizationSyncPauseSQLiteSchema,\n};\n"]}
|
|
@@ -8,7 +8,6 @@ export const principalPolicyOrganizations = sqliteTable("principal_policy_organi
|
|
|
8
8
|
organizationId: text("organization_id").notNull(),
|
|
9
9
|
}, (table) => [
|
|
10
10
|
primaryKey({ columns: [table.principalType, table.principalId] }),
|
|
11
|
-
index("principal_policy_organizations_organization_idx").on(table.organizationId),
|
|
12
11
|
]);
|
|
13
12
|
function principalPolicyBundleColumns() {
|
|
14
13
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalPolicySchema.js","sourceRoot":"","sources":["principalPolicySchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,IAAI,GACL,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAE/E,wEAAwE;AACxE,MAAM,CAAC,MAAM,4BAA4B,GAAG,WAAW,CACrD,gCAAgC,EAChC;IACE,aAAa,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE;IAC/C,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE;IAC3C,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE;CAClD,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"principalPolicySchema.js","sourceRoot":"","sources":["principalPolicySchema.ts"],"names":[],"mappings":"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","sourcesContent":["import { desc } from \"drizzle-orm\";\nimport {\n index,\n integer,\n primaryKey,\n sqliteTable,\n text,\n} from \"drizzle-orm/sqlite-core\";\n\nimport { principalStateFingerprintJson } from \"../principalKeyFingerprintJson\";\n\n/** Durable organization ownership for every managed-principal cache. */\nexport const principalPolicyOrganizations = sqliteTable(\n \"principal_policy_organizations\",\n {\n principalType: text(\"principal_type\").notNull(),\n principalId: text(\"principal_id\").notNull(),\n organizationId: text(\"organization_id\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.principalType, table.principalId] }),\n ],\n);\n\nfunction principalPolicyBundleColumns() {\n return {\n principalType: text(\"principal_type\").notNull(),\n principalId: text(\"principal_id\").notNull(),\n stateHash: text(\"state_hash\").notNull(),\n currentStateJson: text(\"current_state_json\").notNull(),\n currentPayloadJson: text(\"current_payload_json\").notNull(),\n currentProjectionJson: text(\"current_projection_json\").notNull(),\n currentGrantsJson: text(\"current_grants_json\").notNull(),\n currentMemberEnvelopesJson: text(\"current_member_envelopes_json\").notNull(),\n previousStatesJson: text(\"previous_states_json\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n };\n}\n\n/** Latest full policy bundle per managed principal. */\nexport const principalPolicies = sqliteTable(\n \"principal_policies\",\n principalPolicyBundleColumns(),\n (table) => [\n primaryKey({ columns: [table.principalType, table.principalId] }),\n index(\"principal_policies_key_fingerprint_idx\").on(\n principalStateFingerprintJson(table.currentStateJson),\n desc(table.updatedAt),\n ),\n ],\n);\n\n/** Older verified bundles retained for exact-reference verification and epoch key unwrapping. */\nexport const principalPolicyBundleHistory = sqliteTable(\n \"principal_policy_bundle_history\",\n principalPolicyBundleColumns(),\n (table) => [\n primaryKey({\n columns: [table.principalType, table.principalId, table.stateHash],\n }),\n index(\"principal_policy_history_key_fingerprint_idx\").on(\n principalStateFingerprintJson(table.currentStateJson),\n desc(table.updatedAt),\n ),\n ],\n);\n\n/** Exact policy states mapped to every retained bundle chain that contains them. */\nexport const principalPolicyBundleReferences = sqliteTable(\n \"principal_policy_bundle_references\",\n {\n principalType: text(\"principal_type\").notNull(),\n principalId: text(\"principal_id\").notNull(),\n version: integer(\"version\").notNull(),\n stateHash: text(\"state_hash\").notNull(),\n keyEpoch: integer(\"key_epoch\").notNull(),\n keyFingerprint: text(\"key_fingerprint\").notNull(),\n bundleVersion: integer(\"bundle_version\").notNull(),\n bundleStateHash: text(\"bundle_state_hash\").notNull(),\n },\n (table) => [\n primaryKey({\n columns: [\n table.principalType,\n table.principalId,\n table.version,\n table.stateHash,\n table.keyEpoch,\n table.keyFingerprint,\n table.bundleStateHash,\n ],\n }),\n ],\n);\n\n/** Monotonic anti-rollback pin for each verified managed principal. */\nexport const principalPolicyCheckpoints = sqliteTable(\n \"principal_policy_checkpoints\",\n {\n principalType: text(\"principal_type\").notNull(),\n principalId: text(\"principal_id\").notNull(),\n version: integer(\"version\").notNull(),\n stateHash: text(\"state_hash\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.principalType, table.principalId] }),\n ],\n);\n"]}
|
|
@@ -27,8 +27,10 @@ export const verifiedAccessManifestBundles = sqliteTable("verified_access_manife
|
|
|
27
27
|
verifiedAt: text("verified_at").notNull(),
|
|
28
28
|
}, (table) => [
|
|
29
29
|
index("verified_access_manifest_bundles_object_idx").on(table.objectKind, table.objectId, desc(table.epoch)),
|
|
30
|
-
|
|
31
|
-
index("
|
|
30
|
+
// Eviction order: oldest verification first, hash as the tiebreak.
|
|
31
|
+
index("verified_access_manifest_bundles_eviction_idx").on(table.verifiedAt, table.manifestHash),
|
|
32
|
+
// Recent citations: an organization's newest verifications first.
|
|
33
|
+
index("verified_access_manifest_bundles_organization_recent_idx").on(table.organizationId, desc(table.verifiedAt), table.manifestHash),
|
|
32
34
|
]);
|
|
33
35
|
export const verifiedManifestBundleTables = [
|
|
34
36
|
defineSqlTableSchema(verifiedAccessManifestBundles),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifiedManifestBundleSchema.js","sourceRoot":"","sources":["verifiedManifestBundleSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAuB,MAAM,mBAAmB,CAAC;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,WAAW,CACtD,kCAAkC,EAClC;IACE,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,UAAU,EAAE;IAChD,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE;IACjD,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE;IACrC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE;IACjC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE;IAC7C,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;CAC1C,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,KAAK,CAAC,6CAA6C,CAAC,CAAC,EAAE,CACrD,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,QAAQ,EACd,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAClB;IACD,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"verifiedManifestBundleSchema.js","sourceRoot":"","sources":["verifiedManifestBundleSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAuB,MAAM,mBAAmB,CAAC;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,WAAW,CACtD,kCAAkC,EAClC;IACE,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,UAAU,EAAE;IAChD,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE;IACjD,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE;IACrC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE;IACjC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IACzC,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE;IAC7C,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;CAC1C,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,KAAK,CAAC,6CAA6C,CAAC,CAAC,EAAE,CACrD,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,QAAQ,EACd,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAClB;IACD,mEAAmE;IACnE,KAAK,CAAC,+CAA+C,CAAC,CAAC,EAAE,CACvD,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,YAAY,CACnB;IACD,kEAAkE;IAClE,KAAK,CAAC,0DAA0D,CAAC,CAAC,EAAE,CAClE,KAAK,CAAC,cAAc,EACpB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EACtB,KAAK,CAAC,YAAY,CACnB;CACF,CACF,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAkC;IACzE,oBAAoB,CAAC,6BAA6B,CAAC;CACpD,CAAC","sourcesContent":["import { desc } from \"drizzle-orm\";\nimport { index, integer, sqliteTable, text } from \"drizzle-orm/sqlite-core\";\nimport { defineSqlTableSchema, type SqlTableSchema } from \"../sqlTableSchema\";\n\n/**\n * Access-manifest bundles this device verified inside a writer projection,\n * keyed by manifest hash. A later projection read cites them so the API can\n * omit their bytes; the client refills each omission from this row and\n * verifies the rebuilt projection from scratch. Rows are neither trust nor\n * checkpoint state: a missing, evicted, or damaged row only costs bytes.\n *\n * Columns:\n * - `manifestHash`: Manifest hash; equals the stored bundle's `manifestHash`.\n * - `organizationId`, `objectKind`, `objectId`, `epoch`: The verified\n * manifest's object, used to cite the lineage relevant to a request.\n * - `bundleJson`: The exact verified bundle as JSON.\n * - `bundleDigest`: SHA-256 hex of `bundleJson`; a mismatch drops the row.\n * - `verifiedAt`: Latest local verification time; oldest rows evict first.\n */\nexport const verifiedAccessManifestBundles = sqliteTable(\n \"verified_access_manifest_bundles\",\n {\n manifestHash: text(\"manifest_hash\").primaryKey(),\n organizationId: text(\"organization_id\").notNull(),\n objectKind: text(\"object_kind\").notNull(),\n objectId: text(\"object_id\").notNull(),\n epoch: integer(\"epoch\").notNull(),\n bundleJson: text(\"bundle_json\").notNull(),\n bundleDigest: text(\"bundle_digest\").notNull(),\n verifiedAt: text(\"verified_at\").notNull(),\n },\n (table) => [\n index(\"verified_access_manifest_bundles_object_idx\").on(\n table.objectKind,\n table.objectId,\n desc(table.epoch),\n ),\n // Eviction order: oldest verification first, hash as the tiebreak.\n index(\"verified_access_manifest_bundles_eviction_idx\").on(\n table.verifiedAt,\n table.manifestHash,\n ),\n // Recent citations: an organization's newest verifications first.\n index(\"verified_access_manifest_bundles_organization_recent_idx\").on(\n table.organizationId,\n desc(table.verifiedAt),\n table.manifestHash,\n ),\n ],\n);\n\nexport const verifiedManifestBundleTables: ReadonlyArray<SqlTableSchema> = [\n defineSqlTableSchema(verifiedAccessManifestBundles),\n];\n"]}
|
package/data/sqlite/sqlExec.d.ts
CHANGED
|
@@ -27,6 +27,18 @@ export declare const unavailableExecSql: ExecSql;
|
|
|
27
27
|
export declare function resolveCanonicalExecSql(execSql: ExecSql): ExecSql;
|
|
28
28
|
export declare function hasCompletedConnectionOnce(execSql: ExecSql, key: string): boolean;
|
|
29
29
|
export declare function markCompletedConnectionOnce(execSql: ExecSql, key: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Start recording the once-per-connection keys completed inside a transaction
|
|
32
|
+
* scope (a transaction or one of its savepoints). Every open must be paired
|
|
33
|
+
* with exactly one `closeTransactionSchemaMemoScope`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function openTransactionSchemaMemoScope(execSql: ExecSql): void;
|
|
36
|
+
/**
|
|
37
|
+
* Close the innermost transaction scope. A rollback forgets only the keys
|
|
38
|
+
* completed inside it, so the next query re-ensures exactly the schema the
|
|
39
|
+
* rollback undid; a commit keeps them, handing them to the enclosing scope.
|
|
40
|
+
*/
|
|
41
|
+
export declare function closeTransactionSchemaMemoScope(execSql: ExecSql, committed: boolean): void;
|
|
30
42
|
export declare function runOncePerConnection(execSql: ExecSql, key: string, run: () => Promise<void>): Promise<void>;
|
|
31
43
|
/**
|
|
32
44
|
* Forget every completed once-per-connection key for this connection. Required
|
package/data/sqlite/sqlExec.js
CHANGED
|
@@ -24,6 +24,11 @@ export function resolveCanonicalExecSql(execSql) {
|
|
|
24
24
|
// awaiting a promise that can only settle after the lock the other context is
|
|
25
25
|
// already holding.
|
|
26
26
|
const completedConnectionOnceKeys = new WeakMap();
|
|
27
|
+
// Keys first completed inside each open transaction scope on a connection,
|
|
28
|
+
// innermost scope last. A rolled-back scope undid that schema work, so it
|
|
29
|
+
// forgets exactly its own keys; a committed savepoint hands its keys to the
|
|
30
|
+
// enclosing scope, whose rollback would undo them too.
|
|
31
|
+
const transactionSchemaMemoScopes = new WeakMap();
|
|
27
32
|
export function hasCompletedConnectionOnce(execSql, key) {
|
|
28
33
|
return (completedConnectionOnceKeys
|
|
29
34
|
.get(resolveCanonicalExecSql(execSql))
|
|
@@ -32,12 +37,51 @@ export function hasCompletedConnectionOnce(execSql, key) {
|
|
|
32
37
|
export function markCompletedConnectionOnce(execSql, key) {
|
|
33
38
|
const canonical = resolveCanonicalExecSql(execSql);
|
|
34
39
|
const keys = completedConnectionOnceKeys.get(canonical) ?? new Set();
|
|
40
|
+
if (keys.has(key))
|
|
41
|
+
return;
|
|
35
42
|
keys.add(key);
|
|
36
43
|
completedConnectionOnceKeys.set(canonical, keys);
|
|
44
|
+
transactionSchemaMemoScopes.get(canonical)?.at(-1)?.add(key);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Start recording the once-per-connection keys completed inside a transaction
|
|
48
|
+
* scope (a transaction or one of its savepoints). Every open must be paired
|
|
49
|
+
* with exactly one `closeTransactionSchemaMemoScope`.
|
|
50
|
+
*/
|
|
51
|
+
export function openTransactionSchemaMemoScope(execSql) {
|
|
52
|
+
const canonical = resolveCanonicalExecSql(execSql);
|
|
53
|
+
const scopes = transactionSchemaMemoScopes.get(canonical) ?? [];
|
|
54
|
+
scopes.push(new Set());
|
|
55
|
+
transactionSchemaMemoScopes.set(canonical, scopes);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Close the innermost transaction scope. A rollback forgets only the keys
|
|
59
|
+
* completed inside it, so the next query re-ensures exactly the schema the
|
|
60
|
+
* rollback undid; a commit keeps them, handing them to the enclosing scope.
|
|
61
|
+
*/
|
|
62
|
+
export function closeTransactionSchemaMemoScope(execSql, committed) {
|
|
63
|
+
const canonical = resolveCanonicalExecSql(execSql);
|
|
64
|
+
const scopes = transactionSchemaMemoScopes.get(canonical);
|
|
65
|
+
const scopeKeys = scopes?.pop();
|
|
66
|
+
if (!scopes || !scopeKeys) {
|
|
67
|
+
throw new Error("No open transaction schema memo scope to close");
|
|
68
|
+
}
|
|
69
|
+
if (scopes.length === 0)
|
|
70
|
+
transactionSchemaMemoScopes.delete(canonical);
|
|
71
|
+
if (committed) {
|
|
72
|
+
const parent = scopes.at(-1);
|
|
73
|
+
for (const key of scopeKeys)
|
|
74
|
+
parent?.add(key);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const completed = completedConnectionOnceKeys.get(canonical);
|
|
78
|
+
for (const key of scopeKeys)
|
|
79
|
+
completed?.delete(key);
|
|
37
80
|
}
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
81
|
+
// Completion is recorded as soon as `run` resolves. Inside a runtime
|
|
82
|
+
// transaction the key joins the open schema memo scope, so a later ROLLBACK
|
|
83
|
+
// forgets it; an explicit transaction outside the runtime must instead call
|
|
84
|
+
// `resetConnectionSchemaMemo` after rolling back.
|
|
41
85
|
export async function runOncePerConnection(execSql, key, run) {
|
|
42
86
|
if (hasCompletedConnectionOnce(execSql, key)) {
|
|
43
87
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlExec.js","sourceRoot":"","sources":["sqlExec.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n readUserTimingClock,\n recordUserTimingEntry,\n} from \"../shared/userTiming\";\n\nexport type SqlRowValue = string | number | null;\nexport type SqlRow = Record<string, SqlRowValue>;\nexport type SqlArrayRow = SqlRowValue[];\nexport type SqlBind = Record<string, SqlRowValue> | ReadonlyArray<SqlRowValue>;\nexport type SqlRowMode = \"object\" | \"array\";\n\nexport interface ExecSql {\n (\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: \"object\" },\n ): Promise<SqlRow[]>;\n (\n sql: string,\n bind: SqlBind | undefined,\n options: { rowMode: \"array\" },\n ): Promise<SqlArrayRow[]>;\n (\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ): Promise<Array<SqlRow | SqlArrayRow>>;\n}\n\nexport interface ExecSqlClientLike {\n exec(options: {\n sql: string;\n bind?: SqlBind;\n rowMode?: SqlRowMode;\n }): Promise<{ rows: Array<SqlRow | SqlArrayRow> }>;\n}\n\nexport const unavailableExecSql: ExecSql = async () => {\n throw new Error(\"Database client is unavailable.\");\n};\n\n// Tracks the active serialized mutation chain for each canonical SQL executor\n// so callers sharing one connection cannot interleave transactional statements.\nconst sqlMutationQueue = new WeakMap<ExecSql, Promise<void>>();\n\n// Marks executors that already run inside the shared mutation lock so nested\n// callers can reuse the current lock instead of queueing a second time.\nconst serializedSqlExecs = new WeakSet<ExecSql>();\n\n// Reuses one ExecSql adapter per client so all wrappers around the same\n// connection share the same serialized mutation queue.\nconst clientExecSqls = new WeakMap<ExecSqlClientLike, ExecSql>();\n\n// Maps each locked executor back to the canonical executor whose lock it runs\n// under, so per-connection caches key on one stable identity no matter which\n// wrapper a caller holds.\nconst serializedSqlExecCanonicals = new WeakMap<ExecSql, ExecSql>();\n\nexport function resolveCanonicalExecSql(execSql: ExecSql): ExecSql {\n return serializedSqlExecCanonicals.get(execSql) ?? execSql;\n}\n\n// Completed once-per-connection keys (schema ensures).\n// Only COMPLETED runs are recorded — never in-flight promises — so two lock\n// contexts racing the same key both run the (idempotent) work instead of one\n// awaiting a promise that can only settle after the lock the other context is\n// already holding.\nconst completedConnectionOnceKeys = new WeakMap<ExecSql, Set<string>>();\n\nexport function hasCompletedConnectionOnce(\n execSql: ExecSql,\n key: string,\n): boolean {\n return (\n completedConnectionOnceKeys\n .get(resolveCanonicalExecSql(execSql))\n ?.has(key) ?? false\n );\n}\n\nexport function markCompletedConnectionOnce(\n execSql: ExecSql,\n key: string,\n): void {\n const canonical = resolveCanonicalExecSql(execSql);\n const keys = completedConnectionOnceKeys.get(canonical) ?? new Set<string>();\n keys.add(key);\n completedConnectionOnceKeys.set(canonical, keys);\n}\n\n// Callers must not invoke this inside an explicit SQL transaction that can\n// roll back: completion is recorded as soon as `run` resolves, so a later\n// ROLLBACK would leave the memo asserting schema that no longer exists.\nexport async function runOncePerConnection(\n execSql: ExecSql,\n key: string,\n run: () => Promise<void>,\n): Promise<void> {\n if (hasCompletedConnectionOnce(execSql, key)) {\n return;\n }\n await run();\n markCompletedConnectionOnce(execSql, key);\n}\n\n/**\n * Forget every completed once-per-connection key for this connection. Required\n * after an operation that rebuilds the schema out from under the runtime (the\n * local backup restore drops and recreates all user tables) so the next query\n * re-runs its schema ensures.\n */\nexport function resetConnectionSchemaMemo(execSql: ExecSql): void {\n completedConnectionOnceKeys.delete(resolveCanonicalExecSql(execSql));\n}\n\nfunction defineExecSql(\n run: (\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ) => Promise<Array<SqlRow | SqlArrayRow>>,\n): ExecSql {\n function execSql(\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: \"object\" },\n ): Promise<SqlRow[]>;\n function execSql(\n sql: string,\n bind: SqlBind | undefined,\n options: { rowMode: \"array\" },\n ): Promise<SqlArrayRow[]>;\n function execSql(\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ): Promise<Array<SqlRow | SqlArrayRow>>;\n async function execSql(\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ): Promise<Array<SqlRow | SqlArrayRow>> {\n return run(sql, bind, options);\n }\n\n return execSql;\n}\n\nexport function createExecSql(client: ExecSqlClientLike): ExecSql {\n const existingExecSql = clientExecSqls.get(client);\n if (existingExecSql) {\n return existingExecSql;\n }\n\n const execSql = defineExecSql(async (sql, bind, options) => {\n const result = await client.exec({\n sql,\n ...(bind !== undefined ? { bind } : {}),\n ...(options?.rowMode ? { rowMode: options.rowMode } : {}),\n });\n return result.rows;\n });\n\n clientExecSqls.set(client, execSql);\n return execSql;\n}\n\nfunction isSerializedSqlExec(execSql: ExecSql): boolean {\n return serializedSqlExecs.has(execSql);\n}\n\nfunction createSerializedSqlExec(execSql: ExecSql): ExecSql {\n if (isSerializedSqlExec(execSql)) {\n return execSql;\n }\n\n const serializedExecSql = defineExecSql(execSql);\n serializedSqlExecs.add(serializedExecSql);\n serializedSqlExecCanonicals.set(\n serializedExecSql,\n resolveCanonicalExecSql(execSql),\n );\n return serializedExecSql;\n}\n\n// SQLite transactions are scoped to the shared connection, so we must hold a\n// connection-level lock across multi-statement mutations to prevent interleaving.\n// Nested callers must keep passing the provided locked executor. Re-entering\n// with the original canonical executor will wait on the current mutation and\n// deadlock.\n// Each outermost mutation is drawn on DevTools tracks: time spent queued\n// behind another mutation, then time holding the lock.\nexport async function runSerializedSqlMutation<T>(\n execSql: ExecSql,\n operation: (execSql: ExecSql) => Promise<T> | T,\n): Promise<T> {\n if (isSerializedSqlExec(execSql)) {\n return operation(execSql);\n }\n\n const queuedAtMs = readUserTimingClock();\n const previous = sqlMutationQueue.get(execSql);\n let releaseCurrent = () => {};\n const current = new Promise<void>((resolve) => {\n releaseCurrent = resolve;\n });\n const waitForPrevious = (previous ?? Promise.resolve()).catch(\n () => undefined,\n );\n const queuedCurrent = waitForPrevious.then(() => current);\n\n sqlMutationQueue.set(execSql, queuedCurrent);\n await waitForPrevious;\n const acquiredAtMs = readUserTimingClock();\n if (previous) {\n recordUserTimingEntry({\n endMs: acquiredAtMs,\n name: \"SQLite mutation wait\",\n startMs: queuedAtMs,\n track: \"SQLite mutation queue\",\n });\n }\n\n let failed = true;\n try {\n const result = await operation(createSerializedSqlExec(execSql));\n failed = false;\n return result;\n } finally {\n const releasedAtMs = readUserTimingClock();\n releaseCurrent();\n if (sqlMutationQueue.get(execSql) === queuedCurrent) {\n sqlMutationQueue.delete(execSql);\n }\n recordUserTimingEntry({\n endMs: releasedAtMs,\n failed,\n name: \"SQLite mutation\",\n startMs: acquiredAtMs,\n track: \"SQLite mutations\",\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sqlExec.js","sourceRoot":"","sources":["sqlExec.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n readUserTimingClock,\n recordUserTimingEntry,\n} from \"../shared/userTiming\";\n\nexport type SqlRowValue = string | number | null;\nexport type SqlRow = Record<string, SqlRowValue>;\nexport type SqlArrayRow = SqlRowValue[];\nexport type SqlBind = Record<string, SqlRowValue> | ReadonlyArray<SqlRowValue>;\nexport type SqlRowMode = \"object\" | \"array\";\n\nexport interface ExecSql {\n (\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: \"object\" },\n ): Promise<SqlRow[]>;\n (\n sql: string,\n bind: SqlBind | undefined,\n options: { rowMode: \"array\" },\n ): Promise<SqlArrayRow[]>;\n (\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ): Promise<Array<SqlRow | SqlArrayRow>>;\n}\n\nexport interface ExecSqlClientLike {\n exec(options: {\n sql: string;\n bind?: SqlBind;\n rowMode?: SqlRowMode;\n }): Promise<{ rows: Array<SqlRow | SqlArrayRow> }>;\n}\n\nexport const unavailableExecSql: ExecSql = async () => {\n throw new Error(\"Database client is unavailable.\");\n};\n\n// Tracks the active serialized mutation chain for each canonical SQL executor\n// so callers sharing one connection cannot interleave transactional statements.\nconst sqlMutationQueue = new WeakMap<ExecSql, Promise<void>>();\n\n// Marks executors that already run inside the shared mutation lock so nested\n// callers can reuse the current lock instead of queueing a second time.\nconst serializedSqlExecs = new WeakSet<ExecSql>();\n\n// Reuses one ExecSql adapter per client so all wrappers around the same\n// connection share the same serialized mutation queue.\nconst clientExecSqls = new WeakMap<ExecSqlClientLike, ExecSql>();\n\n// Maps each locked executor back to the canonical executor whose lock it runs\n// under, so per-connection caches key on one stable identity no matter which\n// wrapper a caller holds.\nconst serializedSqlExecCanonicals = new WeakMap<ExecSql, ExecSql>();\n\nexport function resolveCanonicalExecSql(execSql: ExecSql): ExecSql {\n return serializedSqlExecCanonicals.get(execSql) ?? execSql;\n}\n\n// Completed once-per-connection keys (schema ensures).\n// Only COMPLETED runs are recorded — never in-flight promises — so two lock\n// contexts racing the same key both run the (idempotent) work instead of one\n// awaiting a promise that can only settle after the lock the other context is\n// already holding.\nconst completedConnectionOnceKeys = new WeakMap<ExecSql, Set<string>>();\n\n// Keys first completed inside each open transaction scope on a connection,\n// innermost scope last. A rolled-back scope undid that schema work, so it\n// forgets exactly its own keys; a committed savepoint hands its keys to the\n// enclosing scope, whose rollback would undo them too.\nconst transactionSchemaMemoScopes = new WeakMap<ExecSql, Set<string>[]>();\n\nexport function hasCompletedConnectionOnce(\n execSql: ExecSql,\n key: string,\n): boolean {\n return (\n completedConnectionOnceKeys\n .get(resolveCanonicalExecSql(execSql))\n ?.has(key) ?? false\n );\n}\n\nexport function markCompletedConnectionOnce(\n execSql: ExecSql,\n key: string,\n): void {\n const canonical = resolveCanonicalExecSql(execSql);\n const keys = completedConnectionOnceKeys.get(canonical) ?? new Set<string>();\n if (keys.has(key)) return;\n keys.add(key);\n completedConnectionOnceKeys.set(canonical, keys);\n transactionSchemaMemoScopes.get(canonical)?.at(-1)?.add(key);\n}\n\n/**\n * Start recording the once-per-connection keys completed inside a transaction\n * scope (a transaction or one of its savepoints). Every open must be paired\n * with exactly one `closeTransactionSchemaMemoScope`.\n */\nexport function openTransactionSchemaMemoScope(execSql: ExecSql): void {\n const canonical = resolveCanonicalExecSql(execSql);\n const scopes = transactionSchemaMemoScopes.get(canonical) ?? [];\n scopes.push(new Set<string>());\n transactionSchemaMemoScopes.set(canonical, scopes);\n}\n\n/**\n * Close the innermost transaction scope. A rollback forgets only the keys\n * completed inside it, so the next query re-ensures exactly the schema the\n * rollback undid; a commit keeps them, handing them to the enclosing scope.\n */\nexport function closeTransactionSchemaMemoScope(\n execSql: ExecSql,\n committed: boolean,\n): void {\n const canonical = resolveCanonicalExecSql(execSql);\n const scopes = transactionSchemaMemoScopes.get(canonical);\n const scopeKeys = scopes?.pop();\n if (!scopes || !scopeKeys) {\n throw new Error(\"No open transaction schema memo scope to close\");\n }\n if (scopes.length === 0) transactionSchemaMemoScopes.delete(canonical);\n if (committed) {\n const parent = scopes.at(-1);\n for (const key of scopeKeys) parent?.add(key);\n return;\n }\n const completed = completedConnectionOnceKeys.get(canonical);\n for (const key of scopeKeys) completed?.delete(key);\n}\n\n// Completion is recorded as soon as `run` resolves. Inside a runtime\n// transaction the key joins the open schema memo scope, so a later ROLLBACK\n// forgets it; an explicit transaction outside the runtime must instead call\n// `resetConnectionSchemaMemo` after rolling back.\nexport async function runOncePerConnection(\n execSql: ExecSql,\n key: string,\n run: () => Promise<void>,\n): Promise<void> {\n if (hasCompletedConnectionOnce(execSql, key)) {\n return;\n }\n await run();\n markCompletedConnectionOnce(execSql, key);\n}\n\n/**\n * Forget every completed once-per-connection key for this connection. Required\n * after an operation that rebuilds the schema out from under the runtime (the\n * local backup restore drops and recreates all user tables) so the next query\n * re-runs its schema ensures.\n */\nexport function resetConnectionSchemaMemo(execSql: ExecSql): void {\n completedConnectionOnceKeys.delete(resolveCanonicalExecSql(execSql));\n}\n\nfunction defineExecSql(\n run: (\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ) => Promise<Array<SqlRow | SqlArrayRow>>,\n): ExecSql {\n function execSql(\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: \"object\" },\n ): Promise<SqlRow[]>;\n function execSql(\n sql: string,\n bind: SqlBind | undefined,\n options: { rowMode: \"array\" },\n ): Promise<SqlArrayRow[]>;\n function execSql(\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ): Promise<Array<SqlRow | SqlArrayRow>>;\n async function execSql(\n sql: string,\n bind?: SqlBind,\n options?: { rowMode?: SqlRowMode },\n ): Promise<Array<SqlRow | SqlArrayRow>> {\n return run(sql, bind, options);\n }\n\n return execSql;\n}\n\nexport function createExecSql(client: ExecSqlClientLike): ExecSql {\n const existingExecSql = clientExecSqls.get(client);\n if (existingExecSql) {\n return existingExecSql;\n }\n\n const execSql = defineExecSql(async (sql, bind, options) => {\n const result = await client.exec({\n sql,\n ...(bind !== undefined ? { bind } : {}),\n ...(options?.rowMode ? { rowMode: options.rowMode } : {}),\n });\n return result.rows;\n });\n\n clientExecSqls.set(client, execSql);\n return execSql;\n}\n\nfunction isSerializedSqlExec(execSql: ExecSql): boolean {\n return serializedSqlExecs.has(execSql);\n}\n\nfunction createSerializedSqlExec(execSql: ExecSql): ExecSql {\n if (isSerializedSqlExec(execSql)) {\n return execSql;\n }\n\n const serializedExecSql = defineExecSql(execSql);\n serializedSqlExecs.add(serializedExecSql);\n serializedSqlExecCanonicals.set(\n serializedExecSql,\n resolveCanonicalExecSql(execSql),\n );\n return serializedExecSql;\n}\n\n// SQLite transactions are scoped to the shared connection, so we must hold a\n// connection-level lock across multi-statement mutations to prevent interleaving.\n// Nested callers must keep passing the provided locked executor. Re-entering\n// with the original canonical executor will wait on the current mutation and\n// deadlock.\n// Each outermost mutation is drawn on DevTools tracks: time spent queued\n// behind another mutation, then time holding the lock.\nexport async function runSerializedSqlMutation<T>(\n execSql: ExecSql,\n operation: (execSql: ExecSql) => Promise<T> | T,\n): Promise<T> {\n if (isSerializedSqlExec(execSql)) {\n return operation(execSql);\n }\n\n const queuedAtMs = readUserTimingClock();\n const previous = sqlMutationQueue.get(execSql);\n let releaseCurrent = () => {};\n const current = new Promise<void>((resolve) => {\n releaseCurrent = resolve;\n });\n const waitForPrevious = (previous ?? Promise.resolve()).catch(\n () => undefined,\n );\n const queuedCurrent = waitForPrevious.then(() => current);\n\n sqlMutationQueue.set(execSql, queuedCurrent);\n await waitForPrevious;\n const acquiredAtMs = readUserTimingClock();\n if (previous) {\n recordUserTimingEntry({\n endMs: acquiredAtMs,\n name: \"SQLite mutation wait\",\n startMs: queuedAtMs,\n track: \"SQLite mutation queue\",\n });\n }\n\n let failed = true;\n try {\n const result = await operation(createSerializedSqlExec(execSql));\n failed = false;\n return result;\n } finally {\n const releasedAtMs = readUserTimingClock();\n releaseCurrent();\n if (sqlMutationQueue.get(execSql) === queuedCurrent) {\n sqlMutationQueue.delete(execSql);\n }\n recordUserTimingEntry({\n endMs: releasedAtMs,\n failed,\n name: \"SQLite mutation\",\n startMs: acquiredAtMs,\n track: \"SQLite mutations\",\n });\n }\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SQL } from "drizzle-orm";
|
|
2
2
|
import { getTableConfig, SQLiteSyncDialect, } from "drizzle-orm/sqlite-core";
|
|
3
3
|
import { hasCompletedConnectionOnce, markCompletedConnectionOnce, runSerializedSqlMutation, } from "./sqlExec.js";
|
|
4
|
+
import { sqliteRowsPerStatement } from "./sqliteBindBudget.js";
|
|
4
5
|
const sqliteDialect = new SQLiteSyncDialect();
|
|
5
6
|
function renderIdentifier(name) {
|
|
6
7
|
return `"${name.replaceAll('"', '""')}"`;
|
|
@@ -100,15 +101,30 @@ export function defineSqlTableSchema(table) {
|
|
|
100
101
|
function getTableEnsureKey(table) {
|
|
101
102
|
return `sql-table:${table.name}`;
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
// Two binds per table; the schema has far fewer tables than this.
|
|
105
|
+
const REQUIRED_COLUMN_TABLES_PER_STATEMENT = sqliteRowsPerStatement(2);
|
|
106
|
+
// One read of every checked table's stored columns. The first obsolete table,
|
|
107
|
+
// in ensure order, fails before any index DDL runs.
|
|
108
|
+
async function assertRequiredColumns(execSql, tables) {
|
|
109
|
+
const checked = tables.filter((table) => (table.requiredColumns?.length ?? 0) > 0);
|
|
110
|
+
const storedColumns = new Map();
|
|
111
|
+
for (let offset = 0; offset < checked.length; offset += REQUIRED_COLUMN_TABLES_PER_STATEMENT) {
|
|
112
|
+
const batch = checked.slice(offset, offset + REQUIRED_COLUMN_TABLES_PER_STATEMENT);
|
|
113
|
+
const rows = await execSql(batch
|
|
114
|
+
.map(() => "SELECT ? AS table_name, name FROM pragma_table_info(?)")
|
|
115
|
+
.join(" UNION ALL "), batch.flatMap((table) => [table.name, table.name]));
|
|
116
|
+
for (const { name, table_name: tableName } of rows) {
|
|
117
|
+
const tableKey = String(tableName);
|
|
118
|
+
const columns = storedColumns.get(tableKey) ?? new Set();
|
|
119
|
+
columns.add(String(name));
|
|
120
|
+
storedColumns.set(tableKey, columns);
|
|
121
|
+
}
|
|
106
122
|
}
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
123
|
+
for (const table of checked) {
|
|
124
|
+
const stored = storedColumns.get(table.name);
|
|
125
|
+
if (table.requiredColumns?.some((column) => !stored?.has(column))) {
|
|
126
|
+
throw new Error(`Local database schema for ${table.name} is obsolete; reset the local database before continuing`);
|
|
127
|
+
}
|
|
112
128
|
}
|
|
113
129
|
}
|
|
114
130
|
// Table ensures run on every query path, so completed ones are
|
|
@@ -118,17 +134,26 @@ async function assertRequiredColumns(execSql, table) {
|
|
|
118
134
|
// EXISTS no-ops. `resetConnectionSchemaMemo` forgets the memo when the schema
|
|
119
135
|
// is rebuilt out from under the runtime (local backup restore).
|
|
120
136
|
export async function ensureSqlTables(execSql, tables) {
|
|
121
|
-
const
|
|
137
|
+
const pendingByName = new Map();
|
|
138
|
+
for (const table of tables) {
|
|
139
|
+
if (!pendingByName.has(table.name) &&
|
|
140
|
+
!hasCompletedConnectionOnce(execSql, getTableEnsureKey(table))) {
|
|
141
|
+
pendingByName.set(table.name, table);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const pendingTables = [...pendingByName.values()];
|
|
122
145
|
if (pendingTables.length === 0) {
|
|
123
146
|
return;
|
|
124
147
|
}
|
|
148
|
+
// Each statement is a worker message, so the DDL travels in three: every
|
|
149
|
+
// CREATE TABLE, then the required-column read (an obsolete table fails
|
|
150
|
+
// before an index can trip over a missing column), then every CREATE INDEX.
|
|
125
151
|
await runSerializedSqlMutation(execSql, async (lockedExecSql) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
152
|
+
await lockedExecSql(pendingTables.map((table) => table.createSql).join(";\n"));
|
|
153
|
+
await assertRequiredColumns(lockedExecSql, pendingTables);
|
|
154
|
+
const indexSql = pendingTables.flatMap((table) => table.indexes ?? []);
|
|
155
|
+
if (indexSql.length > 0) {
|
|
156
|
+
await lockedExecSql(indexSql.join(";\n"));
|
|
132
157
|
}
|
|
133
158
|
});
|
|
134
159
|
for (const table of pendingTables) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlTableSchema.js","sourceRoot":"","sources":["sqlTableSchema.ts"],"names":[],"mappings":"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","sourcesContent":["import { SQL } from \"drizzle-orm\";\nimport {\n getTableConfig,\n type Index,\n type IndexColumn,\n type SQLiteColumn,\n SQLiteSyncDialect,\n type SQLiteTable,\n} from \"drizzle-orm/sqlite-core\";\nimport type { ExecSql } from \"./sqlExec\";\nimport {\n hasCompletedConnectionOnce,\n markCompletedConnectionOnce,\n runSerializedSqlMutation,\n} from \"./sqlExec\";\n\nexport interface SqlTableSchema {\n name: string;\n createSql: string;\n indexes?: ReadonlyArray<string>;\n requiredColumns?: ReadonlyArray<string>;\n}\n\nconst sqliteDialect = new SQLiteSyncDialect();\n\nfunction renderIdentifier(name: string): string {\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction renderDefaultValue(value: unknown): string {\n if (value === null) {\n return \"NULL\";\n }\n\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n\n if (value instanceof SQL) {\n return sqliteDialect.sqlToQuery(value).sql;\n }\n\n if (typeof value === \"number\") {\n return String(value);\n }\n\n if (typeof value === \"string\") {\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n }\n\n throw new Error(`Unsupported SQLite default value: ${String(value)}`);\n}\n\nfunction renderColumn(\n column: SQLiteColumn,\n inlinePrimaryKeyColumnName?: string,\n): string {\n const parts = [\n renderIdentifier(column.name),\n column.getSQLType().toUpperCase(),\n ];\n\n if (column.notNull) {\n parts.push(\"NOT NULL\");\n }\n\n if (column.hasDefault) {\n parts.push(\"DEFAULT\", renderDefaultValue(column.default));\n }\n\n if (column.primary || column.name === inlinePrimaryKeyColumnName) {\n parts.push(\"PRIMARY KEY\");\n }\n\n if (column.isUnique) {\n parts.push(\"UNIQUE\");\n }\n\n return parts.join(\" \");\n}\n\nfunction renderPrimaryKey(columns: ReadonlyArray<SQLiteColumn>): string {\n const columnNames = columns.map((column) => renderIdentifier(column.name));\n return `PRIMARY KEY (${columnNames.join(\", \")})`;\n}\n\nfunction renderUniqueConstraint(columns: ReadonlyArray<SQLiteColumn>): string {\n const columnNames = columns.map((column) => renderIdentifier(column.name));\n return `UNIQUE (${columnNames.join(\", \")})`;\n}\n\nfunction isSQLiteColumn(value: IndexColumn): value is SQLiteColumn {\n return (\n \"name\" in value && typeof value.name === \"string\" && \"getSQLType\" in value\n );\n}\n\nfunction renderIndexColumn(column: IndexColumn): string {\n if (isSQLiteColumn(column)) {\n return renderIdentifier(column.name);\n }\n\n return sqliteDialect.sqlToQuery(column.getSQL(), \"indexes\").sql;\n}\n\nfunction renderIndex(indexDefinition: Index): string {\n const config = indexDefinition.config;\n const unique = config.unique ? \"UNIQUE \" : \"\";\n const columns = config.columns.map(renderIndexColumn).join(\", \");\n const where = config.where\n ? ` WHERE ${sqliteDialect.sqlToQuery(config.where, \"indexes\").sql}`\n : \"\";\n\n return `CREATE ${unique}INDEX IF NOT EXISTS ${renderIdentifier(\n config.name,\n )} ON ${renderIdentifier(getTableConfig(config.table).name)} (${columns})${where}`;\n}\n\n/**\n * Render a Drizzle SQLite table definition into executable schema SQL.\n *\n * The client runtime creates local tables through `ensureSqlTables`, which works\n * with raw SQL strings rather than Drizzle migrations. This helper keeps the\n * Drizzle table definitions as the source of truth while preserving primary\n * keys, table-level unique constraints, partial indexes, default values, and\n * identifier quoting.\n */\nexport function defineSqlTableSchema(table: SQLiteTable): SqlTableSchema {\n const config = getTableConfig(table);\n const inlinePrimaryKeyColumnName =\n config.primaryKeys.length === 1 &&\n config.primaryKeys[0]?.columns.length === 1\n ? config.primaryKeys[0].columns[0]?.name\n : undefined;\n const columns = config.columns.map((column) =>\n renderColumn(column, inlinePrimaryKeyColumnName),\n );\n const primaryKeys = inlinePrimaryKeyColumnName\n ? []\n : config.primaryKeys.map((key) => renderPrimaryKey(key.columns));\n const uniqueConstraints = config.uniqueConstraints.map((constraint) =>\n renderUniqueConstraint(constraint.columns),\n );\n const columnDefinitions = [...columns, ...primaryKeys, ...uniqueConstraints];\n\n return {\n name: config.name,\n createSql: `CREATE TABLE IF NOT EXISTS ${renderIdentifier(config.name)} (\n ${columnDefinitions.join(\",\\n \")}\n)`,\n indexes: config.indexes.map(renderIndex),\n };\n}\n\nfunction getTableEnsureKey(table: SqlTableSchema): string {\n return `sql-table:${table.name}`;\n}\n\nasync function assertRequiredColumns(\n execSql: ExecSql,\n table: SqlTableSchema,\n): Promise<void> {\n if (!table.requiredColumns || table.requiredColumns.length === 0) {\n return;\n }\n const rows = await execSql(\n `PRAGMA table_info(${renderIdentifier(table.name)})`,\n );\n const storedColumns = new Set(rows.map(({ name }) => name));\n const missingColumns = table.requiredColumns.filter(\n (column) => !storedColumns.has(column),\n );\n if (missingColumns.length > 0) {\n throw new Error(\n `Local database schema for ${table.name} is obsolete; reset the local database before continuing`,\n );\n }\n}\n\n// Table ensures run on every query path, so completed ones are\n// remembered per connection: a re-ensure of an already-ensured table skips the\n// DDL round-trips AND the serialized mutation lock, keeping diagnostic reads\n// from queueing behind bulk-import writes just to re-issue CREATE IF NOT\n// EXISTS no-ops. `resetConnectionSchemaMemo` forgets the memo when the schema\n// is rebuilt out from under the runtime (local backup restore).\nexport async function ensureSqlTables(\n execSql: ExecSql,\n tables: ReadonlyArray<SqlTableSchema>,\n): Promise<void> {\n const pendingTables = tables.filter(\n (table) => !hasCompletedConnectionOnce(execSql, getTableEnsureKey(table)),\n );\n if (pendingTables.length === 0) {\n return;\n }\n\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n for (const table of pendingTables) {\n await lockedExecSql(table.createSql);\n await assertRequiredColumns(lockedExecSql, table);\n for (const indexSql of table.indexes ?? []) {\n await lockedExecSql(indexSql);\n }\n }\n });\n for (const table of pendingTables) {\n markCompletedConnectionOnce(execSql, getTableEnsureKey(table));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sqlTableSchema.js","sourceRoot":"","sources":["sqlTableSchema.ts"],"names":[],"mappings":"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","sourcesContent":["import { SQL } from \"drizzle-orm\";\nimport {\n getTableConfig,\n type Index,\n type IndexColumn,\n type SQLiteColumn,\n SQLiteSyncDialect,\n type SQLiteTable,\n} from \"drizzle-orm/sqlite-core\";\nimport type { ExecSql } from \"./sqlExec\";\nimport {\n hasCompletedConnectionOnce,\n markCompletedConnectionOnce,\n runSerializedSqlMutation,\n} from \"./sqlExec\";\nimport { sqliteRowsPerStatement } from \"./sqliteBindBudget\";\n\nexport interface SqlTableSchema {\n name: string;\n createSql: string;\n indexes?: ReadonlyArray<string>;\n requiredColumns?: ReadonlyArray<string>;\n}\n\nconst sqliteDialect = new SQLiteSyncDialect();\n\nfunction renderIdentifier(name: string): string {\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction renderDefaultValue(value: unknown): string {\n if (value === null) {\n return \"NULL\";\n }\n\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n\n if (value instanceof SQL) {\n return sqliteDialect.sqlToQuery(value).sql;\n }\n\n if (typeof value === \"number\") {\n return String(value);\n }\n\n if (typeof value === \"string\") {\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n }\n\n throw new Error(`Unsupported SQLite default value: ${String(value)}`);\n}\n\nfunction renderColumn(\n column: SQLiteColumn,\n inlinePrimaryKeyColumnName?: string,\n): string {\n const parts = [\n renderIdentifier(column.name),\n column.getSQLType().toUpperCase(),\n ];\n\n if (column.notNull) {\n parts.push(\"NOT NULL\");\n }\n\n if (column.hasDefault) {\n parts.push(\"DEFAULT\", renderDefaultValue(column.default));\n }\n\n if (column.primary || column.name === inlinePrimaryKeyColumnName) {\n parts.push(\"PRIMARY KEY\");\n }\n\n if (column.isUnique) {\n parts.push(\"UNIQUE\");\n }\n\n return parts.join(\" \");\n}\n\nfunction renderPrimaryKey(columns: ReadonlyArray<SQLiteColumn>): string {\n const columnNames = columns.map((column) => renderIdentifier(column.name));\n return `PRIMARY KEY (${columnNames.join(\", \")})`;\n}\n\nfunction renderUniqueConstraint(columns: ReadonlyArray<SQLiteColumn>): string {\n const columnNames = columns.map((column) => renderIdentifier(column.name));\n return `UNIQUE (${columnNames.join(\", \")})`;\n}\n\nfunction isSQLiteColumn(value: IndexColumn): value is SQLiteColumn {\n return (\n \"name\" in value && typeof value.name === \"string\" && \"getSQLType\" in value\n );\n}\n\nfunction renderIndexColumn(column: IndexColumn): string {\n if (isSQLiteColumn(column)) {\n return renderIdentifier(column.name);\n }\n\n return sqliteDialect.sqlToQuery(column.getSQL(), \"indexes\").sql;\n}\n\nfunction renderIndex(indexDefinition: Index): string {\n const config = indexDefinition.config;\n const unique = config.unique ? \"UNIQUE \" : \"\";\n const columns = config.columns.map(renderIndexColumn).join(\", \");\n const where = config.where\n ? ` WHERE ${sqliteDialect.sqlToQuery(config.where, \"indexes\").sql}`\n : \"\";\n\n return `CREATE ${unique}INDEX IF NOT EXISTS ${renderIdentifier(\n config.name,\n )} ON ${renderIdentifier(getTableConfig(config.table).name)} (${columns})${where}`;\n}\n\n/**\n * Render a Drizzle SQLite table definition into executable schema SQL.\n *\n * The client runtime creates local tables through `ensureSqlTables`, which works\n * with raw SQL strings rather than Drizzle migrations. This helper keeps the\n * Drizzle table definitions as the source of truth while preserving primary\n * keys, table-level unique constraints, partial indexes, default values, and\n * identifier quoting.\n */\nexport function defineSqlTableSchema(table: SQLiteTable): SqlTableSchema {\n const config = getTableConfig(table);\n const inlinePrimaryKeyColumnName =\n config.primaryKeys.length === 1 &&\n config.primaryKeys[0]?.columns.length === 1\n ? config.primaryKeys[0].columns[0]?.name\n : undefined;\n const columns = config.columns.map((column) =>\n renderColumn(column, inlinePrimaryKeyColumnName),\n );\n const primaryKeys = inlinePrimaryKeyColumnName\n ? []\n : config.primaryKeys.map((key) => renderPrimaryKey(key.columns));\n const uniqueConstraints = config.uniqueConstraints.map((constraint) =>\n renderUniqueConstraint(constraint.columns),\n );\n const columnDefinitions = [...columns, ...primaryKeys, ...uniqueConstraints];\n\n return {\n name: config.name,\n createSql: `CREATE TABLE IF NOT EXISTS ${renderIdentifier(config.name)} (\n ${columnDefinitions.join(\",\\n \")}\n)`,\n indexes: config.indexes.map(renderIndex),\n };\n}\n\nfunction getTableEnsureKey(table: SqlTableSchema): string {\n return `sql-table:${table.name}`;\n}\n\n// Two binds per table; the schema has far fewer tables than this.\nconst REQUIRED_COLUMN_TABLES_PER_STATEMENT = sqliteRowsPerStatement(2);\n\n// One read of every checked table's stored columns. The first obsolete table,\n// in ensure order, fails before any index DDL runs.\nasync function assertRequiredColumns(\n execSql: ExecSql,\n tables: ReadonlyArray<SqlTableSchema>,\n): Promise<void> {\n const checked = tables.filter(\n (table) => (table.requiredColumns?.length ?? 0) > 0,\n );\n const storedColumns = new Map<string, Set<string>>();\n for (\n let offset = 0;\n offset < checked.length;\n offset += REQUIRED_COLUMN_TABLES_PER_STATEMENT\n ) {\n const batch = checked.slice(\n offset,\n offset + REQUIRED_COLUMN_TABLES_PER_STATEMENT,\n );\n const rows = await execSql(\n batch\n .map(() => \"SELECT ? AS table_name, name FROM pragma_table_info(?)\")\n .join(\" UNION ALL \"),\n batch.flatMap((table) => [table.name, table.name]),\n );\n for (const { name, table_name: tableName } of rows) {\n const tableKey = String(tableName);\n const columns = storedColumns.get(tableKey) ?? new Set<string>();\n columns.add(String(name));\n storedColumns.set(tableKey, columns);\n }\n }\n for (const table of checked) {\n const stored = storedColumns.get(table.name);\n if (table.requiredColumns?.some((column) => !stored?.has(column))) {\n throw new Error(\n `Local database schema for ${table.name} is obsolete; reset the local database before continuing`,\n );\n }\n }\n}\n\n// Table ensures run on every query path, so completed ones are\n// remembered per connection: a re-ensure of an already-ensured table skips the\n// DDL round-trips AND the serialized mutation lock, keeping diagnostic reads\n// from queueing behind bulk-import writes just to re-issue CREATE IF NOT\n// EXISTS no-ops. `resetConnectionSchemaMemo` forgets the memo when the schema\n// is rebuilt out from under the runtime (local backup restore).\nexport async function ensureSqlTables(\n execSql: ExecSql,\n tables: ReadonlyArray<SqlTableSchema>,\n): Promise<void> {\n const pendingByName = new Map<string, SqlTableSchema>();\n for (const table of tables) {\n if (\n !pendingByName.has(table.name) &&\n !hasCompletedConnectionOnce(execSql, getTableEnsureKey(table))\n ) {\n pendingByName.set(table.name, table);\n }\n }\n const pendingTables = [...pendingByName.values()];\n if (pendingTables.length === 0) {\n return;\n }\n\n // Each statement is a worker message, so the DDL travels in three: every\n // CREATE TABLE, then the required-column read (an obsolete table fails\n // before an index can trip over a missing column), then every CREATE INDEX.\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await lockedExecSql(\n pendingTables.map((table) => table.createSql).join(\";\\n\"),\n );\n await assertRequiredColumns(lockedExecSql, pendingTables);\n const indexSql = pendingTables.flatMap((table) => table.indexes ?? []);\n if (indexSql.length > 0) {\n await lockedExecSql(indexSql.join(\";\\n\"));\n }\n });\n for (const table of pendingTables) {\n markCompletedConnectionOnce(execSql, getTableEnsureKey(table));\n }\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { drizzle } from "drizzle-orm/sqlite-proxy";
|
|
2
2
|
import { clientSQLiteSchema } from "./schema/index.js";
|
|
3
|
+
import { closeTransactionSchemaMemoScope, openTransactionSchemaMemoScope, } from "./sqlExec.js";
|
|
3
4
|
import { assertClientSQLiteCommitAllowed, beginClientSQLiteCommitGuards, captureClientSQLiteCommitGuards, clearClientSQLiteCommitGuards, rethrowClientSQLiteCommitGuardFailure, } from "./sqliteCommitGuards.js";
|
|
4
|
-
import { createExecSql,
|
|
5
|
+
import { createExecSql, resolveCanonicalExecSql, runSerializedSqlMutation, } from "./sqlSchema.js";
|
|
5
6
|
const runtimeByExecSql = new WeakMap();
|
|
6
7
|
function transactionBeginStatement(config) {
|
|
7
8
|
if (config?.behavior === "immediate")
|
|
@@ -86,19 +87,23 @@ async function runNestedSavepointScope(canonical, lockedExecSql, operation) {
|
|
|
86
87
|
transactionDepthByCanonicalExecSql.set(canonical, depth + 1);
|
|
87
88
|
const savepoint = `runtime_transaction_sp_${depth}`;
|
|
88
89
|
const discardNestedGuards = captureClientSQLiteCommitGuards(canonical);
|
|
90
|
+
openTransactionSchemaMemoScope(canonical);
|
|
91
|
+
let released = false;
|
|
89
92
|
try {
|
|
90
93
|
await lockedExecSql(`SAVEPOINT ${savepoint}`);
|
|
91
94
|
const result = await operation();
|
|
92
95
|
await lockedExecSql(`RELEASE SAVEPOINT ${savepoint}`);
|
|
96
|
+
released = true;
|
|
93
97
|
return result;
|
|
94
98
|
}
|
|
95
99
|
catch (error) {
|
|
96
100
|
await lockedExecSql(`ROLLBACK TO SAVEPOINT ${savepoint}`).then(discardNestedGuards, () => undefined);
|
|
97
101
|
await lockedExecSql(`RELEASE SAVEPOINT ${savepoint}`).catch(() => undefined);
|
|
98
|
-
resetConnectionSchemaMemo(canonical);
|
|
99
102
|
throw error;
|
|
100
103
|
}
|
|
101
104
|
finally {
|
|
105
|
+
// The savepoint's rollback undid only the schema it first ensured.
|
|
106
|
+
closeTransactionSchemaMemoScope(canonical, released);
|
|
102
107
|
transactionDepthByCanonicalExecSql.set(canonical, depth);
|
|
103
108
|
if (chains.get(depthAtEntry) === tracked) {
|
|
104
109
|
chains.delete(depthAtEntry);
|
|
@@ -142,19 +147,20 @@ function createRuntimeForExecSql(execSql) {
|
|
|
142
147
|
}
|
|
143
148
|
transactionDepthByCanonicalExecSql.set(canonical, 1);
|
|
144
149
|
beginClientSQLiteCommitGuards(canonical);
|
|
150
|
+
openTransactionSchemaMemoScope(canonical);
|
|
151
|
+
let committed = false;
|
|
145
152
|
try {
|
|
146
|
-
|
|
153
|
+
const result = await db.transaction(operation, config);
|
|
154
|
+
committed = true;
|
|
155
|
+
return result;
|
|
147
156
|
}
|
|
148
157
|
catch (error) {
|
|
149
|
-
// The rollback undid any DDL this transaction ran, but the
|
|
150
|
-
// per-connection ensure memo still claims it exists — reset it
|
|
151
|
-
// so later operations re-ensure instead of hitting missing
|
|
152
|
-
// tables.
|
|
153
|
-
resetConnectionSchemaMemo(canonical);
|
|
154
158
|
rethrowClientSQLiteCommitGuardFailure(canonical);
|
|
155
159
|
throw error;
|
|
156
160
|
}
|
|
157
161
|
finally {
|
|
162
|
+
// A rollback forgets the ensures it undid (see sqlExec).
|
|
163
|
+
closeTransactionSchemaMemoScope(canonical, committed);
|
|
158
164
|
clearClientSQLiteCommitGuards(canonical);
|
|
159
165
|
transactionDepthByCanonicalExecSql.delete(canonical);
|
|
160
166
|
}
|
|
@@ -168,12 +174,13 @@ function createRuntimeForExecSql(execSql) {
|
|
|
168
174
|
}
|
|
169
175
|
transactionDepthByCanonicalExecSql.set(canonical, 1);
|
|
170
176
|
beginClientSQLiteCommitGuards(canonical);
|
|
177
|
+
openTransactionSchemaMemoScope(canonical);
|
|
178
|
+
let committed = false;
|
|
171
179
|
try {
|
|
172
180
|
await lockedExecSql(transactionBeginStatement(config));
|
|
173
181
|
const result = await operation(db);
|
|
174
182
|
if (!canCommit()) {
|
|
175
183
|
await lockedExecSql("ROLLBACK");
|
|
176
|
-
resetConnectionSchemaMemo(canonical);
|
|
177
184
|
return { committed: false, result: null };
|
|
178
185
|
}
|
|
179
186
|
// The guard passed in THIS synchronous slice and the COMMIT is
|
|
@@ -184,15 +191,16 @@ function createRuntimeForExecSql(execSql) {
|
|
|
184
191
|
assertClientSQLiteCommitAllowed(lockedExecSql);
|
|
185
192
|
const commit = lockedExecSql("COMMIT");
|
|
186
193
|
await commit;
|
|
194
|
+
committed = true;
|
|
187
195
|
return { committed: true, result };
|
|
188
196
|
}
|
|
189
197
|
catch (error) {
|
|
190
198
|
await lockedExecSql("ROLLBACK").catch(() => undefined);
|
|
191
|
-
resetConnectionSchemaMemo(canonical);
|
|
192
199
|
rethrowClientSQLiteCommitGuardFailure(canonical);
|
|
193
200
|
throw error;
|
|
194
201
|
}
|
|
195
202
|
finally {
|
|
203
|
+
closeTransactionSchemaMemoScope(canonical, committed);
|
|
196
204
|
clearClientSQLiteCommitGuards(canonical);
|
|
197
205
|
transactionDepthByCanonicalExecSql.delete(canonical);
|
|
198
206
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlitePersistenceRuntime.js","sourceRoot":"","sources":["sqlitePersistenceRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RemoteCallback,\n SqliteRemoteDatabase,\n} from \"drizzle-orm/sqlite-proxy\";\nimport { drizzle } from \"drizzle-orm/sqlite-proxy\";\nimport { clientSQLiteSchema } from \"./schema\";\nimport {\n assertClientSQLiteCommitAllowed,\n beginClientSQLiteCommitGuards,\n captureClientSQLiteCommitGuards,\n clearClientSQLiteCommitGuards,\n rethrowClientSQLiteCommitGuardFailure,\n} from \"./sqliteCommitGuards\";\nimport {\n createExecSql,\n type ExecSql,\n type ExecSqlClientLike,\n resetConnectionSchemaMemo,\n resolveCanonicalExecSql,\n runSerializedSqlMutation,\n type SqlArrayRow,\n type SqlRowValue,\n} from \"./sqlSchema\";\n\nexport type ClientSQLiteSchema = typeof clientSQLiteSchema;\nexport type ClientSQLiteDatabase = SqliteRemoteDatabase<ClientSQLiteSchema>;\nexport type ClientSQLiteTransactionConfig = NonNullable<\n Parameters<ClientSQLiteDatabase[\"transaction\"]>[1]\n>;\n/**\n * The handle a runtime transaction callback receives: the transaction's\n * query interface WITHOUT `rollback` (throw instead — every scope maps an\n * exception to its own rollback) and WITHOUT `transaction` (nest by calling\n * `runtime.transaction` again, which scopes to a savepoint). Narrowing the\n * contract here is what lets a nested scope share the connection-backed\n * database handle safely.\n */\nexport type ClientSQLiteTransactionScope = Pick<\n ClientSQLiteDatabase,\n | \"all\"\n | \"delete\"\n | \"get\"\n | \"insert\"\n | \"query\"\n | \"run\"\n | \"select\"\n | \"selectDistinct\"\n | \"update\"\n | \"values\"\n>;\n\nexport interface ClientSQLitePersistenceRuntime {\n db: ClientSQLiteDatabase;\n execSql: ExecSql;\n runMutation<T>(\n operation: (db: ClientSQLiteDatabase) => Promise<T> | T,\n ): Promise<T>;\n transaction<T>(\n operation: (tx: ClientSQLiteTransactionScope) => Promise<T>,\n config?: ClientSQLiteTransactionConfig,\n ): Promise<T>;\n /**\n * A transaction whose commit is gated on a SYNCHRONOUS guard: the guard\n * runs and — when it passes — the COMMIT is dispatched in the same\n * synchronous slice, so no JavaScript (an identity replacement included)\n * can interleave between the decision and the commit dispatch. Resolves\n * with `committed: false` (all writes rolled back) when the guard refuses.\n */\n guardedTransaction<T>(\n operation: (tx: ClientSQLiteTransactionScope) => Promise<T>,\n canCommit: () => boolean,\n config?: ClientSQLiteTransactionConfig,\n ): Promise<{ committed: boolean; result: T | null }>;\n}\n\nconst runtimeByExecSql = new WeakMap<ExecSql, ClientSQLitePersistenceRuntime>();\n\nfunction transactionBeginStatement(\n config: ClientSQLiteTransactionConfig | undefined,\n): \"BEGIN\" | \"BEGIN EXCLUSIVE\" | \"BEGIN IMMEDIATE\" {\n if (config?.behavior === \"immediate\") return \"BEGIN IMMEDIATE\";\n if (config?.behavior === \"exclusive\") return \"BEGIN EXCLUSIVE\";\n return \"BEGIN\";\n}\n\n// One transaction depth per underlying connection (canonical executor), so a\n// runtime.transaction call made while another transaction is already open on\n// the same connection degrades to a SAVEPOINT scope instead of issuing a\n// second BEGIN. Callers inside a serialized mutation get separate runtime\n// instances per locked executor, so the depth cannot live on the runtime.\nconst transactionDepthByCanonicalExecSql = new WeakMap<ExecSql, number>();\n// Sibling nested scopes on one connection must not interleave: SQLite\n// savepoints form a stack, so releasing an earlier savepoint would also\n// release a later sibling started concurrently. Scopes serialize per\n// NESTING DEPTH — siblings share a depth and queue behind each other, while\n// a descendant runs one level deeper and must NOT wait on its own enclosing\n// scope (that wait can never resolve).\nconst nestedScopeChainsByCanonicalExecSql = new WeakMap<\n ExecSql,\n Map<number, Promise<unknown>>\n>();\nconst execSqlByClient = new WeakMap<ExecSqlClientLike, ExecSql>();\n\nfunction toSqlRowValue(value: unknown): SqlRowValue {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === \"string\" || typeof value === \"number\") {\n return value;\n }\n\n if (typeof value === \"boolean\") {\n return value ? 1 : 0;\n }\n\n throw new Error(`Unsupported SQLite bind value: ${String(value)}`);\n}\n\nfunction createRemoteCallback(getExecSql: () => ExecSql): RemoteCallback {\n type RemoteResult = Awaited<ReturnType<RemoteCallback>>;\n\n function getRemoteResult(rows: readonly SqlArrayRow[]): RemoteResult {\n const row = rows[0];\n if (row !== undefined) {\n return { rows: row } satisfies RemoteResult;\n }\n\n // Drizzle's RemoteCallback type requires rows, but sqlite-proxy's get()\n // mapper treats an undefined rows value as \"no row found\".\n return Object.defineProperty({ rows: [] } satisfies RemoteResult, \"rows\", {\n enumerable: true,\n value: undefined,\n });\n }\n\n return async (sql, params, method) => {\n const execSql = getExecSql();\n if (sql.trim().toLowerCase() === \"commit\")\n assertClientSQLiteCommitAllowed(execSql);\n const rows = await execSql(sql, params.map(toSqlRowValue), {\n rowMode: \"array\",\n });\n\n if (method === \"get\") {\n return getRemoteResult(rows);\n }\n\n return { rows } satisfies RemoteResult;\n };\n}\n\nfunction createClientSQLiteDatabase(\n getExecSql: () => ExecSql,\n): ClientSQLiteDatabase {\n return drizzle(createRemoteCallback(getExecSql), {\n schema: clientSQLiteSchema,\n });\n}\n\n// Serialize nested savepoint scopes per connection AND depth: a sibling\n// (same depth) queues behind the previous sibling so their savepoints\n// strictly nest instead of interleaving on the shared stack, while a\n// descendant (called from inside an executing scope, so one level deeper)\n// starts on its own depth's chain and never waits on its unresolved parent.\nasync function runNestedSavepointScope<T>(\n canonical: ExecSql,\n lockedExecSql: ExecSql,\n operation: () => Promise<T>,\n): Promise<T> {\n const depthAtEntry = transactionDepthByCanonicalExecSql.get(canonical) ?? 0;\n const chains =\n nestedScopeChainsByCanonicalExecSql.get(canonical) ??\n new Map<number, Promise<unknown>>();\n nestedScopeChainsByCanonicalExecSql.set(canonical, chains);\n const previous = chains.get(depthAtEntry) ?? Promise.resolve();\n let tracked: Promise<unknown> = Promise.resolve();\n const scope = previous\n .catch(() => undefined)\n .then(async () => {\n const depth = transactionDepthByCanonicalExecSql.get(canonical) ?? 0;\n transactionDepthByCanonicalExecSql.set(canonical, depth + 1);\n const savepoint = `runtime_transaction_sp_${depth}`;\n const discardNestedGuards = captureClientSQLiteCommitGuards(canonical);\n try {\n await lockedExecSql(`SAVEPOINT ${savepoint}`);\n const result = await operation();\n await lockedExecSql(`RELEASE SAVEPOINT ${savepoint}`);\n return result;\n } catch (error: unknown) {\n await lockedExecSql(`ROLLBACK TO SAVEPOINT ${savepoint}`).then(\n discardNestedGuards,\n () => undefined,\n );\n await lockedExecSql(`RELEASE SAVEPOINT ${savepoint}`).catch(\n () => undefined,\n );\n resetConnectionSchemaMemo(canonical);\n throw error;\n } finally {\n transactionDepthByCanonicalExecSql.set(canonical, depth);\n if (chains.get(depthAtEntry) === tracked) {\n chains.delete(depthAtEntry);\n }\n }\n });\n tracked = scope.catch(() => undefined);\n chains.set(depthAtEntry, tracked);\n return scope;\n}\n\nfunction createRuntimeForExecSql(\n execSql: ExecSql,\n): ClientSQLitePersistenceRuntime {\n let activeExecSql = execSql;\n const db = createClientSQLiteDatabase(() => activeExecSql);\n\n async function withActiveExecSql<T>(\n nextExecSql: ExecSql,\n operation: () => Promise<T> | T,\n ): Promise<T> {\n const previousExecSql = activeExecSql;\n activeExecSql = nextExecSql;\n\n try {\n return await operation();\n } finally {\n activeExecSql = previousExecSql;\n }\n }\n\n const runtime: ClientSQLitePersistenceRuntime = {\n db,\n execSql,\n runMutation(operation) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n withActiveExecSql(lockedExecSql, () => operation(db)),\n );\n },\n transaction(operation, config) {\n // A caller already inside an open transaction on this connection MUST\n // reach us through the transaction's locked executor (the runtime that\n // executor resolves to detects the open transaction below and joins it\n // as a savepoint scope). Re-entering through the canonical executor\n // queues here for full isolation — the contract every persistence\n // helper follows by passing its received locked executor down.\n const canonical = resolveCanonicalExecSql(execSql);\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n withActiveExecSql(lockedExecSql, async () => {\n if ((transactionDepthByCanonicalExecSql.get(canonical) ?? 0) > 0) {\n return runNestedSavepointScope(canonical, lockedExecSql, () =>\n operation(db),\n );\n }\n\n transactionDepthByCanonicalExecSql.set(canonical, 1);\n beginClientSQLiteCommitGuards(canonical);\n try {\n return await db.transaction(operation, config);\n } catch (error: unknown) {\n // The rollback undid any DDL this transaction ran, but the\n // per-connection ensure memo still claims it exists — reset it\n // so later operations re-ensure instead of hitting missing\n // tables.\n resetConnectionSchemaMemo(canonical);\n rethrowClientSQLiteCommitGuardFailure(canonical);\n throw error;\n } finally {\n clearClientSQLiteCommitGuards(canonical);\n transactionDepthByCanonicalExecSql.delete(canonical);\n }\n }),\n );\n },\n guardedTransaction(operation, canCommit, config) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n withActiveExecSql(lockedExecSql, async () => {\n const canonical = resolveCanonicalExecSql(execSql);\n if ((transactionDepthByCanonicalExecSql.get(canonical) ?? 0) > 0) {\n throw new Error(\n \"guardedTransaction cannot nest inside an open transaction\",\n );\n }\n\n transactionDepthByCanonicalExecSql.set(canonical, 1);\n beginClientSQLiteCommitGuards(canonical);\n try {\n await lockedExecSql(transactionBeginStatement(config));\n const result = await operation(db);\n if (!canCommit()) {\n await lockedExecSql(\"ROLLBACK\");\n resetConnectionSchemaMemo(canonical);\n return { committed: false, result: null };\n }\n // The guard passed in THIS synchronous slice and the COMMIT is\n // dispatched in the same slice: no JavaScript can run between\n // the two, so the decision cannot go stale before dispatch. (A\n // host tearing the connection down concurrently is resolved by\n // SQLite's own commit atomicity, not by anything client-side.)\n assertClientSQLiteCommitAllowed(lockedExecSql);\n const commit = lockedExecSql(\"COMMIT\");\n await commit;\n return { committed: true, result };\n } catch (error: unknown) {\n await lockedExecSql(\"ROLLBACK\").catch(() => undefined);\n resetConnectionSchemaMemo(canonical);\n rethrowClientSQLiteCommitGuardFailure(canonical);\n throw error;\n } finally {\n clearClientSQLiteCommitGuards(canonical);\n transactionDepthByCanonicalExecSql.delete(canonical);\n }\n }),\n );\n },\n };\n\n runtimeByExecSql.set(execSql, runtime);\n return runtime;\n}\n\nexport function getClientSQLitePersistenceRuntime(\n execSql: ExecSql,\n): ClientSQLitePersistenceRuntime {\n return runtimeByExecSql.get(execSql) ?? createRuntimeForExecSql(execSql);\n}\n\nexport function createClientSQLitePersistenceRuntime(\n client: ExecSqlClientLike,\n): ClientSQLitePersistenceRuntime {\n let execSql = execSqlByClient.get(client);\n if (!execSql) {\n execSql = createExecSql(client);\n execSqlByClient.set(client, execSql);\n }\n\n return getClientSQLitePersistenceRuntime(execSql);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sqlitePersistenceRuntime.js","sourceRoot":"","sources":["sqlitePersistenceRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RemoteCallback,\n SqliteRemoteDatabase,\n} from \"drizzle-orm/sqlite-proxy\";\nimport { drizzle } from \"drizzle-orm/sqlite-proxy\";\nimport { clientSQLiteSchema } from \"./schema\";\nimport {\n closeTransactionSchemaMemoScope,\n openTransactionSchemaMemoScope,\n} from \"./sqlExec\";\nimport {\n assertClientSQLiteCommitAllowed,\n beginClientSQLiteCommitGuards,\n captureClientSQLiteCommitGuards,\n clearClientSQLiteCommitGuards,\n rethrowClientSQLiteCommitGuardFailure,\n} from \"./sqliteCommitGuards\";\nimport {\n createExecSql,\n type ExecSql,\n type ExecSqlClientLike,\n resolveCanonicalExecSql,\n runSerializedSqlMutation,\n type SqlArrayRow,\n type SqlRowValue,\n} from \"./sqlSchema\";\n\nexport type ClientSQLiteSchema = typeof clientSQLiteSchema;\nexport type ClientSQLiteDatabase = SqliteRemoteDatabase<ClientSQLiteSchema>;\nexport type ClientSQLiteTransactionConfig = NonNullable<\n Parameters<ClientSQLiteDatabase[\"transaction\"]>[1]\n>;\n/**\n * The handle a runtime transaction callback receives: the transaction's\n * query interface WITHOUT `rollback` (throw instead — every scope maps an\n * exception to its own rollback) and WITHOUT `transaction` (nest by calling\n * `runtime.transaction` again, which scopes to a savepoint). Narrowing the\n * contract here is what lets a nested scope share the connection-backed\n * database handle safely.\n */\nexport type ClientSQLiteTransactionScope = Pick<\n ClientSQLiteDatabase,\n | \"all\"\n | \"delete\"\n | \"get\"\n | \"insert\"\n | \"query\"\n | \"run\"\n | \"select\"\n | \"selectDistinct\"\n | \"update\"\n | \"values\"\n>;\n\nexport interface ClientSQLitePersistenceRuntime {\n db: ClientSQLiteDatabase;\n execSql: ExecSql;\n runMutation<T>(\n operation: (db: ClientSQLiteDatabase) => Promise<T> | T,\n ): Promise<T>;\n transaction<T>(\n operation: (tx: ClientSQLiteTransactionScope) => Promise<T>,\n config?: ClientSQLiteTransactionConfig,\n ): Promise<T>;\n /**\n * A transaction whose commit is gated on a SYNCHRONOUS guard: the guard\n * runs and — when it passes — the COMMIT is dispatched in the same\n * synchronous slice, so no JavaScript (an identity replacement included)\n * can interleave between the decision and the commit dispatch. Resolves\n * with `committed: false` (all writes rolled back) when the guard refuses.\n */\n guardedTransaction<T>(\n operation: (tx: ClientSQLiteTransactionScope) => Promise<T>,\n canCommit: () => boolean,\n config?: ClientSQLiteTransactionConfig,\n ): Promise<{ committed: boolean; result: T | null }>;\n}\n\nconst runtimeByExecSql = new WeakMap<ExecSql, ClientSQLitePersistenceRuntime>();\n\nfunction transactionBeginStatement(\n config: ClientSQLiteTransactionConfig | undefined,\n): \"BEGIN\" | \"BEGIN EXCLUSIVE\" | \"BEGIN IMMEDIATE\" {\n if (config?.behavior === \"immediate\") return \"BEGIN IMMEDIATE\";\n if (config?.behavior === \"exclusive\") return \"BEGIN EXCLUSIVE\";\n return \"BEGIN\";\n}\n\n// One transaction depth per underlying connection (canonical executor), so a\n// runtime.transaction call made while another transaction is already open on\n// the same connection degrades to a SAVEPOINT scope instead of issuing a\n// second BEGIN. Callers inside a serialized mutation get separate runtime\n// instances per locked executor, so the depth cannot live on the runtime.\nconst transactionDepthByCanonicalExecSql = new WeakMap<ExecSql, number>();\n// Sibling nested scopes on one connection must not interleave: SQLite\n// savepoints form a stack, so releasing an earlier savepoint would also\n// release a later sibling started concurrently. Scopes serialize per\n// NESTING DEPTH — siblings share a depth and queue behind each other, while\n// a descendant runs one level deeper and must NOT wait on its own enclosing\n// scope (that wait can never resolve).\nconst nestedScopeChainsByCanonicalExecSql = new WeakMap<\n ExecSql,\n Map<number, Promise<unknown>>\n>();\nconst execSqlByClient = new WeakMap<ExecSqlClientLike, ExecSql>();\n\nfunction toSqlRowValue(value: unknown): SqlRowValue {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === \"string\" || typeof value === \"number\") {\n return value;\n }\n\n if (typeof value === \"boolean\") {\n return value ? 1 : 0;\n }\n\n throw new Error(`Unsupported SQLite bind value: ${String(value)}`);\n}\n\nfunction createRemoteCallback(getExecSql: () => ExecSql): RemoteCallback {\n type RemoteResult = Awaited<ReturnType<RemoteCallback>>;\n\n function getRemoteResult(rows: readonly SqlArrayRow[]): RemoteResult {\n const row = rows[0];\n if (row !== undefined) {\n return { rows: row } satisfies RemoteResult;\n }\n\n // Drizzle's RemoteCallback type requires rows, but sqlite-proxy's get()\n // mapper treats an undefined rows value as \"no row found\".\n return Object.defineProperty({ rows: [] } satisfies RemoteResult, \"rows\", {\n enumerable: true,\n value: undefined,\n });\n }\n\n return async (sql, params, method) => {\n const execSql = getExecSql();\n if (sql.trim().toLowerCase() === \"commit\")\n assertClientSQLiteCommitAllowed(execSql);\n const rows = await execSql(sql, params.map(toSqlRowValue), {\n rowMode: \"array\",\n });\n\n if (method === \"get\") {\n return getRemoteResult(rows);\n }\n\n return { rows } satisfies RemoteResult;\n };\n}\n\nfunction createClientSQLiteDatabase(\n getExecSql: () => ExecSql,\n): ClientSQLiteDatabase {\n return drizzle(createRemoteCallback(getExecSql), {\n schema: clientSQLiteSchema,\n });\n}\n\n// Serialize nested savepoint scopes per connection AND depth: a sibling\n// (same depth) queues behind the previous sibling so their savepoints\n// strictly nest instead of interleaving on the shared stack, while a\n// descendant (called from inside an executing scope, so one level deeper)\n// starts on its own depth's chain and never waits on its unresolved parent.\nasync function runNestedSavepointScope<T>(\n canonical: ExecSql,\n lockedExecSql: ExecSql,\n operation: () => Promise<T>,\n): Promise<T> {\n const depthAtEntry = transactionDepthByCanonicalExecSql.get(canonical) ?? 0;\n const chains =\n nestedScopeChainsByCanonicalExecSql.get(canonical) ??\n new Map<number, Promise<unknown>>();\n nestedScopeChainsByCanonicalExecSql.set(canonical, chains);\n const previous = chains.get(depthAtEntry) ?? Promise.resolve();\n let tracked: Promise<unknown> = Promise.resolve();\n const scope = previous\n .catch(() => undefined)\n .then(async () => {\n const depth = transactionDepthByCanonicalExecSql.get(canonical) ?? 0;\n transactionDepthByCanonicalExecSql.set(canonical, depth + 1);\n const savepoint = `runtime_transaction_sp_${depth}`;\n const discardNestedGuards = captureClientSQLiteCommitGuards(canonical);\n openTransactionSchemaMemoScope(canonical);\n let released = false;\n try {\n await lockedExecSql(`SAVEPOINT ${savepoint}`);\n const result = await operation();\n await lockedExecSql(`RELEASE SAVEPOINT ${savepoint}`);\n released = true;\n return result;\n } catch (error: unknown) {\n await lockedExecSql(`ROLLBACK TO SAVEPOINT ${savepoint}`).then(\n discardNestedGuards,\n () => undefined,\n );\n await lockedExecSql(`RELEASE SAVEPOINT ${savepoint}`).catch(\n () => undefined,\n );\n throw error;\n } finally {\n // The savepoint's rollback undid only the schema it first ensured.\n closeTransactionSchemaMemoScope(canonical, released);\n transactionDepthByCanonicalExecSql.set(canonical, depth);\n if (chains.get(depthAtEntry) === tracked) {\n chains.delete(depthAtEntry);\n }\n }\n });\n tracked = scope.catch(() => undefined);\n chains.set(depthAtEntry, tracked);\n return scope;\n}\n\nfunction createRuntimeForExecSql(\n execSql: ExecSql,\n): ClientSQLitePersistenceRuntime {\n let activeExecSql = execSql;\n const db = createClientSQLiteDatabase(() => activeExecSql);\n\n async function withActiveExecSql<T>(\n nextExecSql: ExecSql,\n operation: () => Promise<T> | T,\n ): Promise<T> {\n const previousExecSql = activeExecSql;\n activeExecSql = nextExecSql;\n\n try {\n return await operation();\n } finally {\n activeExecSql = previousExecSql;\n }\n }\n\n const runtime: ClientSQLitePersistenceRuntime = {\n db,\n execSql,\n runMutation(operation) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n withActiveExecSql(lockedExecSql, () => operation(db)),\n );\n },\n transaction(operation, config) {\n // A caller already inside an open transaction on this connection MUST\n // reach us through the transaction's locked executor (the runtime that\n // executor resolves to detects the open transaction below and joins it\n // as a savepoint scope). Re-entering through the canonical executor\n // queues here for full isolation — the contract every persistence\n // helper follows by passing its received locked executor down.\n const canonical = resolveCanonicalExecSql(execSql);\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n withActiveExecSql(lockedExecSql, async () => {\n if ((transactionDepthByCanonicalExecSql.get(canonical) ?? 0) > 0) {\n return runNestedSavepointScope(canonical, lockedExecSql, () =>\n operation(db),\n );\n }\n\n transactionDepthByCanonicalExecSql.set(canonical, 1);\n beginClientSQLiteCommitGuards(canonical);\n openTransactionSchemaMemoScope(canonical);\n let committed = false;\n try {\n const result = await db.transaction(operation, config);\n committed = true;\n return result;\n } catch (error: unknown) {\n rethrowClientSQLiteCommitGuardFailure(canonical);\n throw error;\n } finally {\n // A rollback forgets the ensures it undid (see sqlExec).\n closeTransactionSchemaMemoScope(canonical, committed);\n clearClientSQLiteCommitGuards(canonical);\n transactionDepthByCanonicalExecSql.delete(canonical);\n }\n }),\n );\n },\n guardedTransaction(operation, canCommit, config) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n withActiveExecSql(lockedExecSql, async () => {\n const canonical = resolveCanonicalExecSql(execSql);\n if ((transactionDepthByCanonicalExecSql.get(canonical) ?? 0) > 0) {\n throw new Error(\n \"guardedTransaction cannot nest inside an open transaction\",\n );\n }\n\n transactionDepthByCanonicalExecSql.set(canonical, 1);\n beginClientSQLiteCommitGuards(canonical);\n openTransactionSchemaMemoScope(canonical);\n let committed = false;\n try {\n await lockedExecSql(transactionBeginStatement(config));\n const result = await operation(db);\n if (!canCommit()) {\n await lockedExecSql(\"ROLLBACK\");\n return { committed: false, result: null };\n }\n // The guard passed in THIS synchronous slice and the COMMIT is\n // dispatched in the same slice: no JavaScript can run between\n // the two, so the decision cannot go stale before dispatch. (A\n // host tearing the connection down concurrently is resolved by\n // SQLite's own commit atomicity, not by anything client-side.)\n assertClientSQLiteCommitAllowed(lockedExecSql);\n const commit = lockedExecSql(\"COMMIT\");\n await commit;\n committed = true;\n return { committed: true, result };\n } catch (error: unknown) {\n await lockedExecSql(\"ROLLBACK\").catch(() => undefined);\n rethrowClientSQLiteCommitGuardFailure(canonical);\n throw error;\n } finally {\n closeTransactionSchemaMemoScope(canonical, committed);\n clearClientSQLiteCommitGuards(canonical);\n transactionDepthByCanonicalExecSql.delete(canonical);\n }\n }),\n );\n },\n };\n\n runtimeByExecSql.set(execSql, runtime);\n return runtime;\n}\n\nexport function getClientSQLitePersistenceRuntime(\n execSql: ExecSql,\n): ClientSQLitePersistenceRuntime {\n return runtimeByExecSql.get(execSql) ?? createRuntimeForExecSql(execSql);\n}\n\nexport function createClientSQLitePersistenceRuntime(\n client: ExecSqlClientLike,\n): ClientSQLitePersistenceRuntime {\n let execSql = execSqlByClient.get(client);\n if (!execSql) {\n execSql = createExecSql(client);\n execSqlByClient.set(client, execSql);\n }\n\n return getClientSQLitePersistenceRuntime(execSql);\n}\n"]}
|
package/package.json
CHANGED