@iworkforces/tracelattice 2.0.7 → 2.1.1
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/README.md +88 -64
- package/dist/ServerConfig.d.ts +1 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/cli.js +223 -254
- package/dist/cli.js.map +1 -1
- package/dist/config/ConfigLoader.d.ts +29 -26
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +40 -36
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts +7 -108
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/PersistenceBackend.js +1 -6
- package/dist/contracts/calibrator.d.ts +6 -6
- package/dist/contracts/calibrator.d.ts.map +1 -1
- package/dist/contracts/ids.d.ts +1 -8
- package/dist/contracts/ids.d.ts.map +1 -1
- package/dist/contracts/ids.js +2 -3
- package/dist/contracts/ids.js.map +1 -1
- package/dist/contracts/interfaces.d.ts +4 -6
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/persistence-work.d.ts +2 -3
- package/dist/contracts/persistence-work.d.ts.map +1 -1
- package/dist/contracts/summary.d.ts +0 -1
- package/dist/contracts/summary.d.ts.map +1 -1
- package/dist/core/HistoryManager.d.ts +12 -16
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +19 -40
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +22 -30
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/InputNormalizer.d.ts +7 -24
- package/dist/core/InputNormalizer.d.ts.map +1 -1
- package/dist/core/InputNormalizer.js +3 -9
- package/dist/core/InputNormalizer.js.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +3 -20
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +1 -4
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +4 -10
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWriter.d.ts.map +1 -1
- package/dist/core/PersistenceWriter.js +3 -12
- package/dist/core/PersistenceWriter.js.map +1 -1
- package/dist/core/SessionErrors.d.ts +0 -11
- package/dist/core/SessionErrors.d.ts.map +1 -1
- package/dist/core/SessionErrors.js +1 -14
- package/dist/core/SessionErrors.js.map +1 -1
- package/dist/core/SessionLock.d.ts +4 -5
- package/dist/core/SessionLock.d.ts.map +1 -1
- package/dist/core/SessionLock.js +5 -10
- package/dist/core/SessionLock.js.map +1 -1
- package/dist/core/SessionManager.d.ts +0 -2
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +3 -5
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/SessionResetCoordinator.d.ts +10 -7
- package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
- package/dist/core/SessionResetCoordinator.js +10 -28
- package/dist/core/SessionResetCoordinator.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +5 -5
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +4 -40
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtFormatter.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +10 -3
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +34 -38
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.js +5 -7
- package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
- package/dist/core/compression/CompressionService.d.ts +2 -1
- package/dist/core/compression/CompressionService.d.ts.map +1 -1
- package/dist/core/compression/CompressionService.js.map +1 -1
- package/dist/core/compression/DehydrationPolicy.d.ts.map +1 -1
- package/dist/core/compression/DehydrationPolicy.js.map +1 -1
- package/dist/core/compression/InMemorySummaryStore.d.ts +2 -1
- package/dist/core/compression/InMemorySummaryStore.d.ts.map +1 -1
- package/dist/core/compression/InMemorySummaryStore.js.map +1 -1
- package/dist/core/evaluator/Calibrator.d.ts +2 -2
- package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
- package/dist/core/evaluator/Calibrator.js +2 -5
- package/dist/core/evaluator/Calibrator.js.map +1 -1
- package/dist/core/evaluator/SignalComputer.d.ts +2 -1
- package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
- package/dist/core/evaluator/SignalComputer.js.map +1 -1
- package/dist/core/evaluator/internals.d.ts +1 -5
- package/dist/core/evaluator/internals.d.ts.map +1 -1
- package/dist/core/evaluator/internals.js +1 -3
- package/dist/core/evaluator/internals.js.map +1 -1
- package/dist/core/graph/Edge.d.ts +1 -1
- package/dist/core/graph/EdgeEmitter.d.ts +2 -4
- package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +2 -4
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/graph/GraphView.d.ts +13 -1
- package/dist/core/graph/GraphView.d.ts.map +1 -1
- package/dist/core/graph/GraphView.js +34 -0
- package/dist/core/graph/GraphView.js.map +1 -1
- package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
- package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
- package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
- package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
- package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +6 -6
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +16 -2
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/core/reasoning/strategies/totScoring.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/totScoring.js.map +1 -1
- package/dist/core/reasoning.d.ts +1 -3
- package/dist/core/reasoning.d.ts.map +1 -1
- package/dist/core/thought.d.ts +3 -2
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/errors.d.ts +4 -20
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -28
- package/dist/errors.js.map +1 -1
- package/dist/lib.d.ts +31 -24
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +55 -10
- package/dist/lib.js.map +1 -1
- package/dist/logger/NullLogger.d.ts +9 -11
- package/dist/logger/NullLogger.d.ts.map +1 -1
- package/dist/logger/NullLogger.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +3 -12
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +9 -61
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -2
- package/dist/persistence/FileSnapshotV2.js +2 -2
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/FileWriter.d.ts +1 -0
- package/dist/persistence/FileWriter.d.ts.map +1 -1
- package/dist/persistence/FileWriter.js +3 -3
- package/dist/persistence/FileWriter.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +5 -15
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +6 -40
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceCodec.js +1 -3
- package/dist/persistence/PersistenceCodec.js.map +1 -1
- package/dist/persistence/PersistenceErrors.d.ts +0 -6
- package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
- package/dist/persistence/PersistenceErrors.js +1 -9
- package/dist/persistence/PersistenceErrors.js.map +1 -1
- package/dist/persistence/PersistenceScope.d.ts.map +1 -1
- package/dist/persistence/PersistenceScope.js +2 -2
- package/dist/persistence/PersistenceScope.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +3 -10
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +2 -26
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
- package/dist/persistence/SqliteSchemaV2.js +3 -12
- package/dist/persistence/SqliteSchemaV2.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts +3 -12
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js +5 -8
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/pool/IConnectionPool.d.ts +3 -9
- package/dist/pool/IConnectionPool.d.ts.map +1 -1
- package/dist/registry/SkillRegistry.d.ts +1 -7
- package/dist/registry/SkillRegistry.d.ts.map +1 -1
- package/dist/registry/SkillRegistry.js +0 -15
- package/dist/registry/SkillRegistry.js.map +1 -1
- package/dist/registry/ToolRegistry.d.ts +1 -9
- package/dist/registry/ToolRegistry.d.ts.map +1 -1
- package/dist/registry/ToolRegistry.js +0 -21
- package/dist/registry/ToolRegistry.js.map +1 -1
- package/dist/schema.d.ts +2 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +3 -3
- package/dist/schema.js.map +1 -1
- package/dist/transport/BaseTransport.d.ts +0 -9
- package/dist/transport/BaseTransport.d.ts.map +1 -1
- package/dist/transport/BaseTransport.js +0 -11
- package/dist/transport/BaseTransport.js.map +1 -1
- package/dist/transport/HttpHelpers.d.ts +4 -1
- package/dist/transport/HttpHelpers.d.ts.map +1 -1
- package/dist/transport/HttpHelpers.js +61 -11
- package/dist/transport/HttpHelpers.js.map +1 -1
- package/dist/transport/HttpRequestLifecycle.d.ts +15 -1
- package/dist/transport/HttpRequestLifecycle.d.ts.map +1 -1
- package/dist/transport/HttpRequestLifecycle.js +66 -4
- package/dist/transport/HttpRequestLifecycle.js.map +1 -1
- package/dist/transport/HttpTransport.d.ts +2 -0
- package/dist/transport/HttpTransport.d.ts.map +1 -1
- package/dist/transport/HttpTransport.js +75 -38
- package/dist/transport/HttpTransport.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +5 -29
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +74 -116
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/dist/watchers/SkillWatcher.d.ts.map +1 -1
- package/dist/watchers/SkillWatcher.js +1 -1
- package/dist/watchers/SkillWatcher.js.map +1 -1
- package/package.json +2 -2
- package/dist/contracts/PersistenceBackend.js.map +0 -1
- package/dist/persistence/FileLegacyImport.d.ts +0 -2
- package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
- package/dist/persistence/FileLegacyImport.js +0 -183
- package/dist/persistence/FileLegacyImport.js.map +0 -1
- package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
- package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
- package/dist/persistence/SessionScopedPersistence.js +0 -9
- package/dist/persistence/SessionScopedPersistence.js.map +0 -1
- package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
- package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
- package/dist/persistence/SqliteLegacyImport.js +0 -136
- package/dist/persistence/SqliteLegacyImport.js.map +0 -1
- package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
- package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
- package/dist/persistence/SqliteLegacySchema.js +0 -72
- package/dist/persistence/SqliteLegacySchema.js.map +0 -1
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm } from "node:fs/promises";
|
|
2
|
-
import { basename, dirname, join } from "node:path";
|
|
3
|
-
import { GLOBAL_SESSION_ID, asSessionId } from "../contracts/ids.js";
|
|
4
|
-
import { PersistenceCompatibilityError, PersistenceCorruptionError, PersistenceLegacyAmbiguityError } from "../errors.js";
|
|
5
|
-
import { EdgeSchema } from "../schema.js";
|
|
6
|
-
import { SummarySchema } from "../core/compression/Summary.js";
|
|
7
|
-
import { parseEdge, parseSummary, parseThoughtData } from "./PersistenceCodec.js";
|
|
8
|
-
import { EMPTY_FILE_SNAPSHOT_V2, parseFileSnapshotV2, serializeFileSnapshotV2 } from "./FileSnapshotV2.js";
|
|
9
|
-
import { FileWriter, isFileNotFound } from "./FileWriter.js";
|
|
10
|
-
import { compareCodePoint, parsePersistenceBranchId } from "./PersistenceScope.js";
|
|
11
|
-
import * as __rspack_external_valibot from "valibot";
|
|
12
|
-
const LEGACY_NAMESPACES = [
|
|
13
|
-
'branches',
|
|
14
|
-
'edges',
|
|
15
|
-
'summaries'
|
|
16
|
-
];
|
|
17
|
-
async function destinationIsAbsent(path) {
|
|
18
|
-
try {
|
|
19
|
-
await lstat(path);
|
|
20
|
-
return false;
|
|
21
|
-
} catch (error) {
|
|
22
|
-
if (isFileNotFound(error)) return true;
|
|
23
|
-
throw error;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
async function parseJson(path) {
|
|
27
|
-
try {
|
|
28
|
-
return JSON.parse(await readFile(path, 'utf-8'));
|
|
29
|
-
} catch (error) {
|
|
30
|
-
if (error instanceof SyntaxError) throw new PersistenceCorruptionError(path, error);
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
async function parseThoughtArray(path) {
|
|
35
|
-
const raw = await parseJson(path);
|
|
36
|
-
try {
|
|
37
|
-
return __rspack_external_valibot.parse(__rspack_external_valibot.array(__rspack_external_valibot.unknown()), raw).map((thought)=>parseThoughtData(thought, path));
|
|
38
|
-
} catch (error) {
|
|
39
|
-
if (error instanceof PersistenceCompatibilityError) throw error;
|
|
40
|
-
throw new PersistenceCorruptionError(path, error);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
async function namespaceFiles(sourceDataDir, namespace) {
|
|
44
|
-
const directory = join(sourceDataDir, namespace);
|
|
45
|
-
try {
|
|
46
|
-
const entries = await readdir(directory, {
|
|
47
|
-
withFileTypes: true
|
|
48
|
-
});
|
|
49
|
-
for (const entry of entries)if (!entry.isFile() || !entry.name.endsWith('.json')) throw new PersistenceCompatibilityError(directory, `unknown legacy artifact '${entry.name}'`);
|
|
50
|
-
return entries.map((entry)=>join(directory, entry.name)).sort(compareCodePoint);
|
|
51
|
-
} catch (error) {
|
|
52
|
-
if (isFileNotFound(error)) return [];
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
async function validateLegacyLayout(sourceDataDir) {
|
|
57
|
-
const entries = await readdir(sourceDataDir, {
|
|
58
|
-
withFileTypes: true
|
|
59
|
-
});
|
|
60
|
-
const allowed = new Set([
|
|
61
|
-
'history.json',
|
|
62
|
-
...LEGACY_NAMESPACES
|
|
63
|
-
]);
|
|
64
|
-
for (const entry of entries){
|
|
65
|
-
if (!allowed.has(entry.name)) throw new PersistenceCompatibilityError(sourceDataDir, `unknown legacy artifact '${entry.name}'`);
|
|
66
|
-
if ('history.json' === entry.name ? !entry.isFile() : !entry.isDirectory()) throw new PersistenceCompatibilityError(sourceDataDir, `invalid legacy artifact '${entry.name}'`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function groupHistory(thoughts) {
|
|
70
|
-
const grouped = new Map();
|
|
71
|
-
for (const thought of thoughts){
|
|
72
|
-
const sessionId = thought.session_id ?? GLOBAL_SESSION_ID;
|
|
73
|
-
const history = grouped.get(sessionId) ?? [];
|
|
74
|
-
history.push(thought);
|
|
75
|
-
grouped.set(sessionId, history);
|
|
76
|
-
}
|
|
77
|
-
return [
|
|
78
|
-
...grouped
|
|
79
|
-
].map(([sessionId, sessionThoughts])=>({
|
|
80
|
-
sessionId,
|
|
81
|
-
thoughts: sessionThoughts
|
|
82
|
-
}));
|
|
83
|
-
}
|
|
84
|
-
async function loadLegacyHistory(sourceDataDir) {
|
|
85
|
-
const historyPath = join(sourceDataDir, 'history.json');
|
|
86
|
-
try {
|
|
87
|
-
return groupHistory(await parseThoughtArray(historyPath));
|
|
88
|
-
} catch (error) {
|
|
89
|
-
if (isFileNotFound(error)) return [];
|
|
90
|
-
throw error;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
async function loadLegacyBranches(sourceDataDir) {
|
|
94
|
-
const records = [];
|
|
95
|
-
for (const path of (await namespaceFiles(sourceDataDir, 'branches'))){
|
|
96
|
-
const branchId = parsePersistenceBranchId(basename(path, '.json'), path);
|
|
97
|
-
const thoughts = await parseThoughtArray(path);
|
|
98
|
-
if (0 === thoughts.length) throw new PersistenceLegacyAmbiguityError(path, 'empty branch has no inferable session');
|
|
99
|
-
const sessions = new Set(thoughts.map((thought)=>thought.session_id ?? GLOBAL_SESSION_ID));
|
|
100
|
-
if (1 !== sessions.size) throw new PersistenceLegacyAmbiguityError(path, 'branch thoughts resolve to multiple sessions');
|
|
101
|
-
const [sessionId] = sessions;
|
|
102
|
-
if (void 0 === sessionId) throw new PersistenceLegacyAmbiguityError(path, 'branch session is absent');
|
|
103
|
-
records.push({
|
|
104
|
-
sessionId,
|
|
105
|
-
branchId,
|
|
106
|
-
thoughts
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
return records;
|
|
110
|
-
}
|
|
111
|
-
async function loadLegacyEdges(sourceDataDir) {
|
|
112
|
-
const records = [];
|
|
113
|
-
for (const path of (await namespaceFiles(sourceDataDir, 'edges'))){
|
|
114
|
-
const sessionId = asSessionId(basename(path, '.json'));
|
|
115
|
-
try {
|
|
116
|
-
const edges = __rspack_external_valibot.parse(__rspack_external_valibot.array(EdgeSchema), await parseJson(path)).map(parseEdge);
|
|
117
|
-
if (edges.length > 0) records.push({
|
|
118
|
-
sessionId,
|
|
119
|
-
edges
|
|
120
|
-
});
|
|
121
|
-
} catch (error) {
|
|
122
|
-
if (error instanceof PersistenceCorruptionError) throw error;
|
|
123
|
-
throw new PersistenceCorruptionError(path, error);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return records;
|
|
127
|
-
}
|
|
128
|
-
async function loadLegacySummaries(sourceDataDir) {
|
|
129
|
-
const records = [];
|
|
130
|
-
for (const path of (await namespaceFiles(sourceDataDir, 'summaries'))){
|
|
131
|
-
const sessionId = asSessionId(basename(path, '.json'));
|
|
132
|
-
try {
|
|
133
|
-
const summaries = __rspack_external_valibot.parse(__rspack_external_valibot.array(SummarySchema), await parseJson(path)).map((summary)=>parseSummary(summary, path));
|
|
134
|
-
if (summaries.length > 0) records.push({
|
|
135
|
-
sessionId,
|
|
136
|
-
summaries
|
|
137
|
-
});
|
|
138
|
-
} catch (error) {
|
|
139
|
-
if (error instanceof PersistenceCorruptionError) throw error;
|
|
140
|
-
throw new PersistenceCorruptionError(path, error);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return records;
|
|
144
|
-
}
|
|
145
|
-
async function loadLegacySnapshot(sourceDataDir) {
|
|
146
|
-
await validateLegacyLayout(sourceDataDir);
|
|
147
|
-
return {
|
|
148
|
-
...EMPTY_FILE_SNAPSHOT_V2,
|
|
149
|
-
thoughts: await loadLegacyHistory(sourceDataDir),
|
|
150
|
-
branches: await loadLegacyBranches(sourceDataDir),
|
|
151
|
-
edges: await loadLegacyEdges(sourceDataDir),
|
|
152
|
-
summaries: await loadLegacySummaries(sourceDataDir)
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
async function importLegacyFileV1(sourceDataDir, destinationDataDir) {
|
|
156
|
-
if (!await destinationIsAbsent(destinationDataDir)) throw new PersistenceCompatibilityError(destinationDataDir, 'destination must be absent');
|
|
157
|
-
const snapshot = await loadLegacySnapshot(sourceDataDir);
|
|
158
|
-
await mkdir(dirname(destinationDataDir), {
|
|
159
|
-
recursive: true
|
|
160
|
-
});
|
|
161
|
-
const stagingDir = await mkdtemp(join(dirname(destinationDataDir), `.${basename(destinationDataDir)}.import-`));
|
|
162
|
-
const writer = new FileWriter(stagingDir);
|
|
163
|
-
try {
|
|
164
|
-
await writer.ready();
|
|
165
|
-
await writer.run(async (dataDir)=>{
|
|
166
|
-
const snapshotPath = join(dataDir, 'snapshot.json');
|
|
167
|
-
await writer.publish(snapshotPath, serializeFileSnapshotV2(snapshot, snapshotPath));
|
|
168
|
-
});
|
|
169
|
-
await writer.close();
|
|
170
|
-
parseFileSnapshotV2(await readFile(join(stagingDir, 'snapshot.json'), 'utf-8'), join(stagingDir, 'snapshot.json'));
|
|
171
|
-
await rename(stagingDir, destinationDataDir);
|
|
172
|
-
} catch (error) {
|
|
173
|
-
await writer.close();
|
|
174
|
-
await rm(stagingDir, {
|
|
175
|
-
recursive: true,
|
|
176
|
-
force: true
|
|
177
|
-
});
|
|
178
|
-
throw error;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
export { importLegacyFileV1 };
|
|
182
|
-
|
|
183
|
-
//# sourceMappingURL=FileLegacyImport.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/FileLegacyImport.js","sources":["../../src/persistence/FileLegacyImport.ts"],"sourcesContent":["import { lstat, mkdtemp, mkdir, readFile, readdir, rename, rm } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport * as v from 'valibot';\nimport { asSessionId, GLOBAL_SESSION_ID, type SessionId } from '../contracts/ids.js';\nimport {\n\tPersistenceCompatibilityError,\n\tPersistenceCorruptionError,\n\tPersistenceLegacyAmbiguityError,\n} from '../errors.js';\nimport { EdgeSchema } from '../schema.js';\nimport { SummarySchema } from '../core/compression/Summary.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { parseEdge, parseSummary, parseThoughtData } from './PersistenceCodec.js';\nimport {\n\tEMPTY_FILE_SNAPSHOT_V2,\n\tparseFileSnapshotV2,\n\tserializeFileSnapshotV2,\n} from './FileSnapshotV2.js';\nimport type {\n\tBranchRecordV2,\n\tEdgeSessionV2,\n\tFileSnapshotV2,\n\tSummarySessionV2,\n\tThoughtSessionV2,\n} from './FileSnapshotTypes.js';\nimport { FileWriter, isFileNotFound } from './FileWriter.js';\nimport { compareCodePoint, parsePersistenceBranchId } from './PersistenceScope.js';\n\nconst LEGACY_NAMESPACES = ['branches', 'edges', 'summaries'] as const;\n\nasync function destinationIsAbsent(path: string): Promise<boolean> {\n\ttry {\n\t\tawait lstat(path);\n\t\treturn false;\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return true;\n\t\tthrow error;\n\t}\n}\n\nasync function parseJson(path: string): Promise<unknown> {\n\ttry {\n\t\treturn JSON.parse(await readFile(path, 'utf-8'));\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError) throw new PersistenceCorruptionError(path, error);\n\t\tthrow error;\n\t}\n}\n\nasync function parseThoughtArray(path: string): Promise<ThoughtData[]> {\n\tconst raw = await parseJson(path);\n\ttry {\n\t\treturn v.parse(v.array(v.unknown()), raw).map((thought) => parseThoughtData(thought, path));\n\t} catch (error) {\n\t\tif (error instanceof PersistenceCompatibilityError) throw error;\n\t\tthrow new PersistenceCorruptionError(path, error);\n\t}\n}\n\nasync function namespaceFiles(sourceDataDir: string, namespace: string): Promise<string[]> {\n\tconst directory = join(sourceDataDir, namespace);\n\ttry {\n\t\tconst entries = await readdir(directory, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isFile() || !entry.name.endsWith('.json')) {\n\t\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t\tdirectory,\n\t\t\t\t\t`unknown legacy artifact '${entry.name}'`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn entries.map((entry) => join(directory, entry.name)).sort(compareCodePoint);\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return [];\n\t\tthrow error;\n\t}\n}\n\nasync function validateLegacyLayout(sourceDataDir: string): Promise<void> {\n\tconst entries = await readdir(sourceDataDir, { withFileTypes: true });\n\tconst allowed = new Set<string>(['history.json', ...LEGACY_NAMESPACES]);\n\tfor (const entry of entries) {\n\t\tif (!allowed.has(entry.name)) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tsourceDataDir,\n\t\t\t\t`unknown legacy artifact '${entry.name}'`\n\t\t\t);\n\t\t}\n\t\tif (entry.name === 'history.json' ? !entry.isFile() : !entry.isDirectory()) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tsourceDataDir,\n\t\t\t\t`invalid legacy artifact '${entry.name}'`\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction groupHistory(thoughts: readonly ThoughtData[]): ThoughtSessionV2[] {\n\tconst grouped = new Map<SessionId, ThoughtData[]>();\n\tfor (const thought of thoughts) {\n\t\tconst sessionId = thought.session_id ?? GLOBAL_SESSION_ID;\n\t\tconst history = grouped.get(sessionId) ?? [];\n\t\thistory.push(thought);\n\t\tgrouped.set(sessionId, history);\n\t}\n\treturn [...grouped].map(([sessionId, sessionThoughts]) => ({\n\t\tsessionId,\n\t\tthoughts: sessionThoughts,\n\t}));\n}\n\nasync function loadLegacyHistory(sourceDataDir: string): Promise<ThoughtSessionV2[]> {\n\tconst historyPath = join(sourceDataDir, 'history.json');\n\ttry {\n\t\treturn groupHistory(await parseThoughtArray(historyPath));\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return [];\n\t\tthrow error;\n\t}\n}\n\nasync function loadLegacyBranches(sourceDataDir: string): Promise<BranchRecordV2[]> {\n\tconst records: BranchRecordV2[] = [];\n\tfor (const path of await namespaceFiles(sourceDataDir, 'branches')) {\n\t\tconst branchId = parsePersistenceBranchId(basename(path, '.json'), path);\n\t\tconst thoughts = await parseThoughtArray(path);\n\t\tif (thoughts.length === 0) {\n\t\t\tthrow new PersistenceLegacyAmbiguityError(path, 'empty branch has no inferable session');\n\t\t}\n\t\tconst sessions = new Set(thoughts.map((thought) => thought.session_id ?? GLOBAL_SESSION_ID));\n\t\tif (sessions.size !== 1) {\n\t\t\tthrow new PersistenceLegacyAmbiguityError(\n\t\t\t\tpath,\n\t\t\t\t'branch thoughts resolve to multiple sessions'\n\t\t\t);\n\t\t}\n\t\tconst [sessionId] = sessions;\n\t\tif (sessionId === undefined) {\n\t\t\tthrow new PersistenceLegacyAmbiguityError(path, 'branch session is absent');\n\t\t}\n\t\trecords.push({ sessionId, branchId, thoughts });\n\t}\n\treturn records;\n}\n\nasync function loadLegacyEdges(sourceDataDir: string): Promise<EdgeSessionV2[]> {\n\tconst records: EdgeSessionV2[] = [];\n\tfor (const path of await namespaceFiles(sourceDataDir, 'edges')) {\n\t\tconst sessionId = asSessionId(basename(path, '.json'));\n\t\ttry {\n\t\t\tconst edges = v.parse(v.array(EdgeSchema), await parseJson(path)).map(parseEdge);\n\t\t\tif (edges.length > 0) records.push({ sessionId, edges });\n\t\t} catch (error) {\n\t\t\tif (error instanceof PersistenceCorruptionError) throw error;\n\t\t\tthrow new PersistenceCorruptionError(path, error);\n\t\t}\n\t}\n\treturn records;\n}\n\nasync function loadLegacySummaries(sourceDataDir: string): Promise<SummarySessionV2[]> {\n\tconst records: SummarySessionV2[] = [];\n\tfor (const path of await namespaceFiles(sourceDataDir, 'summaries')) {\n\t\tconst sessionId = asSessionId(basename(path, '.json'));\n\t\ttry {\n\t\t\tconst summaries = v\n\t\t\t\t.parse(v.array(SummarySchema), await parseJson(path))\n\t\t\t\t.map((summary) => parseSummary(summary, path));\n\t\t\tif (summaries.length > 0) records.push({ sessionId, summaries });\n\t\t} catch (error) {\n\t\t\tif (error instanceof PersistenceCorruptionError) throw error;\n\t\t\tthrow new PersistenceCorruptionError(path, error);\n\t\t}\n\t}\n\treturn records;\n}\n\nasync function loadLegacySnapshot(sourceDataDir: string): Promise<FileSnapshotV2> {\n\tawait validateLegacyLayout(sourceDataDir);\n\treturn {\n\t\t...EMPTY_FILE_SNAPSHOT_V2,\n\t\tthoughts: await loadLegacyHistory(sourceDataDir),\n\t\tbranches: await loadLegacyBranches(sourceDataDir),\n\t\tedges: await loadLegacyEdges(sourceDataDir),\n\t\tsummaries: await loadLegacySummaries(sourceDataDir),\n\t};\n}\n\nexport async function importLegacyFileV1(\n\tsourceDataDir: string,\n\tdestinationDataDir: string\n): Promise<void> {\n\tif (!(await destinationIsAbsent(destinationDataDir))) {\n\t\tthrow new PersistenceCompatibilityError(destinationDataDir, 'destination must be absent');\n\t}\n\tconst snapshot = await loadLegacySnapshot(sourceDataDir);\n\tawait mkdir(dirname(destinationDataDir), { recursive: true });\n\tconst stagingDir = await mkdtemp(\n\t\tjoin(dirname(destinationDataDir), `.${basename(destinationDataDir)}.import-`)\n\t);\n\tconst writer = new FileWriter(stagingDir);\n\ttry {\n\t\tawait writer.ready();\n\t\tawait writer.run(async (dataDir) => {\n\t\t\tconst snapshotPath = join(dataDir, 'snapshot.json');\n\t\t\tawait writer.publish(snapshotPath, serializeFileSnapshotV2(snapshot, snapshotPath));\n\t\t});\n\t\tawait writer.close();\n\t\tparseFileSnapshotV2(\n\t\t\tawait readFile(join(stagingDir, 'snapshot.json'), 'utf-8'),\n\t\t\tjoin(stagingDir, 'snapshot.json')\n\t\t);\n\t\tawait rename(stagingDir, destinationDataDir);\n\t} catch (error) {\n\t\tawait writer.close();\n\t\tawait rm(stagingDir, { recursive: true, force: true });\n\t\tthrow error;\n\t}\n}\n"],"names":["LEGACY_NAMESPACES","destinationIsAbsent","path","lstat","error","isFileNotFound","parseJson","JSON","readFile","SyntaxError","PersistenceCorruptionError","parseThoughtArray","raw","v","thought","parseThoughtData","PersistenceCompatibilityError","namespaceFiles","sourceDataDir","namespace","directory","join","entries","readdir","entry","compareCodePoint","validateLegacyLayout","allowed","Set","groupHistory","thoughts","grouped","Map","sessionId","GLOBAL_SESSION_ID","history","sessionThoughts","loadLegacyHistory","historyPath","loadLegacyBranches","records","branchId","parsePersistenceBranchId","basename","PersistenceLegacyAmbiguityError","sessions","undefined","loadLegacyEdges","asSessionId","edges","EdgeSchema","parseEdge","loadLegacySummaries","summaries","SummarySchema","summary","parseSummary","loadLegacySnapshot","EMPTY_FILE_SNAPSHOT_V2","importLegacyFileV1","destinationDataDir","snapshot","mkdir","dirname","stagingDir","mkdtemp","writer","FileWriter","dataDir","snapshotPath","serializeFileSnapshotV2","parseFileSnapshotV2","rename","rm"],"mappings":"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"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { PersistenceBackend, SessionScopedPersistenceBackend, SessionScopedPersistenceOperation } from '../contracts/PersistenceBackend.js';
|
|
2
|
-
/** Require the complete scoped capability without falling back to legacy global operations. */
|
|
3
|
-
export declare function requireSessionScopedPersistence(backend: PersistenceBackend, operation: SessionScopedPersistenceOperation): SessionScopedPersistenceBackend;
|
|
4
|
-
//# sourceMappingURL=SessionScopedPersistence.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SessionScopedPersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SessionScopedPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAClB,+BAA+B,EAC/B,iCAAiC,EACjC,MAAM,oCAAoC,CAAC;AAI5C,+FAA+F;AAC/F,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,iCAAiC,GAC1C,+BAA+B,CAKjC"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { supportsSessionScopedPersistence } from "../contracts/PersistenceBackend.js";
|
|
2
|
-
import { PersistenceCapabilityError } from "./PersistenceErrors.js";
|
|
3
|
-
function requireSessionScopedPersistence(backend, operation) {
|
|
4
|
-
if (!supportsSessionScopedPersistence(backend)) throw new PersistenceCapabilityError(operation);
|
|
5
|
-
return backend;
|
|
6
|
-
}
|
|
7
|
-
export { requireSessionScopedPersistence };
|
|
8
|
-
|
|
9
|
-
//# sourceMappingURL=SessionScopedPersistence.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/SessionScopedPersistence.js","sources":["../../src/persistence/SessionScopedPersistence.ts"],"sourcesContent":["import type {\n\tPersistenceBackend,\n\tSessionScopedPersistenceBackend,\n\tSessionScopedPersistenceOperation,\n} from '../contracts/PersistenceBackend.js';\nimport { supportsSessionScopedPersistence } from '../contracts/PersistenceBackend.js';\nimport { PersistenceCapabilityError } from './PersistenceErrors.js';\n\n/** Require the complete scoped capability without falling back to legacy global operations. */\nexport function requireSessionScopedPersistence(\n\tbackend: PersistenceBackend,\n\toperation: SessionScopedPersistenceOperation\n): SessionScopedPersistenceBackend {\n\tif (!supportsSessionScopedPersistence(backend)) {\n\t\tthrow new PersistenceCapabilityError(operation);\n\t}\n\treturn backend;\n}\n"],"names":["requireSessionScopedPersistence","backend","operation","supportsSessionScopedPersistence","PersistenceCapabilityError"],"mappings":";;AASO,SAASA,gCACfC,OAA2B,EAC3BC,SAA4C;IAE5C,IAAI,CAACC,iCAAiCF,UACrC,MAAM,IAAIG,2BAA2BF;IAEtC,OAAOD;AACR"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Imports an immutable SQLite v1 database into a separately published SQLite v2 destination.
|
|
3
|
-
*
|
|
4
|
-
* @param sourceDbPath - Existing frozen v1 source database opened read-only.
|
|
5
|
-
* @param destinationDbPath - Absent destination path atomically published after validation.
|
|
6
|
-
* @returns A promise that resolves after the validated v2 database is published.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* await importLegacySqliteV1('fixtures/legacy.db', 'output/history.db');
|
|
11
|
-
* ```
|
|
12
|
-
*/
|
|
13
|
-
export declare function importLegacySqliteV1(sourceDbPath: string, destinationDbPath: string): Promise<void>;
|
|
14
|
-
//# sourceMappingURL=SqliteLegacyImport.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SqliteLegacyImport.d.ts","sourceRoot":"","sources":["../../src/persistence/SqliteLegacyImport.ts"],"names":[],"mappings":"AA6KA;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACzC,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAaf"}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { link as promises_link, lstat, mkdir, mkdtemp, rm } from "node:fs/promises";
|
|
2
|
-
import { basename, dirname, join } from "node:path";
|
|
3
|
-
import { GLOBAL_SESSION_ID } from "../contracts/ids.js";
|
|
4
|
-
import { PersistenceCompatibilityError, PersistenceCorruptionError, PersistenceLegacyAmbiguityError } from "../errors.js";
|
|
5
|
-
import { parseFileSnapshotV2, serializeFileSnapshotV2 } from "./FileSnapshotV2.js";
|
|
6
|
-
import { isFileNotFound } from "./FileWriter.js";
|
|
7
|
-
import { validateSqliteV1Schema } from "./SqliteLegacySchema.js";
|
|
8
|
-
import { decodeEdgeRow, decodeSummaryRow, decodeThoughtRow, parseSqliteJson, stringField } from "./SqlitePayload.js";
|
|
9
|
-
import { parsePersistenceBranchId } from "./PersistenceScope.js";
|
|
10
|
-
import { writeSqliteSnapshot } from "./SqliteSnapshotWriter.js";
|
|
11
|
-
async function pathIsAbsent(path) {
|
|
12
|
-
try {
|
|
13
|
-
await lstat(path);
|
|
14
|
-
return false;
|
|
15
|
-
} catch (error) {
|
|
16
|
-
if (isFileNotFound(error)) return true;
|
|
17
|
-
throw error;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function groupBySession(values, sessionOf) {
|
|
21
|
-
const grouped = new Map();
|
|
22
|
-
for (const value of values){
|
|
23
|
-
const sessionId = sessionOf(value);
|
|
24
|
-
const sessionValues = grouped.get(sessionId) ?? [];
|
|
25
|
-
sessionValues.push(value);
|
|
26
|
-
grouped.set(sessionId, sessionValues);
|
|
27
|
-
}
|
|
28
|
-
return grouped;
|
|
29
|
-
}
|
|
30
|
-
function loadLegacyThoughts(database, sourcePath) {
|
|
31
|
-
const thoughts = database.prepare('SELECT data FROM thoughts ORDER BY id ASC').all().map((row, index)=>decodeThoughtRow(row, `${sourcePath}:thoughts:${index}`));
|
|
32
|
-
return [
|
|
33
|
-
...groupBySession(thoughts, (thought)=>thought.session_id ?? GLOBAL_SESSION_ID)
|
|
34
|
-
].map(([sessionId, sessionThoughts])=>({
|
|
35
|
-
sessionId,
|
|
36
|
-
thoughts: sessionThoughts
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
function decodeLegacyBranch(row, sourcePath) {
|
|
40
|
-
const branchId = parsePersistenceBranchId(stringField(row, 'branch_id', sourcePath), sourcePath);
|
|
41
|
-
const data = parseSqliteJson(stringField(row, 'data', sourcePath), sourcePath);
|
|
42
|
-
if (!Array.isArray(data)) throw new PersistenceCorruptionError(sourcePath, new TypeError('branch data is not an array'));
|
|
43
|
-
const thoughts = data.map((value, index)=>decodeThoughtRow({
|
|
44
|
-
data: JSON.stringify(value)
|
|
45
|
-
}, `${sourcePath}:thought:${index}`));
|
|
46
|
-
if (0 === thoughts.length) throw new PersistenceLegacyAmbiguityError(sourcePath, 'empty branch has no inferable session');
|
|
47
|
-
const sessions = new Set(thoughts.map((thought)=>thought.session_id ?? GLOBAL_SESSION_ID));
|
|
48
|
-
if (1 !== sessions.size) throw new PersistenceLegacyAmbiguityError(sourcePath, 'branch thoughts resolve to multiple sessions');
|
|
49
|
-
const sessionId = sessions.values().next().value;
|
|
50
|
-
if (void 0 === sessionId) throw new PersistenceLegacyAmbiguityError(sourcePath, 'branch session is absent');
|
|
51
|
-
return {
|
|
52
|
-
sessionId,
|
|
53
|
-
branchId,
|
|
54
|
-
thoughts
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function loadLegacyBranches(database, sourcePath, hasBranches) {
|
|
58
|
-
if (!hasBranches) return [];
|
|
59
|
-
return database.prepare('SELECT branch_id, data FROM branches ORDER BY branch_id ASC').all().map((row, index)=>decodeLegacyBranch(row, `${sourcePath}:branches:${index}`));
|
|
60
|
-
}
|
|
61
|
-
function loadLegacyEdges(database, sourcePath) {
|
|
62
|
-
const edges = database.prepare('SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges ORDER BY created_at ASC, id ASC').all().map((row, index)=>decodeEdgeRow(row, `${sourcePath}:edges:${index}`));
|
|
63
|
-
return [
|
|
64
|
-
...groupBySession(edges, (edge)=>edge.sessionId)
|
|
65
|
-
].map(([sessionId, sessionEdges])=>({
|
|
66
|
-
sessionId,
|
|
67
|
-
edges: sessionEdges
|
|
68
|
-
}));
|
|
69
|
-
}
|
|
70
|
-
function loadLegacySummaries(database, sourcePath) {
|
|
71
|
-
const summaries = database.prepare('SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries ORDER BY created_at ASC, id ASC').all().map((row, index)=>decodeSummaryRow(row, `${sourcePath}:summaries:${index}`));
|
|
72
|
-
return [
|
|
73
|
-
...groupBySession(summaries, (summary)=>summary.sessionId)
|
|
74
|
-
].map(([sessionId, sessionSummaries])=>({
|
|
75
|
-
sessionId,
|
|
76
|
-
summaries: sessionSummaries
|
|
77
|
-
}));
|
|
78
|
-
}
|
|
79
|
-
function loadLegacySnapshot(database, sourcePath) {
|
|
80
|
-
const hasBranches = validateSqliteV1Schema(database, sourcePath);
|
|
81
|
-
const snapshot = {
|
|
82
|
-
version: 2,
|
|
83
|
-
thoughts: loadLegacyThoughts(database, sourcePath),
|
|
84
|
-
branches: loadLegacyBranches(database, sourcePath, hasBranches),
|
|
85
|
-
edges: loadLegacyEdges(database, sourcePath),
|
|
86
|
-
summaries: loadLegacySummaries(database, sourcePath)
|
|
87
|
-
};
|
|
88
|
-
return parseFileSnapshotV2(serializeFileSnapshotV2(snapshot, sourcePath), sourcePath);
|
|
89
|
-
}
|
|
90
|
-
async function importWithDriver(sourceDbPath, destinationDbPath, Database) {
|
|
91
|
-
if (!await pathIsAbsent(destinationDbPath)) throw new PersistenceCompatibilityError(destinationDbPath, 'destination must be absent');
|
|
92
|
-
const source = new Database(sourceDbPath, {
|
|
93
|
-
readonly: true,
|
|
94
|
-
fileMustExist: true
|
|
95
|
-
});
|
|
96
|
-
let snapshot;
|
|
97
|
-
try {
|
|
98
|
-
snapshot = loadLegacySnapshot(source, sourceDbPath);
|
|
99
|
-
} finally{
|
|
100
|
-
source.close();
|
|
101
|
-
}
|
|
102
|
-
await mkdir(dirname(destinationDbPath), {
|
|
103
|
-
recursive: true
|
|
104
|
-
});
|
|
105
|
-
const stagingDir = await mkdtemp(join(dirname(destinationDbPath), `.${basename(destinationDbPath)}.import-`));
|
|
106
|
-
const stagedDbPath = join(stagingDir, basename(destinationDbPath));
|
|
107
|
-
let destination;
|
|
108
|
-
try {
|
|
109
|
-
destination = new Database(stagedDbPath);
|
|
110
|
-
writeSqliteSnapshot(destination, snapshot, stagedDbPath);
|
|
111
|
-
destination.close();
|
|
112
|
-
destination = void 0;
|
|
113
|
-
await promises_link(stagedDbPath, destinationDbPath);
|
|
114
|
-
} catch (error) {
|
|
115
|
-
destination?.close();
|
|
116
|
-
throw error;
|
|
117
|
-
} finally{
|
|
118
|
-
await rm(stagingDir, {
|
|
119
|
-
recursive: true,
|
|
120
|
-
force: true
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
async function importLegacySqliteV1(sourceDbPath, destinationDbPath) {
|
|
125
|
-
let Database;
|
|
126
|
-
try {
|
|
127
|
-
const module = await import("better-sqlite3");
|
|
128
|
-
Database = module.default;
|
|
129
|
-
} catch (error) {
|
|
130
|
-
throw new PersistenceCompatibilityError(sourceDbPath, "SQLite import requires the optional 'better-sqlite3' package", error);
|
|
131
|
-
}
|
|
132
|
-
await importWithDriver(sourceDbPath, destinationDbPath, Database);
|
|
133
|
-
}
|
|
134
|
-
export { importLegacySqliteV1 };
|
|
135
|
-
|
|
136
|
-
//# sourceMappingURL=SqliteLegacyImport.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/SqliteLegacyImport.js","sources":["../../src/persistence/SqliteLegacyImport.ts"],"sourcesContent":["import { lstat, link, mkdir, mkdtemp, rm } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { GLOBAL_SESSION_ID, type SessionId } from '../contracts/ids.js';\nimport {\n\tPersistenceCompatibilityError,\n\tPersistenceCorruptionError,\n\tPersistenceLegacyAmbiguityError,\n} from '../errors.js';\nimport { parseFileSnapshotV2, serializeFileSnapshotV2 } from './FileSnapshotV2.js';\nimport type {\n\tBranchRecordV2,\n\tEdgeSessionV2,\n\tFileSnapshotV2,\n\tSummarySessionV2,\n\tThoughtSessionV2,\n} from './FileSnapshotTypes.js';\nimport { isFileNotFound } from './FileWriter.js';\nimport type { SqliteDatabase, SqliteDatabaseConstructor } from './SqliteDriver.js';\nimport { validateSqliteV1Schema } from './SqliteLegacySchema.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tparseSqliteJson,\n\tstringField,\n} from './SqlitePayload.js';\nimport { parsePersistenceBranchId } from './PersistenceScope.js';\nimport { writeSqliteSnapshot } from './SqliteSnapshotWriter.js';\n\nasync function pathIsAbsent(path: string): Promise<boolean> {\n\ttry {\n\t\tawait lstat(path);\n\t\treturn false;\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return true;\n\t\tthrow error;\n\t}\n}\n\nfunction groupBySession<T>(\n\tvalues: readonly T[],\n\tsessionOf: (value: T) => SessionId\n): Map<SessionId, T[]> {\n\tconst grouped = new Map<SessionId, T[]>();\n\tfor (const value of values) {\n\t\tconst sessionId = sessionOf(value);\n\t\tconst sessionValues = grouped.get(sessionId) ?? [];\n\t\tsessionValues.push(value);\n\t\tgrouped.set(sessionId, sessionValues);\n\t}\n\treturn grouped;\n}\n\nfunction loadLegacyThoughts(database: SqliteDatabase, sourcePath: string): ThoughtSessionV2[] {\n\tconst thoughts = database\n\t\t.prepare('SELECT data FROM thoughts ORDER BY id ASC')\n\t\t.all()\n\t\t.map((row, index) => decodeThoughtRow(row, `${sourcePath}:thoughts:${index}`));\n\treturn [...groupBySession(thoughts, (thought) => thought.session_id ?? GLOBAL_SESSION_ID)].map(\n\t\t([sessionId, sessionThoughts]) => ({ sessionId, thoughts: sessionThoughts })\n\t);\n}\n\nfunction decodeLegacyBranch(row: unknown, sourcePath: string): BranchRecordV2 {\n\tconst branchId = parsePersistenceBranchId(stringField(row, 'branch_id', sourcePath), sourcePath);\n\tconst data = parseSqliteJson(stringField(row, 'data', sourcePath), sourcePath);\n\tif (!Array.isArray(data)) {\n\t\tthrow new PersistenceCorruptionError(sourcePath, new TypeError('branch data is not an array'));\n\t}\n\tconst thoughts = data.map((value, index) =>\n\t\tdecodeThoughtRow({ data: JSON.stringify(value) }, `${sourcePath}:thought:${index}`)\n\t);\n\tif (thoughts.length === 0) {\n\t\tthrow new PersistenceLegacyAmbiguityError(sourcePath, 'empty branch has no inferable session');\n\t}\n\tconst sessions = new Set(thoughts.map((thought) => thought.session_id ?? GLOBAL_SESSION_ID));\n\tif (sessions.size !== 1) {\n\t\tthrow new PersistenceLegacyAmbiguityError(\n\t\t\tsourcePath,\n\t\t\t'branch thoughts resolve to multiple sessions'\n\t\t);\n\t}\n\tconst sessionId = sessions.values().next().value;\n\tif (sessionId === undefined) {\n\t\tthrow new PersistenceLegacyAmbiguityError(sourcePath, 'branch session is absent');\n\t}\n\treturn { sessionId, branchId, thoughts };\n}\n\nfunction loadLegacyBranches(\n\tdatabase: SqliteDatabase,\n\tsourcePath: string,\n\thasBranches: boolean\n): BranchRecordV2[] {\n\tif (!hasBranches) return [];\n\treturn database\n\t\t.prepare('SELECT branch_id, data FROM branches ORDER BY branch_id ASC')\n\t\t.all()\n\t\t.map((row, index) => decodeLegacyBranch(row, `${sourcePath}:branches:${index}`));\n}\n\nfunction loadLegacyEdges(database: SqliteDatabase, sourcePath: string): EdgeSessionV2[] {\n\tconst edges = database\n\t\t.prepare(\n\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges ORDER BY created_at ASC, id ASC'\n\t\t)\n\t\t.all()\n\t\t.map((row, index) => decodeEdgeRow(row, `${sourcePath}:edges:${index}`));\n\treturn [...groupBySession(edges, (edge) => edge.sessionId)].map(([sessionId, sessionEdges]) => ({\n\t\tsessionId,\n\t\tedges: sessionEdges,\n\t}));\n}\n\nfunction loadLegacySummaries(database: SqliteDatabase, sourcePath: string): SummarySessionV2[] {\n\tconst summaries = database\n\t\t.prepare(\n\t\t\t'SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries ORDER BY created_at ASC, id ASC'\n\t\t)\n\t\t.all()\n\t\t.map((row, index) => decodeSummaryRow(row, `${sourcePath}:summaries:${index}`));\n\treturn [...groupBySession(summaries, (summary) => summary.sessionId)].map(\n\t\t([sessionId, sessionSummaries]) => ({ sessionId, summaries: sessionSummaries })\n\t);\n}\n\nfunction loadLegacySnapshot(database: SqliteDatabase, sourcePath: string): FileSnapshotV2 {\n\tconst hasBranches = validateSqliteV1Schema(database, sourcePath);\n\tconst snapshot: FileSnapshotV2 = {\n\t\tversion: 2,\n\t\tthoughts: loadLegacyThoughts(database, sourcePath),\n\t\tbranches: loadLegacyBranches(database, sourcePath, hasBranches),\n\t\tedges: loadLegacyEdges(database, sourcePath),\n\t\tsummaries: loadLegacySummaries(database, sourcePath),\n\t};\n\treturn parseFileSnapshotV2(serializeFileSnapshotV2(snapshot, sourcePath), sourcePath);\n}\n\nasync function importWithDriver(\n\tsourceDbPath: string,\n\tdestinationDbPath: string,\n\tDatabase: SqliteDatabaseConstructor\n): Promise<void> {\n\tif (!(await pathIsAbsent(destinationDbPath))) {\n\t\tthrow new PersistenceCompatibilityError(destinationDbPath, 'destination must be absent');\n\t}\n\tconst source = new Database(sourceDbPath, { readonly: true, fileMustExist: true });\n\tlet snapshot: FileSnapshotV2;\n\ttry {\n\t\tsnapshot = loadLegacySnapshot(source, sourceDbPath);\n\t} finally {\n\t\tsource.close();\n\t}\n\tawait mkdir(dirname(destinationDbPath), { recursive: true });\n\tconst stagingDir = await mkdtemp(\n\t\tjoin(dirname(destinationDbPath), `.${basename(destinationDbPath)}.import-`)\n\t);\n\tconst stagedDbPath = join(stagingDir, basename(destinationDbPath));\n\tlet destination: SqliteDatabase | undefined;\n\ttry {\n\t\tdestination = new Database(stagedDbPath);\n\t\twriteSqliteSnapshot(destination, snapshot, stagedDbPath);\n\t\tdestination.close();\n\t\tdestination = undefined;\n\t\tawait link(stagedDbPath, destinationDbPath);\n\t} catch (error) {\n\t\tdestination?.close();\n\t\tthrow error;\n\t} finally {\n\t\tawait rm(stagingDir, { recursive: true, force: true });\n\t}\n}\n\n/**\n * Imports an immutable SQLite v1 database into a separately published SQLite v2 destination.\n *\n * @param sourceDbPath - Existing frozen v1 source database opened read-only.\n * @param destinationDbPath - Absent destination path atomically published after validation.\n * @returns A promise that resolves after the validated v2 database is published.\n *\n * @example\n * ```ts\n * await importLegacySqliteV1('fixtures/legacy.db', 'output/history.db');\n * ```\n */\nexport async function importLegacySqliteV1(\n\tsourceDbPath: string,\n\tdestinationDbPath: string\n): Promise<void> {\n\tlet Database: SqliteDatabaseConstructor;\n\ttry {\n\t\tconst module = await import('better-sqlite3');\n\t\tDatabase = module.default;\n\t} catch (error) {\n\t\tthrow new PersistenceCompatibilityError(\n\t\t\tsourceDbPath,\n\t\t\t\"SQLite import requires the optional 'better-sqlite3' package\",\n\t\t\terror\n\t\t);\n\t}\n\tawait importWithDriver(sourceDbPath, destinationDbPath, Database);\n}\n"],"names":["pathIsAbsent","path","lstat","error","isFileNotFound","groupBySession","values","sessionOf","grouped","Map","value","sessionId","sessionValues","loadLegacyThoughts","database","sourcePath","thoughts","row","index","decodeThoughtRow","thought","GLOBAL_SESSION_ID","sessionThoughts","decodeLegacyBranch","branchId","parsePersistenceBranchId","stringField","data","parseSqliteJson","Array","PersistenceCorruptionError","TypeError","JSON","PersistenceLegacyAmbiguityError","sessions","Set","undefined","loadLegacyBranches","hasBranches","loadLegacyEdges","edges","decodeEdgeRow","edge","sessionEdges","loadLegacySummaries","summaries","decodeSummaryRow","summary","sessionSummaries","loadLegacySnapshot","validateSqliteV1Schema","snapshot","parseFileSnapshotV2","serializeFileSnapshotV2","importWithDriver","sourceDbPath","destinationDbPath","Database","PersistenceCompatibilityError","source","mkdir","dirname","stagingDir","mkdtemp","join","basename","stagedDbPath","destination","writeSqliteSnapshot","link","rm","importLegacySqliteV1","module"],"mappings":"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"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { SqliteDatabase } from './SqliteDriver.js';
|
|
2
|
-
/**
|
|
3
|
-
* Validates the frozen, unversioned SQLite v1 schema without mutating it.
|
|
4
|
-
*
|
|
5
|
-
* @param database - Read-only source database.
|
|
6
|
-
* @param sourcePath - Source name used by typed compatibility errors.
|
|
7
|
-
* @returns Whether the optional legacy branches table is present.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* const hasBranches = validateSqliteV1Schema(database, 'legacy.db');
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
export declare function validateSqliteV1Schema(database: SqliteDatabase, sourcePath: string): boolean;
|
|
15
|
-
//# sourceMappingURL=SqliteLegacySchema.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SqliteLegacySchema.d.ts","sourceRoot":"","sources":["../../src/persistence/SqliteLegacySchema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAoDxD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAuB5F"}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { PersistenceCompatibilityError } from "../errors.js";
|
|
2
|
-
const LEGACY_TABLES = new Map([
|
|
3
|
-
[
|
|
4
|
-
'thoughts',
|
|
5
|
-
"CREATE TABLE thoughts (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT NOT NULL, created_at INTEGER DEFAULT (strftime('%s', 'now')))"
|
|
6
|
-
],
|
|
7
|
-
[
|
|
8
|
-
'branches',
|
|
9
|
-
"CREATE TABLE branches (branch_id TEXT PRIMARY KEY, data TEXT NOT NULL, updated_at INTEGER DEFAULT (strftime('%s', 'now')))"
|
|
10
|
-
],
|
|
11
|
-
[
|
|
12
|
-
'edges',
|
|
13
|
-
'CREATE TABLE edges (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, from_id TEXT NOT NULL, to_id TEXT NOT NULL, kind TEXT NOT NULL, created_at INTEGER NOT NULL, metadata TEXT)'
|
|
14
|
-
],
|
|
15
|
-
[
|
|
16
|
-
'summaries',
|
|
17
|
-
'CREATE TABLE summaries (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, branch_id TEXT, root_thought_id TEXT NOT NULL, covered_ids TEXT NOT NULL, covered_range_start INTEGER NOT NULL, covered_range_end INTEGER NOT NULL, topics TEXT NOT NULL, aggregate_confidence REAL NOT NULL, created_at INTEGER NOT NULL, meta TEXT)'
|
|
18
|
-
]
|
|
19
|
-
]);
|
|
20
|
-
const LEGACY_INDEXES = new Map([
|
|
21
|
-
[
|
|
22
|
-
'idx_thoughts_created_at',
|
|
23
|
-
'CREATE INDEX idx_thoughts_created_at ON thoughts(created_at)'
|
|
24
|
-
],
|
|
25
|
-
[
|
|
26
|
-
'idx_edges_session',
|
|
27
|
-
'CREATE INDEX idx_edges_session ON edges(session_id)'
|
|
28
|
-
],
|
|
29
|
-
[
|
|
30
|
-
'idx_edges_from',
|
|
31
|
-
'CREATE INDEX idx_edges_from ON edges(session_id, from_id)'
|
|
32
|
-
],
|
|
33
|
-
[
|
|
34
|
-
'idx_edges_to',
|
|
35
|
-
'CREATE INDEX idx_edges_to ON edges(session_id, to_id)'
|
|
36
|
-
],
|
|
37
|
-
[
|
|
38
|
-
'idx_summaries_session',
|
|
39
|
-
'CREATE INDEX idx_summaries_session ON summaries(session_id)'
|
|
40
|
-
]
|
|
41
|
-
]);
|
|
42
|
-
function normalizeSql(sql) {
|
|
43
|
-
return sql.replace(/\s+/g, ' ').replace(/;$/, '').trim().toLowerCase();
|
|
44
|
-
}
|
|
45
|
-
function readObject(value, sourcePath) {
|
|
46
|
-
if ('object' != typeof value || null === value) throw new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master row');
|
|
47
|
-
const type = 'type' in value ? value.type : void 0;
|
|
48
|
-
const name = 'name' in value ? value.name : void 0;
|
|
49
|
-
const sql = 'sql' in value ? value.sql : void 0;
|
|
50
|
-
if ('string' != typeof type || 'string' != typeof name || 'string' != typeof sql) throw new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master fields');
|
|
51
|
-
return {
|
|
52
|
-
type,
|
|
53
|
-
name,
|
|
54
|
-
sql
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function validateSqliteV1Schema(database, sourcePath) {
|
|
58
|
-
const objects = database.prepare("SELECT type, name, sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY type, name").all().map((row)=>readObject(row, sourcePath));
|
|
59
|
-
const hasBranches = objects.some(({ type, name })=>'table' === type && 'branches' === name);
|
|
60
|
-
const expected = new Map();
|
|
61
|
-
for (const [name, sql] of LEGACY_TABLES)if ('branches' !== name || hasBranches) expected.set(`table:${name}`, normalizeSql(sql));
|
|
62
|
-
for (const [name, sql] of LEGACY_INDEXES)expected.set(`index:${name}`, normalizeSql(sql));
|
|
63
|
-
if (objects.length !== expected.size) throw new PersistenceCompatibilityError(sourcePath, 'SQLite v1 object set does not match');
|
|
64
|
-
for (const object of objects){
|
|
65
|
-
const expectedSql = expected.get(`${object.type}:${object.name}`);
|
|
66
|
-
if (void 0 === expectedSql || normalizeSql(object.sql) !== expectedSql) throw new PersistenceCompatibilityError(sourcePath, `SQLite v1 drift at '${object.name}'`);
|
|
67
|
-
}
|
|
68
|
-
return hasBranches;
|
|
69
|
-
}
|
|
70
|
-
export { validateSqliteV1Schema };
|
|
71
|
-
|
|
72
|
-
//# sourceMappingURL=SqliteLegacySchema.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/SqliteLegacySchema.js","sources":["../../src/persistence/SqliteLegacySchema.ts"],"sourcesContent":["import { PersistenceCompatibilityError } from '../errors.js';\nimport type { SqliteDatabase } from './SqliteDriver.js';\n\ntype LegacySchemaObject = {\n\treadonly type: string;\n\treadonly name: string;\n\treadonly sql: string;\n};\n\nconst LEGACY_TABLES = new Map<string, string>([\n\t[\n\t\t'thoughts',\n\t\t\"CREATE TABLE thoughts (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT NOT NULL, created_at INTEGER DEFAULT (strftime('%s', 'now')))\",\n\t],\n\t[\n\t\t'branches',\n\t\t\"CREATE TABLE branches (branch_id TEXT PRIMARY KEY, data TEXT NOT NULL, updated_at INTEGER DEFAULT (strftime('%s', 'now')))\",\n\t],\n\t[\n\t\t'edges',\n\t\t'CREATE TABLE edges (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, from_id TEXT NOT NULL, to_id TEXT NOT NULL, kind TEXT NOT NULL, created_at INTEGER NOT NULL, metadata TEXT)',\n\t],\n\t[\n\t\t'summaries',\n\t\t'CREATE TABLE summaries (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, branch_id TEXT, root_thought_id TEXT NOT NULL, covered_ids TEXT NOT NULL, covered_range_start INTEGER NOT NULL, covered_range_end INTEGER NOT NULL, topics TEXT NOT NULL, aggregate_confidence REAL NOT NULL, created_at INTEGER NOT NULL, meta TEXT)',\n\t],\n]);\n\nconst LEGACY_INDEXES = new Map<string, string>([\n\t['idx_thoughts_created_at', 'CREATE INDEX idx_thoughts_created_at ON thoughts(created_at)'],\n\t['idx_edges_session', 'CREATE INDEX idx_edges_session ON edges(session_id)'],\n\t['idx_edges_from', 'CREATE INDEX idx_edges_from ON edges(session_id, from_id)'],\n\t['idx_edges_to', 'CREATE INDEX idx_edges_to ON edges(session_id, to_id)'],\n\t['idx_summaries_session', 'CREATE INDEX idx_summaries_session ON summaries(session_id)'],\n]);\n\nfunction normalizeSql(sql: string): string {\n\treturn sql.replace(/\\s+/g, ' ').replace(/;$/, '').trim().toLowerCase();\n}\n\nfunction readObject(value: unknown, sourcePath: string): LegacySchemaObject {\n\tif (typeof value !== 'object' || value === null) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master row');\n\t}\n\tconst type = 'type' in value ? value.type : undefined;\n\tconst name = 'name' in value ? value.name : undefined;\n\tconst sql = 'sql' in value ? value.sql : undefined;\n\tif (typeof type !== 'string' || typeof name !== 'string' || typeof sql !== 'string') {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master fields');\n\t}\n\treturn { type, name, sql };\n}\n\n/**\n * Validates the frozen, unversioned SQLite v1 schema without mutating it.\n *\n * @param database - Read-only source database.\n * @param sourcePath - Source name used by typed compatibility errors.\n * @returns Whether the optional legacy branches table is present.\n *\n * @example\n * ```ts\n * const hasBranches = validateSqliteV1Schema(database, 'legacy.db');\n * ```\n */\nexport function validateSqliteV1Schema(database: SqliteDatabase, sourcePath: string): boolean {\n\tconst objects = database\n\t\t.prepare(\n\t\t\t\"SELECT type, name, sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY type, name\"\n\t\t)\n\t\t.all()\n\t\t.map((row) => readObject(row, sourcePath));\n\tconst hasBranches = objects.some(({ type, name }) => type === 'table' && name === 'branches');\n\tconst expected = new Map<string, string>();\n\tfor (const [name, sql] of LEGACY_TABLES) {\n\t\tif (name !== 'branches' || hasBranches) expected.set(`table:${name}`, normalizeSql(sql));\n\t}\n\tfor (const [name, sql] of LEGACY_INDEXES) expected.set(`index:${name}`, normalizeSql(sql));\n\tif (objects.length !== expected.size) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'SQLite v1 object set does not match');\n\t}\n\tfor (const object of objects) {\n\t\tconst expectedSql = expected.get(`${object.type}:${object.name}`);\n\t\tif (expectedSql === undefined || normalizeSql(object.sql) !== expectedSql) {\n\t\t\tthrow new PersistenceCompatibilityError(sourcePath, `SQLite v1 drift at '${object.name}'`);\n\t\t}\n\t}\n\treturn hasBranches;\n}\n"],"names":["LEGACY_TABLES","Map","LEGACY_INDEXES","normalizeSql","sql","readObject","value","sourcePath","PersistenceCompatibilityError","type","undefined","name","validateSqliteV1Schema","database","objects","row","hasBranches","expected","object","expectedSql"],"mappings":";AASA,MAAMA,gBAAgB,IAAIC,IAAoB;IAC7C;QACC;QACA;KACA;IACD;QACC;QACA;KACA;IACD;QACC;QACA;KACA;IACD;QACC;QACA;KACA;CACD;AAED,MAAMC,iBAAiB,IAAID,IAAoB;IAC9C;QAAC;QAA2B;KAA+D;IAC3F;QAAC;QAAqB;KAAsD;IAC5E;QAAC;QAAkB;KAA4D;IAC/E;QAAC;QAAgB;KAAwD;IACzE;QAAC;QAAyB;KAA8D;CACxF;AAED,SAASE,aAAaC,GAAW;IAChC,OAAOA,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,MAAM,IAAI,IAAI,GAAG,WAAW;AACrE;AAEA,SAASC,WAAWC,KAAc,EAAEC,UAAkB;IACrD,IAAI,AAAiB,YAAjB,OAAOD,SAAsBA,AAAU,SAAVA,OAChC,MAAM,IAAIE,8BAA8BD,YAAY;IAErD,MAAME,OAAO,UAAUH,QAAQA,MAAM,IAAI,GAAGI;IAC5C,MAAMC,OAAO,UAAUL,QAAQA,MAAM,IAAI,GAAGI;IAC5C,MAAMN,MAAM,SAASE,QAAQA,MAAM,GAAG,GAAGI;IACzC,IAAI,AAAgB,YAAhB,OAAOD,QAAqB,AAAgB,YAAhB,OAAOE,QAAqB,AAAe,YAAf,OAAOP,KAClE,MAAM,IAAII,8BAA8BD,YAAY;IAErD,OAAO;QAAEE;QAAME;QAAMP;IAAI;AAC1B;AAcO,SAASQ,uBAAuBC,QAAwB,EAAEN,UAAkB;IAClF,MAAMO,UAAUD,SACd,OAAO,CACP,gGAEA,GAAG,GACH,GAAG,CAAC,CAACE,MAAQV,WAAWU,KAAKR;IAC/B,MAAMS,cAAcF,QAAQ,IAAI,CAAC,CAAC,EAAEL,IAAI,EAAEE,IAAI,EAAE,GAAKF,AAAS,YAATA,QAAoBE,AAAS,eAATA;IACzE,MAAMM,WAAW,IAAIhB;IACrB,KAAK,MAAM,CAACU,MAAMP,IAAI,IAAIJ,cACzB,IAAIW,AAAS,eAATA,QAAuBK,aAAaC,SAAS,GAAG,CAAC,CAAC,MAAM,EAAEN,MAAM,EAAER,aAAaC;IAEpF,KAAK,MAAM,CAACO,MAAMP,IAAI,IAAIF,eAAgBe,SAAS,GAAG,CAAC,CAAC,MAAM,EAAEN,MAAM,EAAER,aAAaC;IACrF,IAAIU,QAAQ,MAAM,KAAKG,SAAS,IAAI,EACnC,MAAM,IAAIT,8BAA8BD,YAAY;IAErD,KAAK,MAAMW,UAAUJ,QAAS;QAC7B,MAAMK,cAAcF,SAAS,GAAG,CAAC,GAAGC,OAAO,IAAI,CAAC,CAAC,EAAEA,OAAO,IAAI,EAAE;QAChE,IAAIC,AAAgBT,WAAhBS,eAA6BhB,aAAae,OAAO,GAAG,MAAMC,aAC7D,MAAM,IAAIX,8BAA8BD,YAAY,CAAC,oBAAoB,EAAEW,OAAO,IAAI,CAAC,CAAC,CAAC;IAE3F;IACA,OAAOF;AACR"}
|