wiki-graph-sdk 0.7.1 → 0.8.0
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 +1 -1
- package/dist/archives.cjs +406 -642
- package/dist/archives.cjs.map +1 -1
- package/dist/archives.d.ts +42 -80
- package/dist/archives.js +342 -571
- package/dist/archives.js.map +1 -1
- package/dist/conversions.cjs +160 -28
- package/dist/conversions.cjs.map +1 -1
- package/dist/conversions.d.ts +3 -1
- package/dist/conversions.js +165 -24
- package/dist/conversions.js.map +1 -1
- package/dist/default-worker.cjs +289 -52
- package/dist/default-worker.cjs.map +1 -1
- package/dist/default-worker.js +303 -50
- package/dist/default-worker.js.map +1 -1
- package/dist/index.cjs +967 -911
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +36 -19
- package/dist/index.js +836 -767
- package/dist/index.js.map +1 -1
- package/dist/{jobs-Dd5PMSId.d.ts → jobs-xIm_kshM.d.ts} +22 -14
- package/dist/maintenance.cjs +138 -29
- package/dist/maintenance.cjs.map +1 -1
- package/dist/maintenance.d.ts +2 -1
- package/dist/maintenance.js +143 -25
- package/dist/maintenance.js.map +1 -1
- package/dist/target-CZ7elwmj.d.ts +14 -0
- package/dist/wikispine.cjs +14 -10
- package/dist/wikispine.cjs.map +1 -1
- package/dist/wikispine.js +14 -10
- package/dist/wikispine.js.map +1 -1
- package/dist/worker.cjs +294 -25
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.ts +28 -5
- package/dist/worker.js +312 -28
- package/dist/worker.js.map +1 -1
- package/package.json +2 -2
package/dist/conversions.js
CHANGED
|
@@ -6,7 +6,7 @@ globalThis.__WIKIGRAPH_DATA_DIR__ ??= __WIKIGRAPH_RESOLVE__(__WIKIGRAPH_FILE_URL
|
|
|
6
6
|
import { createHash } from "crypto";
|
|
7
7
|
import { createReadStream } from "fs";
|
|
8
8
|
import { rm as rm2 } from "fs/promises";
|
|
9
|
-
import { basename as
|
|
9
|
+
import { basename as basename3 } from "path";
|
|
10
10
|
import {
|
|
11
11
|
WikiGraph
|
|
12
12
|
} from "wiki-graph-core";
|
|
@@ -316,6 +316,14 @@ function decodeNodeResourceIdentity(identity, kind) {
|
|
|
316
316
|
return void 0;
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
|
+
function getNodeResourcePath(resource) {
|
|
320
|
+
const brandedPath = getBrandedNodeResourcePath(resource, resource.kind);
|
|
321
|
+
if (brandedPath !== void 0) return brandedPath;
|
|
322
|
+
if (typeof resource === "object" && resource !== null && "path" in resource && typeof resource.path === "string") {
|
|
323
|
+
return resource.path;
|
|
324
|
+
}
|
|
325
|
+
throw new TypeError("Expected a Node File or Directory resource");
|
|
326
|
+
}
|
|
319
327
|
function assertChildName(name) {
|
|
320
328
|
if (name.length === 0 || name === "." || name === ".." || pathModule.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
|
|
321
329
|
throw new TypeError(`Directory child must be a relative name: ${name}`);
|
|
@@ -327,42 +335,42 @@ var NodeDatabaseConnection = class {
|
|
|
327
335
|
}
|
|
328
336
|
database;
|
|
329
337
|
async close() {
|
|
330
|
-
await new Promise((
|
|
338
|
+
await new Promise((resolve4, reject) => {
|
|
331
339
|
this.database.close((error) => {
|
|
332
340
|
if (error) reject(error);
|
|
333
|
-
else
|
|
341
|
+
else resolve4();
|
|
334
342
|
});
|
|
335
343
|
});
|
|
336
344
|
}
|
|
337
345
|
async execute(sql) {
|
|
338
|
-
await new Promise((
|
|
346
|
+
await new Promise((resolve4, reject) => {
|
|
339
347
|
this.database.exec(sql, (error) => {
|
|
340
348
|
if (error) reject(error);
|
|
341
|
-
else
|
|
349
|
+
else resolve4();
|
|
342
350
|
});
|
|
343
351
|
});
|
|
344
352
|
}
|
|
345
353
|
async queryAll(sql, params = []) {
|
|
346
|
-
return await new Promise((
|
|
354
|
+
return await new Promise((resolve4, reject) => {
|
|
347
355
|
this.database.all(sql, [...params], (error, rows) => {
|
|
348
356
|
if (error) reject(error);
|
|
349
|
-
else
|
|
357
|
+
else resolve4(rows);
|
|
350
358
|
});
|
|
351
359
|
});
|
|
352
360
|
}
|
|
353
361
|
async queryOne(sql, params = []) {
|
|
354
|
-
return await new Promise((
|
|
362
|
+
return await new Promise((resolve4, reject) => {
|
|
355
363
|
this.database.get(sql, [...params], (error, row) => {
|
|
356
364
|
if (error) reject(error);
|
|
357
|
-
else
|
|
365
|
+
else resolve4(row);
|
|
358
366
|
});
|
|
359
367
|
});
|
|
360
368
|
}
|
|
361
369
|
async run(sql, params = []) {
|
|
362
|
-
await new Promise((
|
|
370
|
+
await new Promise((resolve4, reject) => {
|
|
363
371
|
this.database.run(sql, [...params], (error) => {
|
|
364
372
|
if (error) reject(error);
|
|
365
|
-
else
|
|
373
|
+
else resolve4();
|
|
366
374
|
});
|
|
367
375
|
});
|
|
368
376
|
}
|
|
@@ -376,10 +384,10 @@ async function openNativeNodeDatabase(file, flags) {
|
|
|
376
384
|
if (path === void 0) {
|
|
377
385
|
throw new TypeError("The Node database adapter requires a NodeFile");
|
|
378
386
|
}
|
|
379
|
-
return await new Promise((
|
|
387
|
+
return await new Promise((resolve4, reject) => {
|
|
380
388
|
const database = new nodeSqlite3.Database(path, flags, (error) => {
|
|
381
389
|
if (error) reject(error);
|
|
382
|
-
else
|
|
390
|
+
else resolve4(database);
|
|
383
391
|
});
|
|
384
392
|
});
|
|
385
393
|
}
|
|
@@ -388,19 +396,19 @@ async function openNodeZip(file) {
|
|
|
388
396
|
if (path === void 0) {
|
|
389
397
|
throw new TypeError("The Node ZIP adapter requires a NodeFile");
|
|
390
398
|
}
|
|
391
|
-
const zipFile = await new Promise((
|
|
399
|
+
const zipFile = await new Promise((resolve4, reject) => {
|
|
392
400
|
yauzl.open(
|
|
393
401
|
path,
|
|
394
402
|
{ autoClose: false, lazyEntries: true },
|
|
395
403
|
(error, opened) => {
|
|
396
404
|
if (error || opened === void 0)
|
|
397
405
|
reject(error ?? new Error("Cannot open ZIP"));
|
|
398
|
-
else
|
|
406
|
+
else resolve4(opened);
|
|
399
407
|
}
|
|
400
408
|
);
|
|
401
409
|
});
|
|
402
410
|
const entries = await new Promise(
|
|
403
|
-
(
|
|
411
|
+
(resolve4, reject) => {
|
|
404
412
|
const discovered = /* @__PURE__ */ new Map();
|
|
405
413
|
const rejectAndClose = (error) => {
|
|
406
414
|
zipFile.close();
|
|
@@ -410,7 +418,7 @@ async function openNodeZip(file) {
|
|
|
410
418
|
};
|
|
411
419
|
const resolveEntries = () => {
|
|
412
420
|
zipFile.off("error", rejectAndClose);
|
|
413
|
-
|
|
421
|
+
resolve4(discovered);
|
|
414
422
|
};
|
|
415
423
|
zipFile.on("entry", (entry) => {
|
|
416
424
|
if (!entry.fileName.endsWith("/")) {
|
|
@@ -520,12 +528,12 @@ async function collectDecodedNodeStreamRange(input, offset, length) {
|
|
|
520
528
|
return Buffer.concat(chunks, collected);
|
|
521
529
|
}
|
|
522
530
|
async function openNodeZipEntryStream(zipFile, entry, options) {
|
|
523
|
-
return await new Promise((
|
|
531
|
+
return await new Promise((resolve4, reject) => {
|
|
524
532
|
const callback = (error, opened) => {
|
|
525
533
|
if (error || opened === void 0) {
|
|
526
534
|
reject(error ?? new Error(`Cannot read ZIP entry: ${entry.fileName}`));
|
|
527
535
|
} else {
|
|
528
|
-
|
|
536
|
+
resolve4(opened);
|
|
529
537
|
}
|
|
530
538
|
};
|
|
531
539
|
if (options === void 0) zipFile.openReadStream(entry, callback);
|
|
@@ -656,11 +664,11 @@ async function writeNodeStream(input, writer) {
|
|
|
656
664
|
);
|
|
657
665
|
}
|
|
658
666
|
async function collectNodeStream(input) {
|
|
659
|
-
return await new Promise((
|
|
667
|
+
return await new Promise((resolve4, reject) => {
|
|
660
668
|
const chunks = [];
|
|
661
669
|
input.on("data", (chunk) => chunks.push(chunk));
|
|
662
670
|
input.once("error", reject);
|
|
663
|
-
input.once("end", () =>
|
|
671
|
+
input.once("end", () => resolve4(Buffer.concat(chunks)));
|
|
664
672
|
});
|
|
665
673
|
}
|
|
666
674
|
var nodeWikiGraphPlatform = {
|
|
@@ -1213,6 +1221,116 @@ function resolveWikiGraphRuntimePath(path) {
|
|
|
1213
1221
|
return isAbsolute2(path) ? path : resolve2(context.cwd, path);
|
|
1214
1222
|
}
|
|
1215
1223
|
|
|
1224
|
+
// src/archive/target.ts
|
|
1225
|
+
import { realpath, stat as stat2 } from "fs/promises";
|
|
1226
|
+
import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute3, join as join3, relative, resolve as resolve3 } from "path";
|
|
1227
|
+
import {
|
|
1228
|
+
formatLocatedWikiGraphUri,
|
|
1229
|
+
formatWikiGraphLibraryUri,
|
|
1230
|
+
listWikiGraphLibraries,
|
|
1231
|
+
listWikiGraphLibraryArchives,
|
|
1232
|
+
parseLocatedWikiGraphUri,
|
|
1233
|
+
parseWikiGraphLibraryUri,
|
|
1234
|
+
resolveWikiGraphLibrary,
|
|
1235
|
+
resolveWikiGraphLibraryArchiveFile
|
|
1236
|
+
} from "wiki-graph-core";
|
|
1237
|
+
var WikiGraphArchiveOwnershipError = class extends Error {
|
|
1238
|
+
code = "WIKI_GRAPH_ARCHIVE_OWNERSHIP_MISMATCH";
|
|
1239
|
+
constructor(message) {
|
|
1240
|
+
super(message);
|
|
1241
|
+
this.name = "WikiGraphArchiveOwnershipError";
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
async function assertStandaloneWikiGraphArchivePath(inputPath) {
|
|
1245
|
+
const path = resolveWikiGraphRuntimePath(inputPath);
|
|
1246
|
+
const candidate = await canonicalPath(path);
|
|
1247
|
+
const candidateIdentity = await readFileIdentity(path);
|
|
1248
|
+
const libraries = await listWikiGraphLibraries();
|
|
1249
|
+
const matches = await findMatchingMembers(
|
|
1250
|
+
libraries,
|
|
1251
|
+
candidate,
|
|
1252
|
+
candidateIdentity
|
|
1253
|
+
);
|
|
1254
|
+
if (matches.length > 0) {
|
|
1255
|
+
const match = requireUnambiguousManagedMatch(path, matches);
|
|
1256
|
+
throw new WikiGraphArchiveOwnershipError(
|
|
1257
|
+
`Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
|
|
1258
|
+
match.library.isDefault ? void 0 : match.library.publicId
|
|
1259
|
+
)}: ${path}. Use the library UUID URI ${match.archive.uri} instead.`
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
for (const library of libraries) {
|
|
1263
|
+
const rootPath = getNodeResourcePath(library.folder);
|
|
1264
|
+
const root = await canonicalPath(rootPath);
|
|
1265
|
+
if (!isWithin(root, candidate)) continue;
|
|
1266
|
+
throw new WikiGraphArchiveOwnershipError(
|
|
1267
|
+
`Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
|
|
1268
|
+
library.isDefault ? void 0 : library.publicId
|
|
1269
|
+
)}: ${path}. Scan the library, then address the archive by its library UUID URI.`
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
return path;
|
|
1273
|
+
}
|
|
1274
|
+
async function canonicalPath(path) {
|
|
1275
|
+
try {
|
|
1276
|
+
return await realpath(path);
|
|
1277
|
+
} catch {
|
|
1278
|
+
const absolute = resolve3(path);
|
|
1279
|
+
const parent = dirname2(absolute);
|
|
1280
|
+
return parent === absolute ? absolute : join3(await canonicalPath(parent), basename2(absolute));
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
function isWithin(root, candidate) {
|
|
1284
|
+
const child = relative(root, candidate);
|
|
1285
|
+
return child === "" || !child.startsWith("..") && !isAbsolute3(child);
|
|
1286
|
+
}
|
|
1287
|
+
async function findMatchingMembers(libraries, candidate, candidateIdentity) {
|
|
1288
|
+
const members = [];
|
|
1289
|
+
for (const library of libraries) {
|
|
1290
|
+
const archives = await listWikiGraphLibraryArchives({
|
|
1291
|
+
isDefault: library.isDefault,
|
|
1292
|
+
kind: "scope",
|
|
1293
|
+
...library.isDefault ? {} : { publicId: library.publicId }
|
|
1294
|
+
});
|
|
1295
|
+
for (const archive of archives) {
|
|
1296
|
+
if (archive.file === void 0) continue;
|
|
1297
|
+
members.push({
|
|
1298
|
+
archive,
|
|
1299
|
+
library,
|
|
1300
|
+
memberPath: getNodeResourcePath(archive.file)
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
const exact = [];
|
|
1305
|
+
for (const member of members) {
|
|
1306
|
+
if (await canonicalPath(member.memberPath) === candidate) {
|
|
1307
|
+
exact.push(member);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
if (exact.length > 0 || candidateIdentity === void 0) return exact;
|
|
1311
|
+
const identityMatches = [];
|
|
1312
|
+
for (const member of members) {
|
|
1313
|
+
if (await readFileIdentity(member.memberPath) === candidateIdentity) {
|
|
1314
|
+
identityMatches.push(member);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return identityMatches;
|
|
1318
|
+
}
|
|
1319
|
+
function requireUnambiguousManagedMatch(path, matches) {
|
|
1320
|
+
if (matches.length === 1) return matches[0];
|
|
1321
|
+
throw new WikiGraphArchiveOwnershipError(
|
|
1322
|
+
`Archive file identity is ambiguous across managed archives: ${path}. Use an explicit library UUID URI (${matches.map((match) => match.archive.uri).join(", ")}).`
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
async function readFileIdentity(path) {
|
|
1326
|
+
try {
|
|
1327
|
+
const value = await stat2(path);
|
|
1328
|
+
return `${value.dev}:${value.ino}`;
|
|
1329
|
+
} catch {
|
|
1330
|
+
return void 0;
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1216
1334
|
// src/conversions.ts
|
|
1217
1335
|
var WikiGraphConversionManager = class {
|
|
1218
1336
|
#runtime;
|
|
@@ -1249,11 +1367,15 @@ var WikiGraphConversionManager = class {
|
|
|
1249
1367
|
requiresDigest
|
|
1250
1368
|
);
|
|
1251
1369
|
let chapterCount;
|
|
1370
|
+
let chapterPaths;
|
|
1252
1371
|
const write = async (archive) => {
|
|
1253
1372
|
if (requiresDigest) await options.onSourceImported?.();
|
|
1254
1373
|
if (typeof archive.readToc === "function") {
|
|
1255
1374
|
const toc = await archive.readToc();
|
|
1256
1375
|
chapterCount = toc === void 0 ? void 0 : countTocChapters(toc.items);
|
|
1376
|
+
if (options.output.format === "wikg") {
|
|
1377
|
+
chapterPaths = toc === void 0 ? [] : collectTocChapterPaths(toc.items);
|
|
1378
|
+
}
|
|
1257
1379
|
}
|
|
1258
1380
|
await writeArchive(archive, options.output.path, options.output.format);
|
|
1259
1381
|
};
|
|
@@ -1262,7 +1384,9 @@ var WikiGraphConversionManager = class {
|
|
|
1262
1384
|
throw new Error("wikg input requires a file path.");
|
|
1263
1385
|
}
|
|
1264
1386
|
await app.openSession(
|
|
1265
|
-
new NodeFile(
|
|
1387
|
+
new NodeFile(
|
|
1388
|
+
await assertStandaloneWikiGraphArchivePath(options.input.path)
|
|
1389
|
+
),
|
|
1266
1390
|
write
|
|
1267
1391
|
);
|
|
1268
1392
|
} else if ("stream" in options.input) {
|
|
@@ -1305,6 +1429,7 @@ var WikiGraphConversionManager = class {
|
|
|
1305
1429
|
const sourceArtifact = await resolveSourceArtifact(options.input);
|
|
1306
1430
|
return {
|
|
1307
1431
|
...chapterCount === void 0 ? {} : { chapterCount },
|
|
1432
|
+
...chapterPaths === void 0 ? {} : { chapterPaths },
|
|
1308
1433
|
inputFormat: options.input.format,
|
|
1309
1434
|
outputFormat: options.output.format,
|
|
1310
1435
|
outputPath: options.output.path,
|
|
@@ -1321,7 +1446,8 @@ async function prepareDigestDirectory(path, required) {
|
|
|
1321
1446
|
return new NodeDirectory(resolved);
|
|
1322
1447
|
}
|
|
1323
1448
|
async function writeArchive(archive, path, format) {
|
|
1324
|
-
const
|
|
1449
|
+
const outputPath = format === "wikg" ? await assertStandaloneWikiGraphArchivePath(path) : resolveWikiGraphRuntimePath(path);
|
|
1450
|
+
const file = new NodeFile(outputPath);
|
|
1325
1451
|
if (format === "epub") await archive.exportEpub(file);
|
|
1326
1452
|
else if (format === "wikg") await archive.saveAs(file);
|
|
1327
1453
|
else if (format === "pcex") throw new Error("pcex output is not supported.");
|
|
@@ -1350,7 +1476,7 @@ async function resolveSourceArtifact(input) {
|
|
|
1350
1476
|
return {
|
|
1351
1477
|
digest: hash.digest("hex"),
|
|
1352
1478
|
mediaType: "application/epub+zip",
|
|
1353
|
-
name:
|
|
1479
|
+
name: basename3(path)
|
|
1354
1480
|
};
|
|
1355
1481
|
}
|
|
1356
1482
|
function isNodeErrorCode(error, code) {
|
|
@@ -1366,6 +1492,21 @@ function countTocChapters(items) {
|
|
|
1366
1492
|
}
|
|
1367
1493
|
return count;
|
|
1368
1494
|
}
|
|
1495
|
+
function collectTocChapterPaths(items, ancestorKeys = []) {
|
|
1496
|
+
const paths = [];
|
|
1497
|
+
for (const item of items) {
|
|
1498
|
+
const key = item.key ?? `chapter-${item.serialId ?? "group"}`;
|
|
1499
|
+
const chapterPath = [...ancestorKeys, key];
|
|
1500
|
+
if (item.serialId !== void 0) paths.push(chapterPath.join("/"));
|
|
1501
|
+
paths.push(
|
|
1502
|
+
...collectTocChapterPaths(
|
|
1503
|
+
item.children,
|
|
1504
|
+
chapterPath
|
|
1505
|
+
)
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
return paths;
|
|
1509
|
+
}
|
|
1369
1510
|
export {
|
|
1370
1511
|
WikiGraphConversionManager
|
|
1371
1512
|
};
|