gutterpress 0.11.19-alpha.1 → 0.11.19-alpha.3
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/dist/api/index.js +1 -1
- package/dist/{build-vgz3pr8y.js → build-6631d323.js} +3 -3
- package/dist/checks/source/character-table.d.ts +63 -0
- package/dist/checks/source/characters.d.ts +1 -0
- package/dist/checks/source/index.d.ts +1 -0
- package/dist/{cli-5j0a5hmc.js → cli-1b65ntcd.js} +1 -1
- package/dist/{cli-mkn97gxp.js → cli-4m7sgga3.js} +322 -159
- package/dist/{cli-n3nd3sav.js → cli-zpawttnh.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-gxf8ty3n.js → doctor-vw0a32kd.js} +2 -2
- package/dist/{ext-7j388f5z.js → ext-7t9fgc3x.js} +3 -3
- package/dist/{index-n4ek1358.js → index-bja72kwa.js} +326 -163
- package/dist/index.js +1 -1
- package/dist/{new-0wyn55dn.js → new-b7nz21pm.js} +3 -3
- package/dist/{preflight-re9v4skc.js → preflight-00vckfwg.js} +3 -3
- package/dist/{preview-2x113vyc.js → preview-mjmnnnpp.js} +3 -3
- package/dist/{publish-r379k1hr.js → publish-qkz561hp.js} +3 -3
- package/dist/{validate-fje7ca9g.js → validate-nwet2ksq.js} +6 -5
- package/package.json +1 -1
|
@@ -5984,7 +5984,7 @@ import git from "isomorphic-git";
|
|
|
5984
5984
|
// package.json
|
|
5985
5985
|
var package_default = {
|
|
5986
5986
|
name: "gutterpress",
|
|
5987
|
-
version: "0.11.19-alpha.
|
|
5987
|
+
version: "0.11.19-alpha.3",
|
|
5988
5988
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
5989
5989
|
author: "itlackey",
|
|
5990
5990
|
license: "MPL-2.0",
|
|
@@ -9262,11 +9262,174 @@ var check27 = {
|
|
|
9262
9262
|
};
|
|
9263
9263
|
registerCheck(check27);
|
|
9264
9264
|
|
|
9265
|
+
// src/checks/source/characters.ts
|
|
9266
|
+
import { readFile as readFile24 } from "node:fs/promises";
|
|
9267
|
+
|
|
9268
|
+
// src/checks/source/character-table.ts
|
|
9269
|
+
var CHARACTER_PATTERN = new RegExp("[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u00A0\\u00AD\\u00B4\\u02BC" + "\\u061C\\u2000-\\u2015\\u2018\\u2019\\u201B-\\u201D\\u201F\\u2022\\u2026" + "\\u2028-\\u202F\\u2032\\u2033\\u205F\\u2060\\u2066-\\u2069\\u2190\\u2192" + "\\u2194\\u21D2\\u2212\\u25AA\\u25E6\\u2605\\u2713\\u2714\\u2717\\u3000" + "\\uE000-\\uF8FF\\uFEFF\\uFF02\\uFF07\\uFFFD]" + "|\\p{Emoji_Presentation}|\\p{Extended_Pictographic}(?=\\uFE0F)", "gu");
|
|
9270
|
+
var NAMED = {
|
|
9271
|
+
8212: ["Em dash", "typographer", "---"],
|
|
9272
|
+
8211: ["En dash", "typographer", "--"],
|
|
9273
|
+
8220: ["Opening curly quote", "typographer", '"'],
|
|
9274
|
+
8221: ["Closing curly quote", "typographer", '"'],
|
|
9275
|
+
8216: ["Opening curly single quote", "typographer", "'"],
|
|
9276
|
+
8217: ["Curly apostrophe", "typographer", "'"],
|
|
9277
|
+
8230: ["Ellipsis character", "typographer", "..."],
|
|
9278
|
+
700: ["Modifier-letter apostrophe", "lookalike", "'"],
|
|
9279
|
+
180: ["Acute accent", "lookalike", "'"],
|
|
9280
|
+
8242: ["Prime", "lookalike", "'"],
|
|
9281
|
+
8243: ["Double prime", "lookalike", '"'],
|
|
9282
|
+
8219: ["Reversed single quote", "lookalike", "'"],
|
|
9283
|
+
8223: ["Reversed double quote", "lookalike", '"'],
|
|
9284
|
+
65282: ["Full-width quote", "lookalike", '"'],
|
|
9285
|
+
65287: ["Full-width apostrophe", "lookalike", "'"],
|
|
9286
|
+
8208: ["Unicode hyphen", "lookalike", "-"],
|
|
9287
|
+
8209: ["Non-breaking hyphen", "lookalike", "-"],
|
|
9288
|
+
8210: ["Figure dash", "lookalike", "-"],
|
|
9289
|
+
8213: ["Horizontal bar", "lookalike", "---"],
|
|
9290
|
+
8722: ["Minus sign", "lookalike", "-"],
|
|
9291
|
+
8226: ["Bullet", "symbol", "•"],
|
|
9292
|
+
9702: ["White bullet", "symbol", "◦"],
|
|
9293
|
+
9642: ["Small square", "symbol", "▪"],
|
|
9294
|
+
8594: ["Right arrow", "symbol", "→"],
|
|
9295
|
+
8592: ["Left arrow", "symbol", "←"],
|
|
9296
|
+
8596: ["Left-right arrow", "symbol", "↔"],
|
|
9297
|
+
8658: ["Double right arrow", "symbol", "⇒"],
|
|
9298
|
+
10003: ["Check mark", "symbol", "✓"],
|
|
9299
|
+
10004: ["Heavy check mark", "symbol", "✔"],
|
|
9300
|
+
10007: ["Ballot X", "symbol", "✗"],
|
|
9301
|
+
9733: ["Star", "symbol", "★"],
|
|
9302
|
+
8203: ["Zero-width space", "invisible", "​"],
|
|
9303
|
+
8288: ["Word joiner", "invisible", "⁠"],
|
|
9304
|
+
65279: ["Byte-order mark", "invisible"],
|
|
9305
|
+
173: ["Soft hyphen", "invisible", "­"],
|
|
9306
|
+
8204: ["Zero-width non-joiner", "invisible", "‌"],
|
|
9307
|
+
8205: ["Zero-width joiner", "invisible", "‍"],
|
|
9308
|
+
8206: ["Left-to-right mark", "invisible", "‎"],
|
|
9309
|
+
8207: ["Right-to-left mark", "invisible", "‏"],
|
|
9310
|
+
1564: ["Arabic letter mark", "invisible", "؜"],
|
|
9311
|
+
8234: ["Left-to-right embedding", "invisible", "‪"],
|
|
9312
|
+
8235: ["Right-to-left embedding", "invisible", "‫"],
|
|
9313
|
+
8236: ["Pop directional formatting", "invisible", "‬"],
|
|
9314
|
+
8237: ["Left-to-right override", "invisible", "‭"],
|
|
9315
|
+
8238: ["Right-to-left override", "invisible", "‮"],
|
|
9316
|
+
8294: ["Left-to-right isolate", "invisible", "⁦"],
|
|
9317
|
+
8295: ["Right-to-left isolate", "invisible", "⁧"],
|
|
9318
|
+
8296: ["First-strong isolate", "invisible", "⁨"],
|
|
9319
|
+
8297: ["Pop directional isolate", "invisible", "⁩"],
|
|
9320
|
+
8232: ["Line separator", "invisible"],
|
|
9321
|
+
8233: ["Paragraph separator", "invisible"],
|
|
9322
|
+
160: ["Non-breaking space", "whitespace", " "],
|
|
9323
|
+
8192: ["En quad", "whitespace", " "],
|
|
9324
|
+
8193: ["Em quad", "whitespace", " "],
|
|
9325
|
+
8194: ["En space", "whitespace", " "],
|
|
9326
|
+
8195: ["Em space", "whitespace", " "],
|
|
9327
|
+
8196: ["Three-per-em space", "whitespace", " "],
|
|
9328
|
+
8197: ["Four-per-em space", "whitespace", " "],
|
|
9329
|
+
8198: ["Six-per-em space", "whitespace", " "],
|
|
9330
|
+
8199: ["Figure space", "whitespace", " "],
|
|
9331
|
+
8200: ["Punctuation space", "whitespace", " "],
|
|
9332
|
+
8201: ["Thin space", "whitespace", " "],
|
|
9333
|
+
8202: ["Hair space", "whitespace", " "],
|
|
9334
|
+
8239: ["Narrow non-breaking space", "whitespace", " "],
|
|
9335
|
+
8287: ["Medium mathematical space", "whitespace", " "],
|
|
9336
|
+
12288: ["Ideographic space", "whitespace", " "],
|
|
9337
|
+
65533: ["Replacement character", "replacement"]
|
|
9338
|
+
};
|
|
9339
|
+
function fixFor(code, spelling) {
|
|
9340
|
+
switch (code) {
|
|
9341
|
+
case "typographer":
|
|
9342
|
+
return `Type ${spelling} instead; it prints the same.`;
|
|
9343
|
+
case "lookalike":
|
|
9344
|
+
return `Type ${spelling} instead.`;
|
|
9345
|
+
case "whitespace":
|
|
9346
|
+
return `Type a space, or ${spelling} if you meant it.`;
|
|
9347
|
+
case "symbol":
|
|
9348
|
+
case "invisible":
|
|
9349
|
+
return spelling ? `Delete it, or type ${spelling} if you meant it.` : "Delete it.";
|
|
9350
|
+
case "control":
|
|
9351
|
+
return "Delete it; it does not print.";
|
|
9352
|
+
case "replacement":
|
|
9353
|
+
return "Retype the character that was lost here.";
|
|
9354
|
+
case "private-use":
|
|
9355
|
+
return "Replace it with the character you meant; this one only shows in the font it came from.";
|
|
9356
|
+
}
|
|
9357
|
+
}
|
|
9358
|
+
function info2(name, code, spelling) {
|
|
9359
|
+
return { name, code, fix: fixFor(code, spelling) };
|
|
9360
|
+
}
|
|
9361
|
+
function describeCharacter(char) {
|
|
9362
|
+
const cp2 = char.codePointAt(0);
|
|
9363
|
+
const named = NAMED[cp2];
|
|
9364
|
+
if (named)
|
|
9365
|
+
return info2(...named);
|
|
9366
|
+
if (cp2 <= 159)
|
|
9367
|
+
return info2("Control character", "control");
|
|
9368
|
+
if (cp2 >= 57344 && cp2 <= 63743)
|
|
9369
|
+
return info2("Private-use character", "private-use");
|
|
9370
|
+
return info2("Emoji", "symbol", `&#x${cp2.toString(16).toUpperCase()};`);
|
|
9371
|
+
}
|
|
9372
|
+
function codePointLabel(char) {
|
|
9373
|
+
return `U+${char.codePointAt(0).toString(16).toUpperCase().padStart(4, "0")}`;
|
|
9374
|
+
}
|
|
9375
|
+
|
|
9376
|
+
// src/checks/source/characters.ts
|
|
9377
|
+
var PROBE = new RegExp(CHARACTER_PATTERN.source, "u");
|
|
9378
|
+
var check28 = {
|
|
9379
|
+
id: "source.characters",
|
|
9380
|
+
name: "Unusual Characters",
|
|
9381
|
+
description: "Finds invisible and control characters, odd spaces, and pasted typography (em dashes, curly quotes, emoji) in markdown",
|
|
9382
|
+
category: "source",
|
|
9383
|
+
phase: "pre-build",
|
|
9384
|
+
async run(ctx) {
|
|
9385
|
+
const results = [];
|
|
9386
|
+
for (const file of (ctx.markdownFiles ?? []).slice().sort()) {
|
|
9387
|
+
let content;
|
|
9388
|
+
try {
|
|
9389
|
+
content = await readFile24(file, "utf8");
|
|
9390
|
+
} catch {
|
|
9391
|
+
results.push(inspectionFailed(check28.id, `Could not read source file: ${file}`, { file }));
|
|
9392
|
+
continue;
|
|
9393
|
+
}
|
|
9394
|
+
if (!PROBE.test(content))
|
|
9395
|
+
continue;
|
|
9396
|
+
const lines = content.split(`
|
|
9397
|
+
`);
|
|
9398
|
+
let silencedLine = -1;
|
|
9399
|
+
for (let i = 0;i < lines.length; i++) {
|
|
9400
|
+
const line = lines[i];
|
|
9401
|
+
const comment = /^\s*<!--(.*)-->\s*$/.exec(line);
|
|
9402
|
+
if (comment && parseDisableDirective(comment[1])?.includes(check28.id)) {
|
|
9403
|
+
silencedLine = i + 1;
|
|
9404
|
+
continue;
|
|
9405
|
+
}
|
|
9406
|
+
if (i === silencedLine)
|
|
9407
|
+
continue;
|
|
9408
|
+
for (const match of line.matchAll(CHARACTER_PATTERN)) {
|
|
9409
|
+
const char = match[0];
|
|
9410
|
+
const { name, code, fix } = describeCharacter(char);
|
|
9411
|
+
results.push(finding(check28.id, {
|
|
9412
|
+
severity: "warning",
|
|
9413
|
+
code,
|
|
9414
|
+
message: `${name} (${codePointLabel(char)}). ${fix}`,
|
|
9415
|
+
file,
|
|
9416
|
+
line: i + 1,
|
|
9417
|
+
column: match.index + 1,
|
|
9418
|
+
data: { codePoint: char.codePointAt(0) }
|
|
9419
|
+
}));
|
|
9420
|
+
}
|
|
9421
|
+
}
|
|
9422
|
+
}
|
|
9423
|
+
return results;
|
|
9424
|
+
}
|
|
9425
|
+
};
|
|
9426
|
+
registerCheck(check28);
|
|
9427
|
+
|
|
9265
9428
|
// src/checks/asset/image-file-size.ts
|
|
9266
9429
|
import { stat as stat4 } from "node:fs/promises";
|
|
9267
9430
|
|
|
9268
9431
|
// src/lib/image-inspect.ts
|
|
9269
|
-
import { stat as stat3, readFile as
|
|
9432
|
+
import { stat as stat3, readFile as readFile25 } from "node:fs/promises";
|
|
9270
9433
|
var DEFAULT_DPI = 72;
|
|
9271
9434
|
var cache = new Map;
|
|
9272
9435
|
async function inspectImage(path13) {
|
|
@@ -9279,15 +9442,15 @@ async function inspectImage(path13) {
|
|
|
9279
9442
|
const hit = cache.get(path13);
|
|
9280
9443
|
if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size)
|
|
9281
9444
|
return hit.info;
|
|
9282
|
-
let
|
|
9445
|
+
let info3 = null;
|
|
9283
9446
|
try {
|
|
9284
|
-
const buf = await
|
|
9285
|
-
|
|
9447
|
+
const buf = await readFile25(path13);
|
|
9448
|
+
info3 = parseImage(buf);
|
|
9286
9449
|
} catch {
|
|
9287
|
-
|
|
9450
|
+
info3 = null;
|
|
9288
9451
|
}
|
|
9289
|
-
cache.set(path13, { mtimeMs: st.mtimeMs, size: st.size, info:
|
|
9290
|
-
return
|
|
9452
|
+
cache.set(path13, { mtimeMs: st.mtimeMs, size: st.size, info: info3 });
|
|
9453
|
+
return info3;
|
|
9291
9454
|
}
|
|
9292
9455
|
function parseImage(b) {
|
|
9293
9456
|
if (b.length > 8 && b[0] === 137 && b[1] === 80 && b[2] === 78 && b[3] === 71) {
|
|
@@ -9486,7 +9649,7 @@ async function collectImageFiles(dirs, exts, ignore2 = ASSET_SCAN_IGNORE_GLOBS)
|
|
|
9486
9649
|
}
|
|
9487
9650
|
|
|
9488
9651
|
// src/checks/asset/image-file-size.ts
|
|
9489
|
-
var
|
|
9652
|
+
var check29 = {
|
|
9490
9653
|
id: "asset.image.file-size",
|
|
9491
9654
|
name: "Image File Size",
|
|
9492
9655
|
description: "Checks that image files do not exceed the maximum size limit",
|
|
@@ -9503,18 +9666,18 @@ var check28 = {
|
|
|
9503
9666
|
const results = [];
|
|
9504
9667
|
for (const file of files) {
|
|
9505
9668
|
try {
|
|
9506
|
-
const
|
|
9507
|
-
if (
|
|
9508
|
-
const sizeMb = (
|
|
9669
|
+
const info3 = await stat4(file);
|
|
9670
|
+
if (info3.size > maxSize) {
|
|
9671
|
+
const sizeMb = (info3.size / 1e6).toFixed(1);
|
|
9509
9672
|
const maxMb = (maxSize / 1e6).toFixed(1);
|
|
9510
|
-
results.push(finding(
|
|
9673
|
+
results.push(finding(check29.id, {
|
|
9511
9674
|
severity: "warning",
|
|
9512
9675
|
message: `Image file too large: ${sizeMb}MB (max ${maxMb}MB)`,
|
|
9513
9676
|
file
|
|
9514
9677
|
}));
|
|
9515
9678
|
}
|
|
9516
9679
|
} catch {
|
|
9517
|
-
results.push(inspectionFailed(
|
|
9680
|
+
results.push(inspectionFailed(check29.id, `Could not stat image file: ${file}`, {
|
|
9518
9681
|
file
|
|
9519
9682
|
}));
|
|
9520
9683
|
}
|
|
@@ -9522,10 +9685,10 @@ var check28 = {
|
|
|
9522
9685
|
return results;
|
|
9523
9686
|
}
|
|
9524
9687
|
};
|
|
9525
|
-
registerCheck(
|
|
9688
|
+
registerCheck(check29);
|
|
9526
9689
|
|
|
9527
9690
|
// src/checks/asset/image-resolution.ts
|
|
9528
|
-
var
|
|
9691
|
+
var check30 = {
|
|
9529
9692
|
id: "asset.image.resolution",
|
|
9530
9693
|
name: "Image Resolution",
|
|
9531
9694
|
description: "Checks source image DPI from embedded density metadata",
|
|
@@ -9541,13 +9704,13 @@ var check29 = {
|
|
|
9541
9704
|
return [];
|
|
9542
9705
|
const results = [];
|
|
9543
9706
|
for (const file of files) {
|
|
9544
|
-
const
|
|
9545
|
-
if (!
|
|
9707
|
+
const info3 = await inspectImage(file);
|
|
9708
|
+
if (!info3)
|
|
9546
9709
|
continue;
|
|
9547
|
-
const { xDpi, yDpi } =
|
|
9710
|
+
const { xDpi, yDpi } = info3;
|
|
9548
9711
|
if (xDpi > 0 && yDpi > 0 && (xDpi < minDpi || yDpi < minDpi)) {
|
|
9549
9712
|
results.push({
|
|
9550
|
-
checkId:
|
|
9713
|
+
checkId: check30.id,
|
|
9551
9714
|
severity: "warning",
|
|
9552
9715
|
message: `Image resolution too low: ${xDpi}x${yDpi} DPI (minimum ${minDpi} DPI)`,
|
|
9553
9716
|
file
|
|
@@ -9557,7 +9720,7 @@ var check29 = {
|
|
|
9557
9720
|
return results;
|
|
9558
9721
|
}
|
|
9559
9722
|
};
|
|
9560
|
-
registerCheck(
|
|
9723
|
+
registerCheck(check30);
|
|
9561
9724
|
|
|
9562
9725
|
// src/checks/asset/image-color-space.ts
|
|
9563
9726
|
var LABEL = {
|
|
@@ -9565,7 +9728,7 @@ var LABEL = {
|
|
|
9565
9728
|
gray: "Gray",
|
|
9566
9729
|
cmyk: "CMYK"
|
|
9567
9730
|
};
|
|
9568
|
-
var
|
|
9731
|
+
var check31 = {
|
|
9569
9732
|
id: "asset.image.color-space",
|
|
9570
9733
|
name: "Image Color Space",
|
|
9571
9734
|
description: "Validates image color spaces against allowed list",
|
|
@@ -9582,11 +9745,11 @@ var check30 = {
|
|
|
9582
9745
|
const allowedLower = new Set(allowed.map((s) => s.toLowerCase()));
|
|
9583
9746
|
const results = [];
|
|
9584
9747
|
for (const file of files) {
|
|
9585
|
-
const
|
|
9586
|
-
const cs =
|
|
9748
|
+
const info3 = await inspectImage(file);
|
|
9749
|
+
const cs = info3?.colorSpace;
|
|
9587
9750
|
if (cs && !allowedLower.has(cs)) {
|
|
9588
9751
|
results.push({
|
|
9589
|
-
checkId:
|
|
9752
|
+
checkId: check31.id,
|
|
9590
9753
|
severity: "warning",
|
|
9591
9754
|
message: `Image uses ${LABEL[cs] ?? cs} color space (allowed: ${allowed.join(", ")})`,
|
|
9592
9755
|
file
|
|
@@ -9596,10 +9759,10 @@ var check30 = {
|
|
|
9596
9759
|
return results;
|
|
9597
9760
|
}
|
|
9598
9761
|
};
|
|
9599
|
-
registerCheck(
|
|
9762
|
+
registerCheck(check31);
|
|
9600
9763
|
|
|
9601
9764
|
// src/checks/asset/image-alpha.ts
|
|
9602
|
-
var
|
|
9765
|
+
var check32 = {
|
|
9603
9766
|
id: "asset.image.alpha-channel",
|
|
9604
9767
|
name: "Image Alpha Channel",
|
|
9605
9768
|
description: "Checks for alpha channels in PNG/TIFF images",
|
|
@@ -9614,10 +9777,10 @@ var check31 = {
|
|
|
9614
9777
|
return [];
|
|
9615
9778
|
const results = [];
|
|
9616
9779
|
for (const file of files) {
|
|
9617
|
-
const
|
|
9618
|
-
if (
|
|
9780
|
+
const info3 = await inspectImage(file);
|
|
9781
|
+
if (info3?.hasAlpha) {
|
|
9619
9782
|
results.push({
|
|
9620
|
-
checkId:
|
|
9783
|
+
checkId: check32.id,
|
|
9621
9784
|
severity: "warning",
|
|
9622
9785
|
message: "Image contains alpha channel, which may cause print issues",
|
|
9623
9786
|
file
|
|
@@ -9627,10 +9790,10 @@ var check31 = {
|
|
|
9627
9790
|
return results;
|
|
9628
9791
|
}
|
|
9629
9792
|
};
|
|
9630
|
-
registerCheck(
|
|
9793
|
+
registerCheck(check32);
|
|
9631
9794
|
|
|
9632
9795
|
// src/checks/asset/image-tac.ts
|
|
9633
|
-
var
|
|
9796
|
+
var check33 = {
|
|
9634
9797
|
id: "asset.image.tac-raster",
|
|
9635
9798
|
name: "Image TAC (Raster)",
|
|
9636
9799
|
description: "Rasterizes and checks TAC per image using Ghostscript",
|
|
@@ -9649,7 +9812,7 @@ var check32 = {
|
|
|
9649
9812
|
const ghostscript = await resolveGhostscript();
|
|
9650
9813
|
if (!ghostscript) {
|
|
9651
9814
|
return [
|
|
9652
|
-
inspectionFailed(
|
|
9815
|
+
inspectionFailed(check33.id, "Could not inspect image ink coverage: Ghostscript executable not found")
|
|
9653
9816
|
];
|
|
9654
9817
|
}
|
|
9655
9818
|
for (const file of files) {
|
|
@@ -9667,7 +9830,7 @@ var check32 = {
|
|
|
9667
9830
|
if (nums.length === 4 && nums.every((n) => Number.isFinite(n))) {
|
|
9668
9831
|
const tac = (nums[0] + nums[1] + nums[2] + nums[3]) * 100;
|
|
9669
9832
|
if (tac > maxTac) {
|
|
9670
|
-
results.push(finding(
|
|
9833
|
+
results.push(finding(check33.id, {
|
|
9671
9834
|
severity: "warning",
|
|
9672
9835
|
message: `Image TAC exceeds limit: ${tac.toFixed(1)}% (max ${maxTac}%)`,
|
|
9673
9836
|
file,
|
|
@@ -9679,16 +9842,16 @@ var check32 = {
|
|
|
9679
9842
|
}
|
|
9680
9843
|
}
|
|
9681
9844
|
} catch {
|
|
9682
|
-
results.push(inspectionFailed(
|
|
9845
|
+
results.push(inspectionFailed(check33.id, `Could not inspect image ink coverage: ${file}`, { file }));
|
|
9683
9846
|
}
|
|
9684
9847
|
}
|
|
9685
9848
|
return results;
|
|
9686
9849
|
}
|
|
9687
9850
|
};
|
|
9688
|
-
registerCheck(
|
|
9851
|
+
registerCheck(check33);
|
|
9689
9852
|
|
|
9690
9853
|
// src/checks/asset/approved-fonts.ts
|
|
9691
|
-
var
|
|
9854
|
+
var check34 = {
|
|
9692
9855
|
id: "asset.font.approved-files",
|
|
9693
9856
|
name: "Approved Font Files",
|
|
9694
9857
|
description: "Checks font files against the approved file patterns",
|
|
@@ -9727,7 +9890,7 @@ var check33 = {
|
|
|
9727
9890
|
for (const font of allFonts) {
|
|
9728
9891
|
if (!approvedFonts.has(font)) {
|
|
9729
9892
|
results.push({
|
|
9730
|
-
checkId:
|
|
9893
|
+
checkId: check34.id,
|
|
9731
9894
|
severity: "warning",
|
|
9732
9895
|
message: "Font file not in approved list",
|
|
9733
9896
|
file: font
|
|
@@ -9737,7 +9900,7 @@ var check33 = {
|
|
|
9737
9900
|
return results;
|
|
9738
9901
|
}
|
|
9739
9902
|
};
|
|
9740
|
-
registerCheck(
|
|
9903
|
+
registerCheck(check34);
|
|
9741
9904
|
|
|
9742
9905
|
// src/checks/asset/font-license.ts
|
|
9743
9906
|
import { existsSync as existsSync11 } from "node:fs";
|
|
@@ -9752,7 +9915,7 @@ var LICENSE_NAMES = [
|
|
|
9752
9915
|
"OFL-1.1.txt",
|
|
9753
9916
|
"COPYING"
|
|
9754
9917
|
];
|
|
9755
|
-
var
|
|
9918
|
+
var check35 = {
|
|
9756
9919
|
id: "asset.font.license",
|
|
9757
9920
|
name: "Font License",
|
|
9758
9921
|
description: "Checks for license files in font directories",
|
|
@@ -9779,7 +9942,7 @@ var check34 = {
|
|
|
9779
9942
|
const hasLicense = LICENSE_NAMES.some((name) => existsSync11(resolve7(fontDir, name)));
|
|
9780
9943
|
if (!hasLicense) {
|
|
9781
9944
|
results.push({
|
|
9782
|
-
checkId:
|
|
9945
|
+
checkId: check35.id,
|
|
9783
9946
|
severity: "warning",
|
|
9784
9947
|
message: `No font license file found in directory`,
|
|
9785
9948
|
file: fontDir
|
|
@@ -9789,10 +9952,10 @@ var check34 = {
|
|
|
9789
9952
|
return results;
|
|
9790
9953
|
}
|
|
9791
9954
|
};
|
|
9792
|
-
registerCheck(
|
|
9955
|
+
registerCheck(check35);
|
|
9793
9956
|
|
|
9794
9957
|
// src/checks/heuristic/text-density.ts
|
|
9795
|
-
var
|
|
9958
|
+
var check36 = {
|
|
9796
9959
|
id: "heuristic.whitespace.text-density",
|
|
9797
9960
|
name: "Text Density",
|
|
9798
9961
|
description: "Checks characters-per-page ratio",
|
|
@@ -9821,7 +9984,7 @@ var check35 = {
|
|
|
9821
9984
|
});
|
|
9822
9985
|
if (lowPages.length > 0) {
|
|
9823
9986
|
results.push({
|
|
9824
|
-
checkId:
|
|
9987
|
+
checkId: check36.id,
|
|
9825
9988
|
severity: "info",
|
|
9826
9989
|
message: `Low text density on pages: ${lowPages.join(", ")} (below ${range.min} chars)`,
|
|
9827
9990
|
file: ctx.pdfPath
|
|
@@ -9829,7 +9992,7 @@ var check35 = {
|
|
|
9829
9992
|
}
|
|
9830
9993
|
if (highPages.length > 0) {
|
|
9831
9994
|
results.push({
|
|
9832
|
-
checkId:
|
|
9995
|
+
checkId: check36.id,
|
|
9833
9996
|
severity: "info",
|
|
9834
9997
|
message: `High text density on pages: ${highPages.join(", ")} (above ${range.max} chars)`,
|
|
9835
9998
|
file: ctx.pdfPath
|
|
@@ -9838,11 +10001,11 @@ var check35 = {
|
|
|
9838
10001
|
return results;
|
|
9839
10002
|
}
|
|
9840
10003
|
};
|
|
9841
|
-
registerCheck(
|
|
10004
|
+
registerCheck(check36);
|
|
9842
10005
|
|
|
9843
10006
|
// src/checks/heuristic/section-density.ts
|
|
9844
|
-
import { readFile as
|
|
9845
|
-
var
|
|
10007
|
+
import { readFile as readFile26 } from "node:fs/promises";
|
|
10008
|
+
var check37 = {
|
|
9846
10009
|
id: "heuristic.chunking.section-density",
|
|
9847
10010
|
name: "Section Density",
|
|
9848
10011
|
description: "Checks heading/paragraph/callout density from source Markdown",
|
|
@@ -9858,7 +10021,7 @@ var check36 = {
|
|
|
9858
10021
|
const results = [];
|
|
9859
10022
|
for (const file of files) {
|
|
9860
10023
|
try {
|
|
9861
|
-
const content = await
|
|
10024
|
+
const content = await readFile26(file, "utf8");
|
|
9862
10025
|
const lines = content.split(`
|
|
9863
10026
|
`);
|
|
9864
10027
|
let currentSectionStart = 0;
|
|
@@ -9868,7 +10031,7 @@ var check36 = {
|
|
|
9868
10031
|
const line = lines[i];
|
|
9869
10032
|
if (/^#{1,6}\s/.test(line)) {
|
|
9870
10033
|
if (paragraphCount > maxParas) {
|
|
9871
|
-
results.push(finding(
|
|
10034
|
+
results.push(finding(check37.id, {
|
|
9872
10035
|
severity: "info",
|
|
9873
10036
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
9874
10037
|
file,
|
|
@@ -9888,7 +10051,7 @@ var check36 = {
|
|
|
9888
10051
|
}
|
|
9889
10052
|
}
|
|
9890
10053
|
if (paragraphCount > maxParas) {
|
|
9891
|
-
results.push(finding(
|
|
10054
|
+
results.push(finding(check37.id, {
|
|
9892
10055
|
severity: "info",
|
|
9893
10056
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
9894
10057
|
file,
|
|
@@ -9896,7 +10059,7 @@ var check36 = {
|
|
|
9896
10059
|
}));
|
|
9897
10060
|
}
|
|
9898
10061
|
} catch {
|
|
9899
|
-
results.push(inspectionFailed(
|
|
10062
|
+
results.push(inspectionFailed(check37.id, `Could not read source file: ${file}`, {
|
|
9900
10063
|
file
|
|
9901
10064
|
}));
|
|
9902
10065
|
}
|
|
@@ -9904,10 +10067,10 @@ var check36 = {
|
|
|
9904
10067
|
return results;
|
|
9905
10068
|
}
|
|
9906
10069
|
};
|
|
9907
|
-
registerCheck(
|
|
10070
|
+
registerCheck(check37);
|
|
9908
10071
|
|
|
9909
10072
|
// src/checks/heuristic/layer-count.ts
|
|
9910
|
-
var
|
|
10073
|
+
var check38 = {
|
|
9911
10074
|
id: "heuristic.decoration.layer-count",
|
|
9912
10075
|
name: "Layer Count",
|
|
9913
10076
|
description: "Counts image objects per page",
|
|
@@ -9932,7 +10095,7 @@ var check37 = {
|
|
|
9932
10095
|
heavyPages.sort((a, b) => a - b);
|
|
9933
10096
|
return [
|
|
9934
10097
|
{
|
|
9935
|
-
checkId:
|
|
10098
|
+
checkId: check38.id,
|
|
9936
10099
|
severity: "info",
|
|
9937
10100
|
message: `Pages with many image layers (>${maxLayers}): ${heavyPages.join(", ")}`,
|
|
9938
10101
|
file: ctx.pdfPath
|
|
@@ -9942,10 +10105,10 @@ var check37 = {
|
|
|
9942
10105
|
return [];
|
|
9943
10106
|
}
|
|
9944
10107
|
};
|
|
9945
|
-
registerCheck(
|
|
10108
|
+
registerCheck(check38);
|
|
9946
10109
|
|
|
9947
10110
|
// src/checks/heuristic/placement-variance.ts
|
|
9948
|
-
var
|
|
10111
|
+
var check39 = {
|
|
9949
10112
|
id: "heuristic.layout.placement-variance",
|
|
9950
10113
|
name: "Placement Variance",
|
|
9951
10114
|
description: "Analyzes text baseline coordinates for layout consistency",
|
|
@@ -9963,7 +10126,7 @@ var check38 = {
|
|
|
9963
10126
|
const uniqueX = new Set(positions.map((p) => Math.round(p.x)));
|
|
9964
10127
|
return [
|
|
9965
10128
|
{
|
|
9966
|
-
checkId:
|
|
10129
|
+
checkId: check39.id,
|
|
9967
10130
|
severity: "info",
|
|
9968
10131
|
message: `Layout analysis: ${uniqueX.size} unique horizontal text positions across ${positions.length} text blocks.`,
|
|
9969
10132
|
file: ctx.pdfPath
|
|
@@ -9971,7 +10134,7 @@ var check38 = {
|
|
|
9971
10134
|
];
|
|
9972
10135
|
}
|
|
9973
10136
|
};
|
|
9974
|
-
registerCheck(
|
|
10137
|
+
registerCheck(check39);
|
|
9975
10138
|
|
|
9976
10139
|
// src/checks/runner.ts
|
|
9977
10140
|
function getCheckSeverityOverride(checkId, config) {
|
|
@@ -10001,16 +10164,16 @@ async function runChecks(ctx, opts = {}) {
|
|
|
10001
10164
|
}
|
|
10002
10165
|
const release = retainPdfCache();
|
|
10003
10166
|
try {
|
|
10004
|
-
for (const
|
|
10167
|
+
for (const check40 of checks2) {
|
|
10005
10168
|
try {
|
|
10006
|
-
let results = await
|
|
10007
|
-
const severityOverride = getCheckSeverityOverride(
|
|
10169
|
+
let results = await check40.run(ctx);
|
|
10170
|
+
const severityOverride = getCheckSeverityOverride(check40.id, ctx.config);
|
|
10008
10171
|
if (severityOverride) {
|
|
10009
10172
|
for (const r of results) {
|
|
10010
10173
|
r.severity = severityOverride;
|
|
10011
10174
|
}
|
|
10012
10175
|
}
|
|
10013
|
-
const lintLevel = ruleLevel(ctx.config.lint.rules,
|
|
10176
|
+
const lintLevel = ruleLevel(ctx.config.lint.rules, check40.id);
|
|
10014
10177
|
if (lintLevel === "off")
|
|
10015
10178
|
results = [];
|
|
10016
10179
|
else if (lintLevel) {
|
|
@@ -10018,15 +10181,15 @@ async function runChecks(ctx, opts = {}) {
|
|
|
10018
10181
|
r.severity = lintLevel === "warn" ? "warning" : "error";
|
|
10019
10182
|
}
|
|
10020
10183
|
if (results.length === 0) {
|
|
10021
|
-
passed.push(
|
|
10184
|
+
passed.push(check40.id);
|
|
10022
10185
|
} else {
|
|
10023
10186
|
allResults.push(...results);
|
|
10024
10187
|
}
|
|
10025
10188
|
} catch (err) {
|
|
10026
10189
|
allResults.push({
|
|
10027
|
-
checkId:
|
|
10190
|
+
checkId: check40.id,
|
|
10028
10191
|
severity: "error",
|
|
10029
|
-
message: `Check "${
|
|
10192
|
+
message: `Check "${check40.id}" threw: ${err instanceof Error ? err.message : String(err)}`
|
|
10030
10193
|
});
|
|
10031
10194
|
}
|
|
10032
10195
|
}
|
|
@@ -10066,15 +10229,15 @@ function emptyReport() {
|
|
|
10066
10229
|
async function checkToolAvailability(config, opts = {}) {
|
|
10067
10230
|
const { checks: checks2 } = selectChecks(opts, config);
|
|
10068
10231
|
const toolToChecks = new Map;
|
|
10069
|
-
for (const
|
|
10070
|
-
if (!
|
|
10232
|
+
for (const check40 of checks2) {
|
|
10233
|
+
if (!check40.requiredTools?.length)
|
|
10071
10234
|
continue;
|
|
10072
|
-
for (const tool of
|
|
10235
|
+
for (const tool of check40.requiredTools) {
|
|
10073
10236
|
const existing = toolToChecks.get(tool);
|
|
10074
10237
|
if (existing) {
|
|
10075
|
-
existing.push(
|
|
10238
|
+
existing.push(check40.id);
|
|
10076
10239
|
} else {
|
|
10077
|
-
toolToChecks.set(tool, [
|
|
10240
|
+
toolToChecks.set(tool, [check40.id]);
|
|
10078
10241
|
}
|
|
10079
10242
|
}
|
|
10080
10243
|
}
|
|
@@ -10090,11 +10253,11 @@ async function checkToolAvailability(config, opts = {}) {
|
|
|
10090
10253
|
const missing = results.filter((r) => !r.found).map((r) => r.tool);
|
|
10091
10254
|
const missingSet = new Set(missing);
|
|
10092
10255
|
const skippedChecks = [];
|
|
10093
|
-
for (const
|
|
10094
|
-
if (!
|
|
10256
|
+
for (const check40 of checks2) {
|
|
10257
|
+
if (!check40.requiredTools?.length)
|
|
10095
10258
|
continue;
|
|
10096
|
-
if (
|
|
10097
|
-
skippedChecks.push(
|
|
10259
|
+
if (check40.requiredTools.some((t) => missingSet.has(t))) {
|
|
10260
|
+
skippedChecks.push(check40.id);
|
|
10098
10261
|
}
|
|
10099
10262
|
}
|
|
10100
10263
|
return { available, missing, skippedChecks, toolToChecks };
|
|
@@ -10367,7 +10530,7 @@ async function executeValidation(args) {
|
|
|
10367
10530
|
};
|
|
10368
10531
|
if (args.fix) {
|
|
10369
10532
|
const selected = selectChecks(runnerOptions, config).checks;
|
|
10370
|
-
if (selected.some((
|
|
10533
|
+
if (selected.some((check40) => check40.id === MARKDOWNLINT_CHECK_ID)) {
|
|
10371
10534
|
await applyMarkdownlintFixes(context);
|
|
10372
10535
|
} else {
|
|
10373
10536
|
log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
|
|
@@ -10850,7 +11013,7 @@ async function runBuild(opts) {
|
|
|
10850
11013
|
import path16 from "path";
|
|
10851
11014
|
import { tmpdir } from "os";
|
|
10852
11015
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
10853
|
-
import { readdir as readdir5, readFile as
|
|
11016
|
+
import { readdir as readdir5, readFile as readFile27, writeFile as writeFile6 } from "node:fs/promises";
|
|
10854
11017
|
|
|
10855
11018
|
// src/utils/file-utils.ts
|
|
10856
11019
|
import { promises as fs3 } from "fs";
|
|
@@ -11402,7 +11565,7 @@ async function cleanupOrphanTempDirs() {
|
|
|
11402
11565
|
const dir = path16.join(TEMP_DIR_BASE, entry);
|
|
11403
11566
|
const pidFile = path16.join(dir, PID_FILE_NAME);
|
|
11404
11567
|
try {
|
|
11405
|
-
const raw = await
|
|
11568
|
+
const raw = await readFile27(pidFile, "utf8");
|
|
11406
11569
|
const pid = parseInt(raw.trim(), 10);
|
|
11407
11570
|
if (!isProcessAlive(pid)) {
|
|
11408
11571
|
debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
|
|
@@ -11509,7 +11672,7 @@ function createServerState(inputPath, tempDir, config, options) {
|
|
|
11509
11672
|
import http from "node:http";
|
|
11510
11673
|
import net from "node:net";
|
|
11511
11674
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
11512
|
-
import { readFile as
|
|
11675
|
+
import { readFile as readFile28, stat as stat5 } from "node:fs/promises";
|
|
11513
11676
|
import path17 from "path";
|
|
11514
11677
|
import { WebSocket, WebSocketServer } from "ws";
|
|
11515
11678
|
|
|
@@ -11608,7 +11771,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
|
|
|
11608
11771
|
}
|
|
11609
11772
|
let data;
|
|
11610
11773
|
try {
|
|
11611
|
-
data = await
|
|
11774
|
+
data = await readFile28(filePath);
|
|
11612
11775
|
} catch {
|
|
11613
11776
|
res.writeHead(404);
|
|
11614
11777
|
res.end("Not Found");
|
|
@@ -11657,7 +11820,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11657
11820
|
let data;
|
|
11658
11821
|
if (!validator || validator.stamp !== stamp) {
|
|
11659
11822
|
try {
|
|
11660
|
-
data = await
|
|
11823
|
+
data = await readFile28(absPath);
|
|
11661
11824
|
} catch {
|
|
11662
11825
|
await serveStatic(absPath, res);
|
|
11663
11826
|
return;
|
|
@@ -11969,7 +12132,7 @@ async function startPreviewServer(options) {
|
|
|
11969
12132
|
import { platform, arch, release } from "node:os";
|
|
11970
12133
|
|
|
11971
12134
|
// src/lib/remote-auth/token-store.ts
|
|
11972
|
-
import { chmod, mkdir as mkdir7, readFile as
|
|
12135
|
+
import { chmod, mkdir as mkdir7, readFile as readFile29, rename as rename4, writeFile as writeFile7 } from "node:fs/promises";
|
|
11973
12136
|
import os3 from "node:os";
|
|
11974
12137
|
import path18 from "node:path";
|
|
11975
12138
|
function credentialHostKey(hostOrUrl) {
|
|
@@ -12013,7 +12176,7 @@ class FileTokenStore {
|
|
|
12013
12176
|
async read() {
|
|
12014
12177
|
let raw;
|
|
12015
12178
|
try {
|
|
12016
|
-
raw = await
|
|
12179
|
+
raw = await readFile29(this.filePath, "utf8");
|
|
12017
12180
|
} catch (e) {
|
|
12018
12181
|
if (e?.code === "ENOENT") {
|
|
12019
12182
|
return { version: 1, credentials: {} };
|
|
@@ -12213,13 +12376,13 @@ async function getSystemDiagnostics() {
|
|
|
12213
12376
|
};
|
|
12214
12377
|
}
|
|
12215
12378
|
// src/lib/project-scaffold.ts
|
|
12216
|
-
import { access, copyFile, cp as cp2, mkdir as mkdir9, readdir as readdir6, readFile as
|
|
12379
|
+
import { access, copyFile, cp as cp2, mkdir as mkdir9, readdir as readdir6, readFile as readFile31, stat as stat6, writeFile as writeFile9 } from "node:fs/promises";
|
|
12217
12380
|
import { constants as FS, existsSync as existsSync14 } from "node:fs";
|
|
12218
12381
|
import path20 from "node:path";
|
|
12219
12382
|
|
|
12220
12383
|
// src/lib/page-size.ts
|
|
12221
12384
|
import { existsSync as existsSync13 } from "node:fs";
|
|
12222
|
-
import { mkdir as mkdir8, readFile as
|
|
12385
|
+
import { mkdir as mkdir8, readFile as readFile30, writeFile as writeFile8 } from "node:fs/promises";
|
|
12223
12386
|
import path19 from "node:path";
|
|
12224
12387
|
import postcss5 from "postcss";
|
|
12225
12388
|
import { Scalar as Scalar2 } from "yaml";
|
|
@@ -12324,7 +12487,7 @@ var relDisplay2 = (projectDir, abs) => path19.relative(projectDir, abs).split(pa
|
|
|
12324
12487
|
async function findCssSize(projectDir, sheets) {
|
|
12325
12488
|
let found = null;
|
|
12326
12489
|
for (const file of sheets) {
|
|
12327
|
-
const size = readPageSizeFromCss(await
|
|
12490
|
+
const size = readPageSizeFromCss(await readFile30(file, "utf8"));
|
|
12328
12491
|
if (size)
|
|
12329
12492
|
found = { file, size };
|
|
12330
12493
|
}
|
|
@@ -12351,7 +12514,7 @@ async function setPageSetup(projectDir, choice) {
|
|
|
12351
12514
|
const found = await findCssSize(projectDir, sheets);
|
|
12352
12515
|
const newSheet = path19.join(projectDir, "styles", "book.css");
|
|
12353
12516
|
const target = found?.file ?? sheets[sheets.length - 1] ?? newSheet;
|
|
12354
|
-
const before = existsSync13(target) ? await
|
|
12517
|
+
const before = existsSync13(target) ? await readFile30(target, "utf8") : "";
|
|
12355
12518
|
let after;
|
|
12356
12519
|
try {
|
|
12357
12520
|
after = setPageSizeInCss(before, size);
|
|
@@ -12641,7 +12804,7 @@ styles:
|
|
|
12641
12804
|
async function firstSourceFile(manifestPath) {
|
|
12642
12805
|
let text;
|
|
12643
12806
|
try {
|
|
12644
|
-
text = await
|
|
12807
|
+
text = await readFile31(manifestPath, "utf8");
|
|
12645
12808
|
} catch {
|
|
12646
12809
|
return;
|
|
12647
12810
|
}
|
|
@@ -12653,14 +12816,14 @@ async function firstSourceFile(manifestPath) {
|
|
|
12653
12816
|
return m ? m[1].trim() : undefined;
|
|
12654
12817
|
}
|
|
12655
12818
|
async function fillTemplateFile(filePath, substitutions) {
|
|
12656
|
-
let text = await
|
|
12819
|
+
let text = await readFile31(filePath, "utf8");
|
|
12657
12820
|
for (const [token, value] of Object.entries(substitutions)) {
|
|
12658
12821
|
text = text.split(token).join(value);
|
|
12659
12822
|
}
|
|
12660
12823
|
await writeFile9(filePath, text, "utf8");
|
|
12661
12824
|
}
|
|
12662
12825
|
// src/lib/extension-scaffold.ts
|
|
12663
|
-
import { access as access2, mkdir as mkdir10, readFile as
|
|
12826
|
+
import { access as access2, mkdir as mkdir10, readFile as readFile32, writeFile as writeFile10 } from "node:fs/promises";
|
|
12664
12827
|
import { constants as FS2 } from "node:fs";
|
|
12665
12828
|
import path21 from "node:path";
|
|
12666
12829
|
var EXTENSION_KINDS = ["plugin", "theme"];
|
|
@@ -12777,7 +12940,7 @@ async function scaffoldExtension(options) {
|
|
|
12777
12940
|
const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
|
|
12778
12941
|
const dest = path21.join(extensionDir, relDest);
|
|
12779
12942
|
await mkdir10(path21.dirname(dest), { recursive: true });
|
|
12780
|
-
const text = await
|
|
12943
|
+
const text = await readFile32(src, "utf8");
|
|
12781
12944
|
const table = relDest.endsWith(".json") ? jsonSafe : plain;
|
|
12782
12945
|
await writeFile10(dest, substitute(text, table), "utf8");
|
|
12783
12946
|
written.push(relDest);
|
|
@@ -12803,7 +12966,7 @@ function substitute(text, table) {
|
|
|
12803
12966
|
return out;
|
|
12804
12967
|
}
|
|
12805
12968
|
// src/lib/project-templates.ts
|
|
12806
|
-
import { cp as cp3, mkdir as mkdir11, readFile as
|
|
12969
|
+
import { cp as cp3, mkdir as mkdir11, readFile as readFile33, readdir as readdir7, stat as stat7, writeFile as writeFile11 } from "node:fs/promises";
|
|
12807
12970
|
import { constants as FS3, existsSync as existsSync15 } from "node:fs";
|
|
12808
12971
|
import { access as access3 } from "node:fs/promises";
|
|
12809
12972
|
import path22 from "node:path";
|
|
@@ -12815,7 +12978,7 @@ var BUILT_IN_TEMPLATE_IDS = [
|
|
|
12815
12978
|
];
|
|
12816
12979
|
async function readTemplateChoices(manifestPath) {
|
|
12817
12980
|
try {
|
|
12818
|
-
const text = await
|
|
12981
|
+
const text = await readFile33(manifestPath, "utf8");
|
|
12819
12982
|
const doc = parseDocument2(text);
|
|
12820
12983
|
const out = {};
|
|
12821
12984
|
const preset = doc.get("preset");
|
|
@@ -12997,7 +13160,7 @@ async function saveProjectAsTemplate(options) {
|
|
|
12997
13160
|
async function retokeniseManifest(manifestPath) {
|
|
12998
13161
|
let text;
|
|
12999
13162
|
try {
|
|
13000
|
-
text = await
|
|
13163
|
+
text = await readFile33(manifestPath, "utf8");
|
|
13001
13164
|
} catch {
|
|
13002
13165
|
return;
|
|
13003
13166
|
}
|
|
@@ -13018,7 +13181,7 @@ async function listCustomTemplates(templatesRoot) {
|
|
|
13018
13181
|
const dir = path22.join(templatesRoot, entry.name);
|
|
13019
13182
|
let label = prettify(entry.name);
|
|
13020
13183
|
try {
|
|
13021
|
-
const meta = JSON.parse(await
|
|
13184
|
+
const meta = JSON.parse(await readFile33(path22.join(dir, TEMPLATE_META_FILE), "utf8"));
|
|
13022
13185
|
if (typeof meta.label === "string" && meta.label)
|
|
13023
13186
|
label = meta.label;
|
|
13024
13187
|
} catch {}
|
|
@@ -13044,7 +13207,7 @@ async function importTemplateFromFolder(options) {
|
|
|
13044
13207
|
return saveProjectAsTemplate({ projectDir: sourceDir, name, templatesRoot });
|
|
13045
13208
|
}
|
|
13046
13209
|
// src/lib/snippets.ts
|
|
13047
|
-
import { readdir as readdir8, readFile as
|
|
13210
|
+
import { readdir as readdir8, readFile as readFile34, writeFile as writeFile12, mkdir as mkdir12, rm as rm4 } from "node:fs/promises";
|
|
13048
13211
|
import path23 from "node:path";
|
|
13049
13212
|
var SNIPPETS_DIR = "snippets";
|
|
13050
13213
|
var LEVEL_RANK = { project: 0, extension: 1, core: 2 };
|
|
@@ -13085,7 +13248,7 @@ async function scanSnippetFiles(dir) {
|
|
|
13085
13248
|
continue;
|
|
13086
13249
|
let body = "";
|
|
13087
13250
|
try {
|
|
13088
|
-
body = await
|
|
13251
|
+
body = await readFile34(path23.join(dir, fileName), "utf8");
|
|
13089
13252
|
} catch {
|
|
13090
13253
|
continue;
|
|
13091
13254
|
}
|
|
@@ -13174,7 +13337,7 @@ async function collectLibrary(projectDir) {
|
|
|
13174
13337
|
listed.component = name;
|
|
13175
13338
|
continue;
|
|
13176
13339
|
}
|
|
13177
|
-
const body = await
|
|
13340
|
+
const body = await readFile34(path23.join(entry.dir, rel), "utf8").catch(() => null);
|
|
13178
13341
|
if (body === null)
|
|
13179
13342
|
continue;
|
|
13180
13343
|
snippets2.push({
|
|
@@ -13243,7 +13406,7 @@ async function listLocationVariants(projectDir) {
|
|
|
13243
13406
|
}
|
|
13244
13407
|
// src/lib/extension-import.ts
|
|
13245
13408
|
import { existsSync as existsSync16 } from "node:fs";
|
|
13246
|
-
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as
|
|
13409
|
+
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as readFile35, rm as rm5, writeFile as writeFile13 } from "node:fs/promises";
|
|
13247
13410
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
13248
13411
|
import path24 from "node:path";
|
|
13249
13412
|
import { unzipSync } from "fflate";
|
|
@@ -13316,7 +13479,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13316
13479
|
if (!existsSync16(cssPath)) {
|
|
13317
13480
|
throw new Error("A theme must contain a theme.css file.");
|
|
13318
13481
|
}
|
|
13319
|
-
const css = await
|
|
13482
|
+
const css = await readFile35(cssPath, "utf8");
|
|
13320
13483
|
const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
|
|
13321
13484
|
if (reject) {
|
|
13322
13485
|
throw new Error(`theme.css could not be parsed — ${reject.message}`);
|
|
@@ -13344,7 +13507,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13344
13507
|
for (let i = 0;i < extraSheets.length; i++) {
|
|
13345
13508
|
const rel = extraSheets[i];
|
|
13346
13509
|
const sheetPath = extraSheetPaths[i];
|
|
13347
|
-
const sheetCss = await
|
|
13510
|
+
const sheetCss = await readFile35(sheetPath, "utf8");
|
|
13348
13511
|
const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
|
|
13349
13512
|
if (sheetReject) {
|
|
13350
13513
|
throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
|
|
@@ -13377,7 +13540,7 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
|
|
|
13377
13540
|
let pkg = {};
|
|
13378
13541
|
if (metaExists) {
|
|
13379
13542
|
try {
|
|
13380
|
-
const parsed = JSON.parse(await
|
|
13543
|
+
const parsed = JSON.parse(await readFile35(file, "utf8"));
|
|
13381
13544
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
13382
13545
|
pkg = parsed;
|
|
13383
13546
|
}
|
|
@@ -13479,11 +13642,11 @@ async function importExtensionFromCssText(projectDir, css, name) {
|
|
|
13479
13642
|
async function importExtensionFromFile(projectDir, filePath) {
|
|
13480
13643
|
const ext = path24.extname(filePath).toLowerCase();
|
|
13481
13644
|
if (ext === ".zip") {
|
|
13482
|
-
const buf = await
|
|
13645
|
+
const buf = await readFile35(filePath);
|
|
13483
13646
|
return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
|
|
13484
13647
|
}
|
|
13485
13648
|
if (ext === ".css") {
|
|
13486
|
-
const css = await
|
|
13649
|
+
const css = await readFile35(filePath, "utf8");
|
|
13487
13650
|
return importExtensionFromCssText(projectDir, css, prettify(path24.basename(filePath, ".css")));
|
|
13488
13651
|
}
|
|
13489
13652
|
throw new Error("Choose a .zip extension package or a .css stylesheet.");
|
|
@@ -13948,8 +14111,8 @@ async function readGoogleApiError(res) {
|
|
|
13948
14111
|
}
|
|
13949
14112
|
var RATE_LIMIT_REASONS = /^(dailyLimitExceeded|userRateLimitExceeded|rateLimitExceeded|quotaExceeded)$/i;
|
|
13950
14113
|
var PERMISSION_REASONS = /^(insufficientPermissions|insufficientFilePermissions|forbidden|PERMISSION_DENIED)$/i;
|
|
13951
|
-
function hintFor(
|
|
13952
|
-
const reason =
|
|
14114
|
+
function hintFor(info3) {
|
|
14115
|
+
const reason = info3.reason ?? "";
|
|
13953
14116
|
if (/^accessNotConfigured$/i.test(reason)) {
|
|
13954
14117
|
return "Google Drive publishing isn't fully set up on this build: the Google Drive API isn't enabled for the app's Google Cloud project, so a maintainer needs to enable it (the link is in Google's message).";
|
|
13955
14118
|
}
|
|
@@ -13959,18 +14122,18 @@ function hintFor(info2) {
|
|
|
13959
14122
|
if (RATE_LIMIT_REASONS.test(reason)) {
|
|
13960
14123
|
return "Google Drive is rate-limiting requests right now. Wait a minute and try again.";
|
|
13961
14124
|
}
|
|
13962
|
-
if (PERMISSION_REASONS.test(reason) ||
|
|
14125
|
+
if (PERMISSION_REASONS.test(reason) || info3.status === 401) {
|
|
13963
14126
|
return "This Google Drive connection doesn't have permission for that — disconnect and connect Google Drive again to re-approve access.";
|
|
13964
14127
|
}
|
|
13965
14128
|
return;
|
|
13966
14129
|
}
|
|
13967
|
-
function googleApiFailure(what,
|
|
13968
|
-
const parts = [`${what} (HTTP ${
|
|
13969
|
-
const hint = hintFor(
|
|
14130
|
+
function googleApiFailure(what, info3) {
|
|
14131
|
+
const parts = [`${what} (HTTP ${info3.status}${info3.reason ? `, ${info3.reason}` : ""}).`];
|
|
14132
|
+
const hint = hintFor(info3);
|
|
13970
14133
|
if (hint)
|
|
13971
14134
|
parts.push(hint);
|
|
13972
|
-
if (
|
|
13973
|
-
parts.push(`Google said: "${
|
|
14135
|
+
if (info3.message)
|
|
14136
|
+
parts.push(`Google said: "${info3.message}"`);
|
|
13974
14137
|
let text = parts.join(" ");
|
|
13975
14138
|
if (!/\bgoogle\b/i.test(text))
|
|
13976
14139
|
text = `Google Drive: ${text}`;
|
|
@@ -14224,13 +14387,13 @@ function publishCredentialKey(host, account) {
|
|
|
14224
14387
|
const a = (account ?? "").trim();
|
|
14225
14388
|
return a ? `${host}#${a}` : host;
|
|
14226
14389
|
}
|
|
14227
|
-
async function resolvePublishCredential(
|
|
14390
|
+
async function resolvePublishCredential(info3, deps, account = deps.credentialAccount) {
|
|
14228
14391
|
const env = deps.env ?? process.env;
|
|
14229
|
-
const fromEnv =
|
|
14392
|
+
const fromEnv = info3.credential.envVar ? env[info3.credential.envVar]?.trim() : undefined;
|
|
14230
14393
|
if (fromEnv) {
|
|
14231
14394
|
return {
|
|
14232
14395
|
credential: {
|
|
14233
|
-
host:
|
|
14396
|
+
host: info3.credential.host,
|
|
14234
14397
|
kind: "token",
|
|
14235
14398
|
token: fromEnv,
|
|
14236
14399
|
createdAt: 0
|
|
@@ -14238,21 +14401,21 @@ async function resolvePublishCredential(info2, deps, account = deps.credentialAc
|
|
|
14238
14401
|
source: "env"
|
|
14239
14402
|
};
|
|
14240
14403
|
}
|
|
14241
|
-
const stored = await deps.tokenStore.get(publishCredentialKey(
|
|
14404
|
+
const stored = await deps.tokenStore.get(publishCredentialKey(info3.credential.host, account));
|
|
14242
14405
|
return stored ? { credential: stored, source: "store" } : null;
|
|
14243
14406
|
}
|
|
14244
|
-
async function publishConnectionStatus(
|
|
14245
|
-
if (!
|
|
14407
|
+
async function publishConnectionStatus(info3, deps, account = deps.credentialAccount) {
|
|
14408
|
+
if (!info3.credential.required)
|
|
14246
14409
|
return { connected: true };
|
|
14247
|
-
const resolved = await resolvePublishCredential(
|
|
14410
|
+
const resolved = await resolvePublishCredential(info3, deps, account);
|
|
14248
14411
|
return resolved ? { connected: true, source: resolved.source } : { connected: false };
|
|
14249
14412
|
}
|
|
14250
|
-
async function listPublishAccounts(
|
|
14251
|
-
const wantHost =
|
|
14413
|
+
async function listPublishAccounts(info3, deps) {
|
|
14414
|
+
const wantHost = info3.credential.host.trim().toLowerCase();
|
|
14252
14415
|
const all = await deps.tokenStore.list();
|
|
14253
14416
|
return all.filter((c) => c.host.trim().toLowerCase() === wantHost).map((c) => ({
|
|
14254
14417
|
account: (c.username ?? "").trim(),
|
|
14255
|
-
label: c.label ?? (c.username ||
|
|
14418
|
+
label: c.label ?? (c.username || info3.label),
|
|
14256
14419
|
createdAt: c.createdAt
|
|
14257
14420
|
}));
|
|
14258
14421
|
}
|
|
@@ -15924,7 +16087,7 @@ async function commandExists(cmd, runCommand = defaultCommandRunner, env) {
|
|
|
15924
16087
|
|
|
15925
16088
|
// src/lib/publish/providers/azure-swa.ts
|
|
15926
16089
|
var AZURE_SWA_HOST = "azure-swa";
|
|
15927
|
-
var
|
|
16090
|
+
var info3 = {
|
|
15928
16091
|
id: "azure-swa",
|
|
15929
16092
|
label: "Azure Static Web Apps",
|
|
15930
16093
|
kind: "api",
|
|
@@ -15949,9 +16112,9 @@ async function resolveSwaCommand(req) {
|
|
|
15949
16112
|
}
|
|
15950
16113
|
var SWA_INSTALL_HINT = "Install the Azure SWA CLI first: `npm install -g @azure/static-web-apps-cli` " + "(needs Node.js), or set SWA_CLI_PATH to the swa binary.";
|
|
15951
16114
|
var azureSwaProvider = {
|
|
15952
|
-
info:
|
|
16115
|
+
info: info3,
|
|
15953
16116
|
async authenticate(req) {
|
|
15954
|
-
const resolved = await resolvePublishCredential(
|
|
16117
|
+
const resolved = await resolvePublishCredential(info3, req.deps);
|
|
15955
16118
|
if (!resolved) {
|
|
15956
16119
|
return {
|
|
15957
16120
|
ok: false,
|
|
@@ -15982,7 +16145,7 @@ var azureSwaProvider = {
|
|
|
15982
16145
|
return issues;
|
|
15983
16146
|
},
|
|
15984
16147
|
async upload(req) {
|
|
15985
|
-
const resolved = await resolvePublishCredential(
|
|
16148
|
+
const resolved = await resolvePublishCredential(info3, req.deps);
|
|
15986
16149
|
if (!resolved) {
|
|
15987
16150
|
throw new Error("No Azure deployment token found. Connect Azure Static Web Apps (or set SWA_CLI_DEPLOYMENT_TOKEN) first.");
|
|
15988
16151
|
}
|
|
@@ -16038,7 +16201,7 @@ async function stageGuidedPackage(req, providerId, listingLines) {
|
|
|
16038
16201
|
|
|
16039
16202
|
// src/lib/publish/providers/drivethrurpg.ts
|
|
16040
16203
|
var PUBLISHER_HUB_URL = "https://www.drivethrurpg.com/publisher_hub";
|
|
16041
|
-
var
|
|
16204
|
+
var info4 = {
|
|
16042
16205
|
id: "drivethrurpg",
|
|
16043
16206
|
label: "DriveThruRPG",
|
|
16044
16207
|
kind: "guided",
|
|
@@ -16054,7 +16217,7 @@ var info3 = {
|
|
|
16054
16217
|
credential: { required: false, host: "drivethrurpg.com" }
|
|
16055
16218
|
};
|
|
16056
16219
|
var drivethrurpgProvider = {
|
|
16057
|
-
info:
|
|
16220
|
+
info: info4,
|
|
16058
16221
|
async authenticate() {
|
|
16059
16222
|
return { ok: true };
|
|
16060
16223
|
},
|
|
@@ -16095,7 +16258,7 @@ var drivethrurpgProvider = {
|
|
|
16095
16258
|
};
|
|
16096
16259
|
|
|
16097
16260
|
// src/lib/publish/providers/gdrive.ts
|
|
16098
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
16261
|
+
import { mkdtemp as mkdtemp3, readFile as readFile36, readdir as readdir11, rm as rm9, stat as stat9, writeFile as writeFile16 } from "node:fs/promises";
|
|
16099
16262
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
16100
16263
|
import path30 from "node:path";
|
|
16101
16264
|
import { Zip, ZipDeflate } from "fflate";
|
|
@@ -16363,7 +16526,7 @@ async function resumableUpload(fetchImpl, accessToken, opts) {
|
|
|
16363
16526
|
// src/lib/publish/providers/gdrive.ts
|
|
16364
16527
|
var DEFAULT_FOLDER_NAME = "Gutterpress";
|
|
16365
16528
|
var NOT_CONNECTED_MESSAGE = "Google Drive isn't connected. Run `gutterpress publish --provider gdrive --connect` (or set GDRIVE_REFRESH_TOKEN) first.";
|
|
16366
|
-
var
|
|
16529
|
+
var info5 = {
|
|
16367
16530
|
id: "gdrive",
|
|
16368
16531
|
label: "Google Drive",
|
|
16369
16532
|
kind: "api",
|
|
@@ -16402,7 +16565,7 @@ async function mintAccessToken(resolved, fetchImpl) {
|
|
|
16402
16565
|
return accessToken;
|
|
16403
16566
|
}
|
|
16404
16567
|
async function getAccessToken(req) {
|
|
16405
|
-
const resolved = await resolvePublishCredential(
|
|
16568
|
+
const resolved = await resolvePublishCredential(info5, req.deps);
|
|
16406
16569
|
if (!resolved)
|
|
16407
16570
|
throw new Error(NOT_CONNECTED_MESSAGE);
|
|
16408
16571
|
const accessToken = await mintAccessToken(resolved, req.deps.fetch ?? globalThis.fetch);
|
|
@@ -16487,12 +16650,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
|
|
|
16487
16650
|
await collectZipEntries(root, full, out, onWarn);
|
|
16488
16651
|
} else if (entry.isFile()) {
|
|
16489
16652
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16490
|
-
out[rel] = await
|
|
16653
|
+
out[rel] = await readFile36(full);
|
|
16491
16654
|
} else if (entry.isSymbolicLink()) {
|
|
16492
16655
|
const resolved = await stat9(full).catch(() => null);
|
|
16493
16656
|
if (resolved?.isFile()) {
|
|
16494
16657
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16495
|
-
out[rel] = await
|
|
16658
|
+
out[rel] = await readFile36(full);
|
|
16496
16659
|
} else if (resolved?.isDirectory()) {
|
|
16497
16660
|
await collectZipEntries(root, full, out, onWarn);
|
|
16498
16661
|
} else {
|
|
@@ -16524,9 +16687,9 @@ async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeF
|
|
|
16524
16687
|
}
|
|
16525
16688
|
}
|
|
16526
16689
|
var gdriveProvider = {
|
|
16527
|
-
info:
|
|
16690
|
+
info: info5,
|
|
16528
16691
|
async authenticate(req) {
|
|
16529
|
-
const resolved = await resolvePublishCredential(
|
|
16692
|
+
const resolved = await resolvePublishCredential(info5, req.deps);
|
|
16530
16693
|
if (!resolved)
|
|
16531
16694
|
return { ok: false, message: NOT_CONNECTED_MESSAGE };
|
|
16532
16695
|
try {
|
|
@@ -16691,7 +16854,7 @@ async function ensureButler(deps) {
|
|
|
16691
16854
|
var ITCH_HOST = "itch.io";
|
|
16692
16855
|
var TARGET_RE = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
|
|
16693
16856
|
var ITCH_API_TIMEOUT_MS = 15000;
|
|
16694
|
-
var
|
|
16857
|
+
var info6 = {
|
|
16695
16858
|
id: "itch",
|
|
16696
16859
|
label: "itch.io",
|
|
16697
16860
|
kind: "api",
|
|
@@ -16721,9 +16884,9 @@ function itchProjectUrl(target) {
|
|
|
16721
16884
|
return `https://${user}.itch.io/${game}`;
|
|
16722
16885
|
}
|
|
16723
16886
|
var itchProvider = {
|
|
16724
|
-
info:
|
|
16887
|
+
info: info6,
|
|
16725
16888
|
async authenticate(req) {
|
|
16726
|
-
const resolved = await resolvePublishCredential(
|
|
16889
|
+
const resolved = await resolvePublishCredential(info6, req.deps);
|
|
16727
16890
|
if (!resolved) {
|
|
16728
16891
|
return {
|
|
16729
16892
|
ok: false,
|
|
@@ -16791,7 +16954,7 @@ var itchProvider = {
|
|
|
16791
16954
|
},
|
|
16792
16955
|
async upload(req) {
|
|
16793
16956
|
const { target, channel } = readConfig2(req);
|
|
16794
|
-
const resolved = await resolvePublishCredential(
|
|
16957
|
+
const resolved = await resolvePublishCredential(info6, req.deps);
|
|
16795
16958
|
if (!resolved) {
|
|
16796
16959
|
throw new Error("No itch.io API key found. Connect itch.io (or set BUTLER_API_KEY) first.");
|
|
16797
16960
|
}
|
|
@@ -16819,7 +16982,7 @@ ${tail}` : ""}`);
|
|
|
16819
16982
|
|
|
16820
16983
|
// src/lib/publish/providers/kdp.ts
|
|
16821
16984
|
var KDP_URL = "https://kdp.amazon.com/en_US/bookshelf";
|
|
16822
|
-
var
|
|
16985
|
+
var info7 = {
|
|
16823
16986
|
id: "kdp",
|
|
16824
16987
|
label: "Amazon KDP",
|
|
16825
16988
|
kind: "guided",
|
|
@@ -16829,7 +16992,7 @@ var info6 = {
|
|
|
16829
16992
|
credential: { required: false, host: "kdp.amazon.com" }
|
|
16830
16993
|
};
|
|
16831
16994
|
var kdpProvider = {
|
|
16832
|
-
info:
|
|
16995
|
+
info: info7,
|
|
16833
16996
|
async authenticate() {
|
|
16834
16997
|
return { ok: true };
|
|
16835
16998
|
},
|
|
@@ -16874,7 +17037,7 @@ var kdpProvider = {
|
|
|
16874
17037
|
import { cp as cp7, mkdir as mkdir20, stat as stat11 } from "node:fs/promises";
|
|
16875
17038
|
import path32 from "node:path";
|
|
16876
17039
|
var LOCAL_PUBLISH_DEFAULT_DIR = "dist";
|
|
16877
|
-
var
|
|
17040
|
+
var info8 = {
|
|
16878
17041
|
id: "local",
|
|
16879
17042
|
label: "A folder on this computer",
|
|
16880
17043
|
kind: "api",
|
|
@@ -16891,7 +17054,7 @@ function localPublishDir(req) {
|
|
|
16891
17054
|
return path32.resolve(req.project.projectDir, dir);
|
|
16892
17055
|
}
|
|
16893
17056
|
var localFolderProvider = {
|
|
16894
|
-
info:
|
|
17057
|
+
info: info8,
|
|
16895
17058
|
async authenticate() {
|
|
16896
17059
|
return { ok: true };
|
|
16897
17060
|
},
|
|
@@ -16932,7 +17095,7 @@ function requireValidShop(shop) {
|
|
|
16932
17095
|
}
|
|
16933
17096
|
return shop;
|
|
16934
17097
|
}
|
|
16935
|
-
var
|
|
17098
|
+
var info9 = {
|
|
16936
17099
|
id: "shopify",
|
|
16937
17100
|
label: "Shopify",
|
|
16938
17101
|
kind: "api",
|
|
@@ -16966,7 +17129,7 @@ function readConfig3(req) {
|
|
|
16966
17129
|
async function adminGraphQL(req, query, variables = {}) {
|
|
16967
17130
|
const { shop: rawShop, apiVersion } = readConfig3(req);
|
|
16968
17131
|
const shop = requireValidShop(rawShop);
|
|
16969
|
-
const resolved = await resolvePublishCredential(
|
|
17132
|
+
const resolved = await resolvePublishCredential(info9, req.deps);
|
|
16970
17133
|
if (!resolved) {
|
|
16971
17134
|
throw new Error("No Shopify access token found. Connect Shopify (or set SHOPIFY_ADMIN_TOKEN) first.");
|
|
16972
17135
|
}
|
|
@@ -17017,9 +17180,9 @@ function userErrorsToMessage(result) {
|
|
|
17017
17180
|
return errs?.length ? errs[0].message : null;
|
|
17018
17181
|
}
|
|
17019
17182
|
var shopifyProvider = {
|
|
17020
|
-
info:
|
|
17183
|
+
info: info9,
|
|
17021
17184
|
async authenticate(req) {
|
|
17022
|
-
const resolved = await resolvePublishCredential(
|
|
17185
|
+
const resolved = await resolvePublishCredential(info9, req.deps);
|
|
17023
17186
|
if (!resolved) {
|
|
17024
17187
|
return {
|
|
17025
17188
|
ok: false,
|
|
@@ -17153,14 +17316,14 @@ function publishProviderFor(id) {
|
|
|
17153
17316
|
}
|
|
17154
17317
|
|
|
17155
17318
|
// src/lib/publish/run-publish.ts
|
|
17156
|
-
function resolvePublishFormat(
|
|
17157
|
-
if (
|
|
17319
|
+
function resolvePublishFormat(info10, providerConfig) {
|
|
17320
|
+
if (info10.formats && info10.formats.length > 0) {
|
|
17158
17321
|
const configured = typeof providerConfig.format === "string" ? providerConfig.format.trim() : "";
|
|
17159
|
-
if (configured &&
|
|
17322
|
+
if (configured && info10.formats.includes(configured)) {
|
|
17160
17323
|
return configured;
|
|
17161
17324
|
}
|
|
17162
17325
|
}
|
|
17163
|
-
return
|
|
17326
|
+
return info10.format;
|
|
17164
17327
|
}
|
|
17165
17328
|
async function resolvePublishRequest(options, deps) {
|
|
17166
17329
|
const provider = publishProviderFor(options.providerId);
|
|
@@ -17309,17 +17472,17 @@ function overlayStore(inner, key, candidate) {
|
|
|
17309
17472
|
}
|
|
17310
17473
|
async function connectPublishProvider(options, deps) {
|
|
17311
17474
|
const provider = publishProviderFor(options.providerId);
|
|
17312
|
-
const
|
|
17313
|
-
if (!
|
|
17314
|
-
throw new Error(`${
|
|
17475
|
+
const info10 = provider.info;
|
|
17476
|
+
if (!info10.credential.required) {
|
|
17477
|
+
throw new Error(`${info10.label} needs no API key — just publish when you're ready.`);
|
|
17315
17478
|
}
|
|
17316
|
-
if (
|
|
17317
|
-
throw new Error(`${
|
|
17479
|
+
if (info10.credential.connect === "oauth") {
|
|
17480
|
+
throw new Error(`${info10.label} connects through your browser, not a pasted key — run ` + `"gutterpress publish --provider ${info10.id} --connect" or use the desktop app's Connect button.`);
|
|
17318
17481
|
}
|
|
17319
17482
|
const token = options.token.trim();
|
|
17320
17483
|
if (!token)
|
|
17321
17484
|
throw new Error("Paste an API key first.");
|
|
17322
|
-
const host =
|
|
17485
|
+
const host = info10.credential.host;
|
|
17323
17486
|
const account = (options.account ?? "").trim();
|
|
17324
17487
|
const key = publishCredentialKey(host, account);
|
|
17325
17488
|
const candidate = {
|
|
@@ -17327,12 +17490,12 @@ async function connectPublishProvider(options, deps) {
|
|
|
17327
17490
|
kind: "token",
|
|
17328
17491
|
token,
|
|
17329
17492
|
...account ? { username: account } : {},
|
|
17330
|
-
label: account ||
|
|
17493
|
+
label: account || info10.label,
|
|
17331
17494
|
createdAt: Date.now()
|
|
17332
17495
|
};
|
|
17333
17496
|
const req = await resolvePublishRequest({
|
|
17334
17497
|
projectDir: options.projectDir,
|
|
17335
|
-
providerId:
|
|
17498
|
+
providerId: info10.id,
|
|
17336
17499
|
...options.manifestPath ? { manifestPath: options.manifestPath } : {}
|
|
17337
17500
|
}, deps);
|
|
17338
17501
|
const trialDeps = {
|
|
@@ -17343,10 +17506,10 @@ async function connectPublishProvider(options, deps) {
|
|
|
17343
17506
|
};
|
|
17344
17507
|
const auth = await provider.authenticate({ ...req, deps: trialDeps });
|
|
17345
17508
|
if (!auth.ok) {
|
|
17346
|
-
throw new Error(auth.message ?? `${
|
|
17509
|
+
throw new Error(auth.message ?? `${info10.label} didn't accept that key.`);
|
|
17347
17510
|
}
|
|
17348
17511
|
await deps.tokenStore.set(key, candidate);
|
|
17349
|
-
return { connected: true, providerId:
|
|
17512
|
+
return { connected: true, providerId: info10.id };
|
|
17350
17513
|
}
|
|
17351
17514
|
async function disconnectPublishCredential(key, deps, options = {}) {
|
|
17352
17515
|
const existing = await deps.tokenStore.get(key);
|
|
@@ -17358,7 +17521,7 @@ async function disconnectPublishCredential(key, deps, options = {}) {
|
|
|
17358
17521
|
}
|
|
17359
17522
|
}
|
|
17360
17523
|
// src/lib/publish/selections.ts
|
|
17361
|
-
import { chmod as chmod3, mkdir as mkdir21, readFile as
|
|
17524
|
+
import { chmod as chmod3, mkdir as mkdir21, readFile as readFile37, writeFile as writeFile18 } from "node:fs/promises";
|
|
17362
17525
|
import path34 from "node:path";
|
|
17363
17526
|
class PublishSelectionsStore {
|
|
17364
17527
|
filePath;
|
|
@@ -17368,7 +17531,7 @@ class PublishSelectionsStore {
|
|
|
17368
17531
|
}
|
|
17369
17532
|
async read() {
|
|
17370
17533
|
try {
|
|
17371
|
-
const raw = await
|
|
17534
|
+
const raw = await readFile37(this.filePath, "utf8");
|
|
17372
17535
|
const parsed = JSON.parse(raw);
|
|
17373
17536
|
if (parsed && typeof parsed === "object") {
|
|
17374
17537
|
return {
|