wiki-graph-core 0.4.0 → 0.4.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/data/help/commands/library-predicate.jinja +2 -2
- package/data/help/commands/library.jinja +12 -10
- package/data/help/commands/predicate.jinja +1 -1
- package/data/help/topics/library.jinja +8 -5
- package/data/help/topics/uri.jinja +2 -0
- package/dist/gc.cjs.map +1 -1
- package/dist/index.cjs +114 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/library/index.d.ts +2 -2
- package/dist/library/membership.js +18 -5
- package/dist/library/membership.js.map +1 -1
- package/dist/library/query.d.ts +4 -2
- package/dist/library/query.js +44 -0
- package/dist/library/query.js.map +1 -1
- package/dist/library/registry.d.ts +2 -1
- package/dist/library/registry.js +10 -0
- package/dist/library/registry.js.map +1 -1
- package/dist/maintenance/upgrade.js +15 -19
- package/dist/maintenance/upgrade.js.map +1 -1
- package/dist/retrieval/query/archive-view/helper/sort.js +1 -1
- package/dist/retrieval/query/archive-view/helper/sort.js.map +1 -1
- package/dist/storage/schema-upgrade/index.d.ts +7 -2
- package/dist/storage/schema-upgrade/index.js +26 -14
- package/dist/storage/schema-upgrade/index.js.map +1 -1
- package/dist/worker.cjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/storage/schema-upgrade/index.ts"],"sourcesContent":["import { randomUUID } from \"crypto\";\nimport { mkdtemp, rename, rm, stat, writeFile } from \"fs/promises\";\nimport { tmpdir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\n\nimport { Database } from \"../../document/database.js\";\nimport { ensureChapterKeys } from \"../../document/chapter/toc.js\";\nimport type { MutableTocFile } from \"../../document/chapter/tree.js\";\nimport { ensureWikiGraphHomeSchemaCurrent } from \"../../document/home-schema-upgrade.js\";\nimport {\n resolveWikiGraphHomeDirectoryPath,\n resolveWikiGraphStagingDirectoryPath,\n} from \"../../runtime/common/wiki-graph/dir.js\";\nimport {\n SEARCH_INDEX_DATABASE_PATH,\n WIKG_MANIFEST_PATH,\n} from \"../wikg/archive/constants.js\";\nimport { parseWikgManifest } from \"../wikg/archive/manifest.js\";\nimport { normalizeArchivePath } from \"../wikg/archive/paths.js\";\nimport {\n openIndexedArchive,\n readArchiveEntryText,\n} from \"../wikg/archive/zip.js\";\nimport { writeWikgArchiveWithOverlays } from \"../wikg/archive/write.js\";\nimport { createArchiveKey } from \"../wikg/wikg-coordinator/archive-key.js\";\nimport { tocFileSchema, type TocFile } from \"../../text/source/toc.js\";\n\nexport {\n ensureWikiGraphHomeSchemaCurrent,\n readWikiGraphHomeSchemaVersion,\n} from \"../../document/home-schema-upgrade.js\";\n\nexport const CURRENT_ARCHIVE_SCHEMA_VERSION = 2;\nconst LOCK_STALE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport async function ensureWikiGraphArchiveSchemaCurrent(\n archivePath: string,\n): Promise<void> {\n const schemaVersion = await readWikiGraphArchiveSchemaVersion(archivePath);\n\n if (schemaVersion > CURRENT_ARCHIVE_SCHEMA_VERSION) {\n throw new Error(\n `Unsupported Wiki Graph archive schema version: ${schemaVersion}.`,\n );\n }\n if (schemaVersion < CURRENT_ARCHIVE_SCHEMA_VERSION) {\n throw new Error(\n `This Wiki Graph archive uses schema v${schemaVersion} and must be upgraded before use.\\nRun: wg maintenance upgrade ${archivePath}`,\n );\n }\n}\n\nexport async function readWikiGraphArchiveSchemaVersion(\n archivePath: string,\n): Promise<number> {\n const { entries, zipFile } = await openIndexedArchive(resolve(archivePath));\n\n try {\n const manifestEntry = entries.find(\n (entry) => normalizeArchivePath(entry.fileName) === WIKG_MANIFEST_PATH,\n );\n\n if (manifestEntry === undefined) {\n throw new Error(`Missing WIKG manifest: ${WIKG_MANIFEST_PATH}.`);\n }\n\n return parseWikgManifest(\n await readArchiveEntryText(resolve(archivePath), manifestEntry),\n ).schemaVersion;\n } finally {\n zipFile.close();\n }\n}\n\nexport async function upgradeWikiGraphArchiveSchema(\n archivePath: string,\n): Promise<void> {\n const resolvedArchivePath = resolve(archivePath);\n const schemaVersion =\n await readWikiGraphArchiveSchemaVersion(resolvedArchivePath);\n\n if (schemaVersion === CURRENT_ARCHIVE_SCHEMA_VERSION) {\n return;\n }\n\n if (schemaVersion > CURRENT_ARCHIVE_SCHEMA_VERSION) {\n throw new Error(\n `Unsupported Wiki Graph archive schema version: ${schemaVersion}.`,\n );\n }\n\n await ensureWikiGraphHomeSchemaCurrent();\n\n const archiveKey = createArchiveKey(resolvedArchivePath);\n await assertArchiveUpgradeSafe(archiveKey);\n\n const temporaryPath = join(\n dirname(resolvedArchivePath),\n `.${getArchiveBasename(resolvedArchivePath)}.${process.pid}.${randomUUID()}.upgrade.tmp`,\n );\n const temporaryDirectories: string[] = [];\n\n try {\n const tocOverlay = await createChapterTocUpgradeOverlay(\n resolvedArchivePath,\n temporaryDirectories,\n );\n await writeWikgArchiveWithOverlays(\n resolvedArchivePath,\n temporaryPath,\n [\n {\n entryPath: SEARCH_INDEX_DATABASE_PATH,\n kind: \"deleted\",\n },\n ...(tocOverlay === undefined ? [] : [tocOverlay]),\n ],\n { preserveMutationToken: true },\n );\n await rename(temporaryPath, resolvedArchivePath);\n await cleanupArchiveDerivedData(archiveKey);\n } finally {\n await Promise.all(\n temporaryDirectories.map(async (path) => {\n await deletePathIfExists(path);\n }),\n );\n }\n}\n\nasync function createChapterTocUpgradeOverlay(\n archivePath: string,\n temporaryDirectories: string[],\n): Promise<\n | {\n readonly entryPath: \"toc.json\";\n readonly kind: \"file\";\n readonly workspacePath: string;\n }\n | undefined\n> {\n const { entries, zipFile } = await openIndexedArchive(archivePath);\n\n try {\n const tocEntry = entries.find(\n (entry) => normalizeArchivePath(entry.fileName) === \"toc.json\",\n );\n\n if (tocEntry === undefined) {\n return undefined;\n }\n\n const tocText = await readArchiveEntryText(archivePath, tocEntry);\n let toc: TocFile;\n\n try {\n const parsed = tocFileSchema.safeParse(JSON.parse(tocText));\n if (!parsed.success) {\n return undefined;\n }\n toc = parsed.data;\n } catch {\n return undefined;\n }\n\n const mutableToc = JSON.parse(JSON.stringify(toc)) as MutableTocFile;\n if (!ensureChapterKeys(mutableToc.items)) {\n return undefined;\n }\n\n const temporaryDirectory = await mkdtemp(\n join(tmpdir(), \"wikigraph-toc-upgrade-\"),\n );\n temporaryDirectories.push(temporaryDirectory);\n const workspacePath = join(temporaryDirectory, \"toc.json\");\n await writeFile(\n workspacePath,\n `${JSON.stringify(mutableToc, null, 2)}\\n`,\n \"utf8\",\n );\n\n return {\n entryPath: \"toc.json\",\n kind: \"file\",\n workspacePath,\n };\n } finally {\n zipFile.close();\n }\n}\n\nasync function cleanupArchiveDerivedData(archiveKey: string): Promise<void> {\n const cacheDirectoryPath = join(resolveWikiGraphHomeDirectoryPath(), \"cache\");\n await deletePathIfExists(join(cacheDirectoryPath, \"search-sessions.sqlite\"));\n await deletePathIfExists(\n join(cacheDirectoryPath, \"continuation-cursors.sqlite\"),\n );\n\n const stagingDatabasePath = join(\n resolveWikiGraphStagingDirectoryPath(),\n \"staging.sqlite\",\n );\n if (await pathExists(stagingDatabasePath)) {\n await removeArchiveSearchIndexOverlays(stagingDatabasePath, archiveKey);\n }\n}\n\nasync function assertArchiveUpgradeSafe(archiveKey: string): Promise<void> {\n const stagingDatabasePath = join(\n resolveWikiGraphStagingDirectoryPath(),\n \"staging.sqlite\",\n );\n\n if (!(await pathExists(stagingDatabasePath))) {\n return;\n }\n\n const database = await Database.open(stagingDatabasePath, \"\", {\n readonly: true,\n });\n\n try {\n for (const tableName of [\n \"archive_owners\",\n \"entry_locks\",\n \"entry_sqlite_leases\",\n \"archive_commit_locks\",\n ]) {\n if (!(await tableExists(database, tableName))) {\n continue;\n }\n\n const rows = await database.queryAll(\n `\n SELECT owner_pid, heartbeat_at\n FROM ${tableName}\n WHERE archive_key = ?\n `,\n [archiveKey],\n (row) => ({\n heartbeatAt: Number(row.heartbeat_at),\n ownerPid: Number(row.owner_pid),\n }),\n );\n\n if (rows.some((row) => isActiveLock(row.ownerPid, row.heartbeatAt))) {\n throw new Error(\n `Cannot upgrade archive with active coordinator state: ${archiveKey}.`,\n );\n }\n }\n\n if (await tableExists(database, \"entry_overlays\")) {\n const overlays = await database.queryAll(\n `\n SELECT entry_path\n FROM entry_overlays\n WHERE archive_key = ?\n `,\n [archiveKey],\n (row) => String(row.entry_path),\n );\n\n const problematicOverlay = overlays.find(\n (entryPath) => entryPath !== SEARCH_INDEX_DATABASE_PATH,\n );\n if (problematicOverlay !== undefined) {\n throw new Error(\n `Cannot upgrade archive with non-derived overlay state: ${archiveKey}.`,\n );\n }\n }\n } finally {\n await database.close();\n }\n}\n\nasync function removeArchiveSearchIndexOverlays(\n stagingDatabasePath: string,\n archiveKey?: string,\n): Promise<void> {\n const database = await Database.open(stagingDatabasePath);\n\n try {\n if (!(await tableExists(database, \"entry_overlays\"))) {\n return;\n }\n\n const whereClause =\n archiveKey === undefined\n ? \"WHERE entry_path = ?\"\n : \"WHERE archive_key = ? AND entry_path = ?\";\n const parameters =\n archiveKey === undefined\n ? [SEARCH_INDEX_DATABASE_PATH]\n : [archiveKey, SEARCH_INDEX_DATABASE_PATH];\n const overlays = await database.queryAll(\n `\n SELECT archive_key, workspace_path\n FROM entry_overlays\n ${whereClause}\n `,\n parameters,\n (row) => ({\n archiveKey: String(row.archive_key),\n workspacePath:\n row.workspace_path === null ? undefined : String(row.workspace_path),\n }),\n );\n\n for (const overlay of overlays) {\n if (overlay.workspacePath !== undefined) {\n await deletePathIfExists(overlay.workspacePath);\n }\n }\n\n await database.run(\n `\n DELETE FROM entry_overlays\n ${whereClause}\n `,\n parameters,\n );\n } finally {\n await database.close();\n }\n}\n\nasync function tableExists(\n database: Database,\n tableName: string,\n): Promise<boolean> {\n const row = await database.queryOne(\n `\n SELECT 1 AS present\n FROM sqlite_master\n WHERE type = 'table' AND name = ?\n `,\n [tableName],\n () => true,\n );\n\n return row === true;\n}\n\nfunction isActiveLock(ownerPid: number, heartbeatAt: number): boolean {\n return (\n Date.now() - heartbeatAt <= LOCK_STALE_TIMEOUT_MS &&\n isProcessAlive(ownerPid)\n );\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function deletePathIfExists(path: string): Promise<void> {\n await rm(path, { force: true, recursive: true });\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction getArchiveBasename(archivePath: string): string {\n return archivePath.split(/[\\\\/]/u).pop() ?? \"archive.wikg\";\n}\n"],"mappings":"AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,QAAQ,IAAI,MAAM,iBAAiB;AACrD,SAAS,cAAc;AACvB,SAAS,SAAS,MAAM,eAAe;AAEvC,SAAS,gBAAgB;AACzB,SAAS,yBAAyB;AAElC,SAAS,wCAAwC;AACjD;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,oCAAoC;AAC7C,SAAS,wBAAwB;AACjC,SAAS,qBAAmC;AAE5C;AAAA,EACE,oCAAAA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,iCAAiC;AAC9C,MAAM,wBAAwB,IAAI,KAAK;AAEvC,eAAsB,oCACpB,aACe;AACf,QAAM,gBAAgB,MAAM,kCAAkC,WAAW;AAEzE,MAAI,gBAAgB,gCAAgC;AAClD,UAAM,IAAI;AAAA,MACR,kDAAkD,aAAa;AAAA,IACjE;AAAA,EACF;AACA,MAAI,gBAAgB,gCAAgC;AAClD,UAAM,IAAI;AAAA,MACR,wCAAwC,aAAa;AAAA,8BAAkE,WAAW;AAAA,IACpI;AAAA,EACF;AACF;AAEA,eAAsB,kCACpB,aACiB;AACjB,QAAM,EAAE,SAAS,QAAQ,IAAI,MAAM,mBAAmB,QAAQ,WAAW,CAAC;AAE1E,MAAI;AACF,UAAM,gBAAgB,QAAQ;AAAA,MAC5B,CAAC,UAAU,qBAAqB,MAAM,QAAQ,MAAM;AAAA,IACtD;AAEA,QAAI,kBAAkB,QAAW;AAC/B,YAAM,IAAI,MAAM,0BAA0B,kBAAkB,GAAG;AAAA,IACjE;AAEA,WAAO;AAAA,MACL,MAAM,qBAAqB,QAAQ,WAAW,GAAG,aAAa;AAAA,IAChE,EAAE;AAAA,EACJ,UAAE;AACA,YAAQ,MAAM;AAAA,EAChB;AACF;AAEA,eAAsB,8BACpB,aACe;AACf,QAAM,sBAAsB,QAAQ,WAAW;AAC/C,QAAM,gBACJ,MAAM,kCAAkC,mBAAmB;AAE7D,MAAI,kBAAkB,gCAAgC;AACpD;AAAA,EACF;AAEA,MAAI,gBAAgB,gCAAgC;AAClD,UAAM,IAAI;AAAA,MACR,kDAAkD,aAAa;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,iCAAiC;AAEvC,QAAM,aAAa,iBAAiB,mBAAmB;AACvD,QAAM,yBAAyB,UAAU;AAEzC,QAAM,gBAAgB;AAAA,IACpB,QAAQ,mBAAmB;AAAA,IAC3B,IAAI,mBAAmB,mBAAmB,CAAC,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC;AAAA,EAC5E;AACA,QAAM,uBAAiC,CAAC;AAExC,MAAI;AACF,UAAM,aAAa,MAAM;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AACA,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,QACE;AAAA,UACE,WAAW;AAAA,UACX,MAAM;AAAA,QACR;AAAA,QACA,GAAI,eAAe,SAAY,CAAC,IAAI,CAAC,UAAU;AAAA,MACjD;AAAA,MACA,EAAE,uBAAuB,KAAK;AAAA,IAChC;AACA,UAAM,OAAO,eAAe,mBAAmB;AAC/C,UAAM,0BAA0B,UAAU;AAAA,EAC5C,UAAE;AACA,UAAM,QAAQ;AAAA,MACZ,qBAAqB,IAAI,OAAO,SAAS;AACvC,cAAM,mBAAmB,IAAI;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,eAAe,+BACb,aACA,sBAQA;AACA,QAAM,EAAE,SAAS,QAAQ,IAAI,MAAM,mBAAmB,WAAW;AAEjE,MAAI;AACF,UAAM,WAAW,QAAQ;AAAA,MACvB,CAAC,UAAU,qBAAqB,MAAM,QAAQ,MAAM;AAAA,IACtD;AAEA,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,MAAM,qBAAqB,aAAa,QAAQ;AAChE,QAAI;AAEJ,QAAI;AACF,YAAM,SAAS,cAAc,UAAU,KAAK,MAAM,OAAO,CAAC;AAC1D,UAAI,CAAC,OAAO,SAAS;AACnB,eAAO;AAAA,MACT;AACA,YAAM,OAAO;AAAA,IACf,QAAQ;AACN,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;AACjD,QAAI,CAAC,kBAAkB,WAAW,KAAK,GAAG;AACxC,aAAO;AAAA,IACT;AAEA,UAAM,qBAAqB,MAAM;AAAA,MAC/B,KAAK,OAAO,GAAG,wBAAwB;AAAA,IACzC;AACA,yBAAqB,KAAK,kBAAkB;AAC5C,UAAM,gBAAgB,KAAK,oBAAoB,UAAU;AACzD,UAAM;AAAA,MACJ;AAAA,MACA,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,CAAC;AAAA;AAAA,MACtC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,MACX,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF,UAAE;AACA,YAAQ,MAAM;AAAA,EAChB;AACF;AAEA,eAAe,0BAA0B,YAAmC;AAC1E,QAAM,qBAAqB,KAAK,kCAAkC,GAAG,OAAO;AAC5E,QAAM,mBAAmB,KAAK,oBAAoB,wBAAwB,CAAC;AAC3E,QAAM;AAAA,IACJ,KAAK,oBAAoB,6BAA6B;AAAA,EACxD;AAEA,QAAM,sBAAsB;AAAA,IAC1B,qCAAqC;AAAA,IACrC;AAAA,EACF;AACA,MAAI,MAAM,WAAW,mBAAmB,GAAG;AACzC,UAAM,iCAAiC,qBAAqB,UAAU;AAAA,EACxE;AACF;AAEA,eAAe,yBAAyB,YAAmC;AACzE,QAAM,sBAAsB;AAAA,IAC1B,qCAAqC;AAAA,IACrC;AAAA,EACF;AAEA,MAAI,CAAE,MAAM,WAAW,mBAAmB,GAAI;AAC5C;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,SAAS,KAAK,qBAAqB,IAAI;AAAA,IAC5D,UAAU;AAAA,EACZ,CAAC;AAED,MAAI;AACF,eAAW,aAAa;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,GAAG;AACD,UAAI,CAAE,MAAM,YAAY,UAAU,SAAS,GAAI;AAC7C;AAAA,MACF;AAEA,YAAM,OAAO,MAAM,SAAS;AAAA,QAC1B;AAAA;AAAA,iBAES,SAAS;AAAA;AAAA;AAAA,QAGlB,CAAC,UAAU;AAAA,QACX,CAAC,SAAS;AAAA,UACR,aAAa,OAAO,IAAI,YAAY;AAAA,UACpC,UAAU,OAAO,IAAI,SAAS;AAAA,QAChC;AAAA,MACF;AAEA,UAAI,KAAK,KAAK,CAAC,QAAQ,aAAa,IAAI,UAAU,IAAI,WAAW,CAAC,GAAG;AACnE,cAAM,IAAI;AAAA,UACR,yDAAyD,UAAU;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,YAAY,UAAU,gBAAgB,GAAG;AACjD,YAAM,WAAW,MAAM,SAAS;AAAA,QAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA,CAAC,UAAU;AAAA,QACX,CAAC,QAAQ,OAAO,IAAI,UAAU;AAAA,MAChC;AAEA,YAAM,qBAAqB,SAAS;AAAA,QAClC,CAAC,cAAc,cAAc;AAAA,MAC/B;AACA,UAAI,uBAAuB,QAAW;AACpC,cAAM,IAAI;AAAA,UACR,0DAA0D,UAAU;AAAA,QACtE;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,UAAM,SAAS,MAAM;AAAA,EACvB;AACF;AAEA,eAAe,iCACb,qBACA,YACe;AACf,QAAM,WAAW,MAAM,SAAS,KAAK,mBAAmB;AAExD,MAAI;AACF,QAAI,CAAE,MAAM,YAAY,UAAU,gBAAgB,GAAI;AACpD;AAAA,IACF;AAEA,UAAM,cACJ,eAAe,SACX,yBACA;AACN,UAAM,aACJ,eAAe,SACX,CAAC,0BAA0B,IAC3B,CAAC,YAAY,0BAA0B;AAC7C,UAAM,WAAW,MAAM,SAAS;AAAA,MAC9B;AAAA;AAAA;AAAA,UAGI,WAAW;AAAA;AAAA,MAEf;AAAA,MACA,CAAC,SAAS;AAAA,QACR,YAAY,OAAO,IAAI,WAAW;AAAA,QAClC,eACE,IAAI,mBAAmB,OAAO,SAAY,OAAO,IAAI,cAAc;AAAA,MACvE;AAAA,IACF;AAEA,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,kBAAkB,QAAW;AACvC,cAAM,mBAAmB,QAAQ,aAAa;AAAA,MAChD;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb;AAAA;AAAA,UAEI,WAAW;AAAA;AAAA,MAEf;AAAA,IACF;AAAA,EACF,UAAE;AACA,UAAM,SAAS,MAAM;AAAA,EACvB;AACF;AAEA,eAAe,YACb,UACA,WACkB;AAClB,QAAM,MAAM,MAAM,SAAS;AAAA,IACzB;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,CAAC,SAAS;AAAA,IACV,MAAM;AAAA,EACR;AAEA,SAAO,QAAQ;AACjB;AAEA,SAAS,aAAa,UAAkB,aAA8B;AACpE,SACE,KAAK,IAAI,IAAI,eAAe,yBAC5B,eAAe,QAAQ;AAE3B;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,mBAAmB,MAA6B;AAC7D,QAAM,GAAG,MAAM,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AACjD;AAEA,eAAe,WAAW,MAAgC;AACxD,MAAI;AACF,UAAM,KAAK,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,aAA6B;AACvD,SAAO,YAAY,MAAM,QAAQ,EAAE,IAAI,KAAK;AAC9C;","names":["ensureWikiGraphHomeSchemaCurrent"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/storage/schema-upgrade/index.ts"],"sourcesContent":["import { randomUUID } from \"crypto\";\nimport { mkdtemp, rename, rm, stat, writeFile } from \"fs/promises\";\nimport { tmpdir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\n\nimport { Database } from \"../../document/database.js\";\nimport { ensureChapterKeys } from \"../../document/chapter/toc.js\";\nimport type { MutableTocFile } from \"../../document/chapter/tree.js\";\nimport { ensureWikiGraphHomeSchemaCurrent } from \"../../document/home-schema-upgrade.js\";\nimport {\n resolveWikiGraphHomeDirectoryPath,\n resolveWikiGraphStagingDirectoryPath,\n} from \"../../runtime/common/wiki-graph/dir.js\";\nimport {\n SEARCH_INDEX_DATABASE_PATH,\n WIKG_MANIFEST_PATH,\n} from \"../wikg/archive/constants.js\";\nimport { parseWikgManifest } from \"../wikg/archive/manifest.js\";\nimport { normalizeArchivePath } from \"../wikg/archive/paths.js\";\nimport {\n openIndexedArchive,\n readArchiveEntryText,\n} from \"../wikg/archive/zip.js\";\nimport { writeWikgArchiveWithOverlays } from \"../wikg/archive/write.js\";\nimport { createArchiveKey } from \"../wikg/wikg-coordinator/archive-key.js\";\nimport { tocFileSchema, type TocFile } from \"../../text/source/toc.js\";\n\nexport {\n ensureWikiGraphHomeSchemaCurrent,\n readWikiGraphHomeSchemaVersion,\n} from \"../../document/home-schema-upgrade.js\";\n\nexport const CURRENT_ARCHIVE_SCHEMA_VERSION = 2;\nconst LOCK_STALE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface WikiGraphArchiveSchemaUpgradeResult {\n readonly changed: boolean;\n readonly repairedToc: boolean;\n readonly schemaChanged: boolean;\n}\n\nexport async function ensureWikiGraphArchiveSchemaCurrent(\n archivePath: string,\n): Promise<void> {\n const schemaVersion = await readWikiGraphArchiveSchemaVersion(archivePath);\n\n if (schemaVersion > CURRENT_ARCHIVE_SCHEMA_VERSION) {\n throw new Error(\n `Unsupported Wiki Graph archive schema version: ${schemaVersion}.`,\n );\n }\n if (schemaVersion < CURRENT_ARCHIVE_SCHEMA_VERSION) {\n throw new Error(\n `This Wiki Graph archive uses schema v${schemaVersion} and must be upgraded before use.\\nRun: wg maintenance upgrade ${archivePath}`,\n );\n }\n}\n\nexport async function readWikiGraphArchiveSchemaVersion(\n archivePath: string,\n): Promise<number> {\n const { entries, zipFile } = await openIndexedArchive(resolve(archivePath));\n\n try {\n const manifestEntry = entries.find(\n (entry) => normalizeArchivePath(entry.fileName) === WIKG_MANIFEST_PATH,\n );\n\n if (manifestEntry === undefined) {\n throw new Error(`Missing WIKG manifest: ${WIKG_MANIFEST_PATH}.`);\n }\n\n return parseWikgManifest(\n await readArchiveEntryText(resolve(archivePath), manifestEntry),\n ).schemaVersion;\n } finally {\n zipFile.close();\n }\n}\n\nexport async function upgradeWikiGraphArchiveSchema(\n archivePath: string,\n): Promise<WikiGraphArchiveSchemaUpgradeResult> {\n const resolvedArchivePath = resolve(archivePath);\n const schemaVersion =\n await readWikiGraphArchiveSchemaVersion(resolvedArchivePath);\n\n if (schemaVersion > CURRENT_ARCHIVE_SCHEMA_VERSION) {\n throw new Error(\n `Unsupported Wiki Graph archive schema version: ${schemaVersion}.`,\n );\n }\n\n const temporaryDirectories: string[] = [];\n\n try {\n const tocOverlay = await createChapterTocUpgradeOverlay(\n resolvedArchivePath,\n temporaryDirectories,\n );\n const schemaChanged = schemaVersion < CURRENT_ARCHIVE_SCHEMA_VERSION;\n\n if (!schemaChanged && tocOverlay === undefined) {\n return {\n changed: false,\n repairedToc: false,\n schemaChanged: false,\n };\n }\n\n await ensureWikiGraphHomeSchemaCurrent();\n\n const archiveKey = createArchiveKey(resolvedArchivePath);\n await assertArchiveUpgradeSafe(archiveKey);\n\n const temporaryPath = join(\n dirname(resolvedArchivePath),\n `.${getArchiveBasename(resolvedArchivePath)}.${process.pid}.${randomUUID()}.upgrade.tmp`,\n );\n\n await writeWikgArchiveWithOverlays(\n resolvedArchivePath,\n temporaryPath,\n [\n ...(schemaChanged\n ? [\n {\n entryPath: SEARCH_INDEX_DATABASE_PATH,\n kind: \"deleted\" as const,\n },\n ]\n : []),\n ...(tocOverlay === undefined ? [] : [tocOverlay]),\n ],\n { preserveMutationToken: true },\n );\n await rename(temporaryPath, resolvedArchivePath);\n await cleanupArchiveDerivedData(archiveKey);\n\n return {\n changed: true,\n repairedToc: tocOverlay !== undefined,\n schemaChanged,\n };\n } finally {\n await Promise.all(\n temporaryDirectories.map(async (path) => {\n await deletePathIfExists(path);\n }),\n );\n }\n}\n\nasync function createChapterTocUpgradeOverlay(\n archivePath: string,\n temporaryDirectories: string[],\n): Promise<\n | {\n readonly entryPath: \"toc.json\";\n readonly kind: \"file\";\n readonly workspacePath: string;\n }\n | undefined\n> {\n const { entries, zipFile } = await openIndexedArchive(archivePath);\n\n try {\n const tocEntry = entries.find(\n (entry) => normalizeArchivePath(entry.fileName) === \"toc.json\",\n );\n\n if (tocEntry === undefined) {\n return undefined;\n }\n\n const tocText = await readArchiveEntryText(archivePath, tocEntry);\n let toc: TocFile;\n\n try {\n const parsed = tocFileSchema.safeParse(JSON.parse(tocText));\n if (!parsed.success) {\n return undefined;\n }\n toc = parsed.data;\n } catch {\n return undefined;\n }\n\n const mutableToc = JSON.parse(JSON.stringify(toc)) as MutableTocFile;\n if (!ensureChapterKeys(mutableToc.items)) {\n return undefined;\n }\n\n const temporaryDirectory = await mkdtemp(\n join(tmpdir(), \"wikigraph-toc-upgrade-\"),\n );\n temporaryDirectories.push(temporaryDirectory);\n const workspacePath = join(temporaryDirectory, \"toc.json\");\n await writeFile(\n workspacePath,\n `${JSON.stringify(mutableToc, null, 2)}\\n`,\n \"utf8\",\n );\n\n return {\n entryPath: \"toc.json\",\n kind: \"file\",\n workspacePath,\n };\n } finally {\n zipFile.close();\n }\n}\n\nasync function cleanupArchiveDerivedData(archiveKey: string): Promise<void> {\n const cacheDirectoryPath = join(resolveWikiGraphHomeDirectoryPath(), \"cache\");\n await deletePathIfExists(join(cacheDirectoryPath, \"search-sessions.sqlite\"));\n await deletePathIfExists(\n join(cacheDirectoryPath, \"continuation-cursors.sqlite\"),\n );\n\n const stagingDatabasePath = join(\n resolveWikiGraphStagingDirectoryPath(),\n \"staging.sqlite\",\n );\n if (await pathExists(stagingDatabasePath)) {\n await removeArchiveSearchIndexOverlays(stagingDatabasePath, archiveKey);\n }\n}\n\nasync function assertArchiveUpgradeSafe(archiveKey: string): Promise<void> {\n const stagingDatabasePath = join(\n resolveWikiGraphStagingDirectoryPath(),\n \"staging.sqlite\",\n );\n\n if (!(await pathExists(stagingDatabasePath))) {\n return;\n }\n\n const database = await Database.open(stagingDatabasePath, \"\", {\n readonly: true,\n });\n\n try {\n for (const tableName of [\n \"archive_owners\",\n \"entry_locks\",\n \"entry_sqlite_leases\",\n \"archive_commit_locks\",\n ]) {\n if (!(await tableExists(database, tableName))) {\n continue;\n }\n\n const rows = await database.queryAll(\n `\n SELECT owner_pid, heartbeat_at\n FROM ${tableName}\n WHERE archive_key = ?\n `,\n [archiveKey],\n (row) => ({\n heartbeatAt: Number(row.heartbeat_at),\n ownerPid: Number(row.owner_pid),\n }),\n );\n\n if (rows.some((row) => isActiveLock(row.ownerPid, row.heartbeatAt))) {\n throw new Error(\n `Cannot upgrade archive with active coordinator state: ${archiveKey}.`,\n );\n }\n }\n\n if (await tableExists(database, \"entry_overlays\")) {\n const overlays = await database.queryAll(\n `\n SELECT entry_path\n FROM entry_overlays\n WHERE archive_key = ?\n `,\n [archiveKey],\n (row) => String(row.entry_path),\n );\n\n const problematicOverlay = overlays.find(\n (entryPath) => entryPath !== SEARCH_INDEX_DATABASE_PATH,\n );\n if (problematicOverlay !== undefined) {\n throw new Error(\n `Cannot upgrade archive with non-derived overlay state: ${archiveKey}.`,\n );\n }\n }\n } finally {\n await database.close();\n }\n}\n\nasync function removeArchiveSearchIndexOverlays(\n stagingDatabasePath: string,\n archiveKey?: string,\n): Promise<void> {\n const database = await Database.open(stagingDatabasePath);\n\n try {\n if (!(await tableExists(database, \"entry_overlays\"))) {\n return;\n }\n\n const whereClause =\n archiveKey === undefined\n ? \"WHERE entry_path = ?\"\n : \"WHERE archive_key = ? AND entry_path = ?\";\n const parameters =\n archiveKey === undefined\n ? [SEARCH_INDEX_DATABASE_PATH]\n : [archiveKey, SEARCH_INDEX_DATABASE_PATH];\n const overlays = await database.queryAll(\n `\n SELECT archive_key, workspace_path\n FROM entry_overlays\n ${whereClause}\n `,\n parameters,\n (row) => ({\n archiveKey: String(row.archive_key),\n workspacePath:\n row.workspace_path === null ? undefined : String(row.workspace_path),\n }),\n );\n\n for (const overlay of overlays) {\n if (overlay.workspacePath !== undefined) {\n await deletePathIfExists(overlay.workspacePath);\n }\n }\n\n await database.run(\n `\n DELETE FROM entry_overlays\n ${whereClause}\n `,\n parameters,\n );\n } finally {\n await database.close();\n }\n}\n\nasync function tableExists(\n database: Database,\n tableName: string,\n): Promise<boolean> {\n const row = await database.queryOne(\n `\n SELECT 1 AS present\n FROM sqlite_master\n WHERE type = 'table' AND name = ?\n `,\n [tableName],\n () => true,\n );\n\n return row === true;\n}\n\nfunction isActiveLock(ownerPid: number, heartbeatAt: number): boolean {\n return (\n Date.now() - heartbeatAt <= LOCK_STALE_TIMEOUT_MS &&\n isProcessAlive(ownerPid)\n );\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function deletePathIfExists(path: string): Promise<void> {\n await rm(path, { force: true, recursive: true });\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction getArchiveBasename(archivePath: string): string {\n return archivePath.split(/[\\\\/]/u).pop() ?? \"archive.wikg\";\n}\n"],"mappings":"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","names":["ensureWikiGraphHomeSchemaCurrent"]}
|