gutterpress 0.0.0 → 0.9.0-alpha.2
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 +21 -16
- package/dist/api/index.d.ts +6 -2
- package/dist/api/index.js +15 -3
- package/dist/{audit-1jrwwacz.js → audit-nhn2pjz3.js} +5 -5
- package/dist/{build-5s92kgpc.js → build-san7fv2z.js} +5 -5
- package/dist/checks/types.d.ts +6 -0
- package/dist/{cli-hvqjs342.js → cli-e5zhb0xs.js} +2 -2
- package/dist/{cli-7ykx7pp0.js → cli-k4bd06sd.js} +982 -331
- package/dist/{cli-h7phg3ka.js → cli-najycadg.js} +258 -258
- package/dist/{index-1tyj4bk3.js → cli-wchtvxvw.js} +4 -1
- package/dist/{cli-5bxx0c4y.js → cli-yzrh708h.js} +2 -2
- package/dist/cli.js +15 -15
- package/dist/{doctor-25zjt8dz.js → doctor-hrk0kxxz.js} +2 -2
- package/dist/{index-3h3fef7r.js → index-bynn850m.js} +1200 -410
- package/dist/{cli-1tyj4bk3.js → index-wchtvxvw.js} +4 -1
- package/dist/{index-5bxx0c4y.js → index-yzrh708h.js} +2 -2
- package/dist/index.js +15 -3
- package/dist/lib/asset-inline.d.ts +19 -0
- package/dist/lib/build-error.d.ts +0 -1
- package/dist/lib/build-fingerprint.d.ts +14 -0
- package/dist/lib/build-runner.d.ts +21 -1
- package/dist/lib/ghostscript.d.ts +0 -9
- package/dist/lib/manifest-config.d.ts +7 -0
- package/dist/lib/manifest.d.ts +8 -0
- package/dist/lib/markdown/assemble.d.ts +4 -6
- package/dist/lib/markdown/chapter-id.d.ts +1 -1
- package/dist/lib/markdown/index.d.ts +1 -2
- package/dist/lib/npm-plugin-installer.d.ts +1 -1
- package/dist/lib/output-paths.d.ts +0 -1
- package/dist/lib/pagination.d.ts +0 -20
- package/dist/lib/pdf-inspect.d.ts +2 -2
- package/dist/lib/pdf-parse.d.ts +2 -1
- package/dist/lib/plugin-manager.d.ts +0 -2
- package/dist/lib/presets.d.ts +36 -7
- package/dist/lib/project-scaffold.d.ts +39 -2
- package/dist/lib/project-source.d.ts +11 -9
- package/dist/lib/project-templates.d.ts +45 -7
- package/dist/lib/publish/providers/azure-swa.d.ts +0 -1
- package/dist/lib/publish/providers/itch.d.ts +0 -1
- package/dist/lib/publish/providers/shopify.d.ts +0 -1
- package/dist/lib/remote-auth/github-repos.d.ts +0 -2
- package/dist/lib/remote-auth/recovery/dispatch.d.ts +0 -5
- package/dist/lib/remote-auth/recovery/outcome-mapping.d.ts +3 -2
- package/dist/lib/remote-auth/recovery/recover-stale-lock.d.ts +0 -8
- package/dist/lib/remote-auth/sync.d.ts +2 -10
- package/dist/lib/remote-auth/test-access.d.ts +0 -2
- package/dist/lib/remote-auth/test-support/git-http-server.d.ts +0 -37
- package/dist/lib/source-provider.d.ts +0 -14
- package/dist/lib/static-serve.d.ts +39 -0
- package/dist/lib/style-resolver.d.ts +10 -1
- package/dist/lib/targets.d.ts +84 -0
- package/dist/lib/theme-import.d.ts +0 -2
- package/dist/lib/theme-manager.d.ts +1 -1
- package/dist/lib/validation-exec.d.ts +4 -3
- package/dist/{lint-f63nxjfj.js → lint-96j9hrj4.js} +5 -5
- package/dist/{manifest.schema-rn1dpdpn.json → manifest.schema-z61rzw44.json} +12 -6
- package/dist/new-8p38wavc.js +185 -0
- package/dist/{pagedjs-interface-80g3xa8p.js → pagedjs-interface-qxvzgwd7.js} +92 -33
- package/dist/{plugin-wf2cbmwc.js → plugin-ees6nhkc.js} +5 -5
- package/dist/{preflight-tg4mpz1h.js → preflight-1q6c2edh.js} +24 -29
- package/dist/preview/file-watcher.d.ts +48 -39
- package/dist/preview/http-server.d.ts +5 -2
- package/dist/preview/server-context.d.ts +24 -0
- package/dist/preview-shell-6dqexx1m.js +581 -0
- package/dist/{preview-h2bwbb2x.js → preview-y5a2zen1.js} +5 -5
- package/dist/{project-source-0tg0r6vm.js → project-source-p0gn1wd5.js} +3 -3
- package/dist/{publish-ztaet53r.js → publish-rm9yb3wh.js} +5 -5
- package/dist/render.js +10 -19
- package/dist/{repair-jkp4n3j8.js → repair-zgq7q2g6.js} +5 -5
- package/dist/schema/manifest.types.d.ts +14 -3
- package/dist/server.d.ts +2 -0
- package/dist/{source-provider-hp96b5jf.js → source-provider-c1rjm2c0.js} +2 -8
- package/dist/types.d.ts +0 -1
- package/dist/{validate-k2drs19j.js → validate-nr0xa6sa.js} +8 -8
- package/package.json +2 -2
- package/dist/chapter-01-jj8ftn4c.md +0 -29
- package/dist/lib/validation-profile.d.ts +0 -18
- package/dist/manifest-ryyg71nf.yaml +0 -9
- package/dist/new-7b08a42h.js +0 -105
- package/dist/preview-shell-rghtfmc8.js +0 -155
- package/dist/theme-0yzvthe8.css +0 -65
- package/dist/theme-6a2fngc8.json +0 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
package_default
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-e5zhb0xs.js";
|
|
4
4
|
import {
|
|
5
5
|
__require
|
|
6
6
|
} from "./cli-37x76zdn.js";
|
|
@@ -67,156 +67,6 @@ var log = {
|
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
// src/lib/remote-auth/token-store.ts
|
|
71
|
-
import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
72
|
-
import os from "node:os";
|
|
73
|
-
import path from "node:path";
|
|
74
|
-
function credentialHostKey(hostOrUrl) {
|
|
75
|
-
const trimmed = String(hostOrUrl ?? "").trim();
|
|
76
|
-
if (!trimmed)
|
|
77
|
-
return "";
|
|
78
|
-
const scp = /^[\w.-]+@([\w.][\w.-]*):/.exec(trimmed);
|
|
79
|
-
if (scp)
|
|
80
|
-
return stripWww(scp[1].toLowerCase());
|
|
81
|
-
const candidate = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
82
|
-
try {
|
|
83
|
-
const url = new URL(candidate);
|
|
84
|
-
if (!url.hostname)
|
|
85
|
-
return "";
|
|
86
|
-
const host = url.port ? `${url.hostname}:${url.port}`.toLowerCase() : url.hostname.toLowerCase();
|
|
87
|
-
return stripWww(host);
|
|
88
|
-
} catch {
|
|
89
|
-
return "";
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function stripWww(host) {
|
|
93
|
-
return host.startsWith("www.") && host.length > 4 ? host.slice(4) : host;
|
|
94
|
-
}
|
|
95
|
-
function defaultConfigDir() {
|
|
96
|
-
const override = process.env.GUTTERPRESS_CONFIG_DIR?.trim();
|
|
97
|
-
if (override)
|
|
98
|
-
return override;
|
|
99
|
-
if (process.platform === "win32" && process.env.APPDATA) {
|
|
100
|
-
return path.join(process.env.APPDATA, "gutterpress");
|
|
101
|
-
}
|
|
102
|
-
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
103
|
-
return path.join(xdg || path.join(os.homedir(), ".config"), "gutterpress");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
class FileTokenStore {
|
|
107
|
-
filePath;
|
|
108
|
-
queue = Promise.resolve();
|
|
109
|
-
constructor(filePath) {
|
|
110
|
-
this.filePath = filePath ?? path.join(defaultConfigDir(), "credentials.json");
|
|
111
|
-
}
|
|
112
|
-
async read() {
|
|
113
|
-
let raw;
|
|
114
|
-
try {
|
|
115
|
-
raw = await readFile(this.filePath, "utf8");
|
|
116
|
-
} catch (e) {
|
|
117
|
-
if (e?.code === "ENOENT") {
|
|
118
|
-
return { version: 1, credentials: {} };
|
|
119
|
-
}
|
|
120
|
-
throw e;
|
|
121
|
-
}
|
|
122
|
-
try {
|
|
123
|
-
const parsed = JSON.parse(raw);
|
|
124
|
-
if (parsed && typeof parsed === "object" && parsed.credentials)
|
|
125
|
-
return parsed;
|
|
126
|
-
} catch {
|
|
127
|
-
await writeFile(`${this.filePath}.corrupt`, raw, {
|
|
128
|
-
encoding: "utf8",
|
|
129
|
-
mode: 384
|
|
130
|
-
}).catch(() => {});
|
|
131
|
-
}
|
|
132
|
-
return { version: 1, credentials: {} };
|
|
133
|
-
}
|
|
134
|
-
async write(data) {
|
|
135
|
-
await mkdir(path.dirname(this.filePath), { recursive: true });
|
|
136
|
-
const tmpPath = `${this.filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
137
|
-
await writeFile(tmpPath, JSON.stringify(data, null, 2), {
|
|
138
|
-
encoding: "utf8",
|
|
139
|
-
mode: 384
|
|
140
|
-
});
|
|
141
|
-
await rename(tmpPath, this.filePath);
|
|
142
|
-
await chmod(this.filePath, 384);
|
|
143
|
-
}
|
|
144
|
-
enqueue(fn) {
|
|
145
|
-
const run = this.queue.then(fn, fn);
|
|
146
|
-
this.queue = run.catch(() => {
|
|
147
|
-
return;
|
|
148
|
-
});
|
|
149
|
-
return run;
|
|
150
|
-
}
|
|
151
|
-
get(host) {
|
|
152
|
-
return this.enqueue(async () => {
|
|
153
|
-
try {
|
|
154
|
-
const data = await this.read();
|
|
155
|
-
return data.credentials[normalizeHost(host)] ?? null;
|
|
156
|
-
} catch {
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
set(host, credential) {
|
|
162
|
-
return this.enqueue(async () => {
|
|
163
|
-
const data = await this.read();
|
|
164
|
-
data.credentials[normalizeHost(host)] = credential;
|
|
165
|
-
await this.write(data);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
delete(host) {
|
|
169
|
-
return this.enqueue(async () => {
|
|
170
|
-
const data = await this.read();
|
|
171
|
-
delete data.credentials[normalizeHost(host)];
|
|
172
|
-
await this.write(data);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
list() {
|
|
176
|
-
return this.enqueue(async () => {
|
|
177
|
-
try {
|
|
178
|
-
const data = await this.read();
|
|
179
|
-
return Object.values(data.credentials);
|
|
180
|
-
} catch {
|
|
181
|
-
return [];
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
function normalizeHost(host) {
|
|
187
|
-
return host.trim().toLowerCase();
|
|
188
|
-
}
|
|
189
|
-
function extractUrlCredential(url) {
|
|
190
|
-
let parsed;
|
|
191
|
-
try {
|
|
192
|
-
parsed = new URL(url);
|
|
193
|
-
} catch {
|
|
194
|
-
return { cleanUrl: url };
|
|
195
|
-
}
|
|
196
|
-
if (!/^https?:$/.test(parsed.protocol))
|
|
197
|
-
return { cleanUrl: url };
|
|
198
|
-
if (!parsed.username && !parsed.password)
|
|
199
|
-
return { cleanUrl: url };
|
|
200
|
-
const token = parsed.password ? decodeURIComponent(parsed.password) : decodeURIComponent(parsed.username);
|
|
201
|
-
const username = parsed.password ? decodeURIComponent(parsed.username) : undefined;
|
|
202
|
-
parsed.username = "";
|
|
203
|
-
parsed.password = "";
|
|
204
|
-
const credential = {
|
|
205
|
-
host: credentialHostKey(parsed.toString()),
|
|
206
|
-
kind: "token",
|
|
207
|
-
token,
|
|
208
|
-
...username ? { username } : {},
|
|
209
|
-
createdAt: Date.now()
|
|
210
|
-
};
|
|
211
|
-
return { cleanUrl: parsed.toString(), credential };
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// src/lib/diagnostics.ts
|
|
215
|
-
import { platform as platform2, arch, release } from "node:os";
|
|
216
|
-
|
|
217
|
-
// src/lib/chromium.ts
|
|
218
|
-
import { existsSync } from "node:fs";
|
|
219
|
-
|
|
220
70
|
// src/lib/tool-probe.ts
|
|
221
71
|
import { platform } from "node:os";
|
|
222
72
|
|
|
@@ -356,107 +206,9 @@ async function findTool(tool) {
|
|
|
356
206
|
}
|
|
357
207
|
}
|
|
358
208
|
|
|
359
|
-
// src/lib/install-hints.ts
|
|
360
|
-
var INSTALL_HINTS = {
|
|
361
|
-
chromium: {
|
|
362
|
-
label: "Google Chrome, Chromium, or Microsoft Edge",
|
|
363
|
-
body: ` macOS: brew install --cask google-chrome
|
|
364
|
-
` + ` Ubuntu: sudo apt install -y chromium-browser
|
|
365
|
-
` + " Windows: https://www.google.com/chrome/ (Edge is auto-detected if pre-installed)"
|
|
366
|
-
},
|
|
367
|
-
gs: {
|
|
368
|
-
label: "Ghostscript",
|
|
369
|
-
body: ` macOS: brew install ghostscript
|
|
370
|
-
` + ` Ubuntu: sudo apt install -y ghostscript
|
|
371
|
-
` + " Windows: https://www.ghostscript.com/releases/gsdnld.html (standard installs are auto-detected; or: choco install ghostscript)"
|
|
372
|
-
},
|
|
373
|
-
qpdf: {
|
|
374
|
-
label: "qpdf",
|
|
375
|
-
body: ` macOS: brew install qpdf
|
|
376
|
-
` + ` Ubuntu: sudo apt install -y qpdf
|
|
377
|
-
` + " Windows: choco install qpdf (or: https://github.com/qpdf/qpdf/releases)"
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
function fullInstallHint(tool) {
|
|
381
|
-
const hint = INSTALL_HINTS[tool];
|
|
382
|
-
return `Install ${hint.label}:
|
|
383
|
-
${hint.body}`;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// src/lib/chromium.ts
|
|
387
|
-
var SYSTEM_PATHS = [
|
|
388
|
-
process.env.CHROMIUM_PATH,
|
|
389
|
-
process.env.PUPPETEER_EXECUTABLE_PATH,
|
|
390
|
-
"/usr/bin/google-chrome",
|
|
391
|
-
"/usr/bin/google-chrome-stable",
|
|
392
|
-
"/usr/bin/chromium",
|
|
393
|
-
"/usr/bin/chromium-browser",
|
|
394
|
-
"/snap/bin/chromium",
|
|
395
|
-
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
396
|
-
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
397
|
-
"/opt/homebrew/bin/chromium",
|
|
398
|
-
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
399
|
-
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
400
|
-
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
401
|
-
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
402
|
-
process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe` : undefined,
|
|
403
|
-
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
404
|
-
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
405
|
-
process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\Microsoft\\Edge\\Application\\msedge.exe` : undefined,
|
|
406
|
-
process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe` : undefined
|
|
407
|
-
].filter(Boolean);
|
|
408
|
-
var PATH_CANDIDATES = [
|
|
409
|
-
"google-chrome",
|
|
410
|
-
"google-chrome-stable",
|
|
411
|
-
"chromium",
|
|
412
|
-
"chromium-browser",
|
|
413
|
-
"chrome",
|
|
414
|
-
"chrome.exe",
|
|
415
|
-
"msedge",
|
|
416
|
-
"msedge.exe",
|
|
417
|
-
"brave",
|
|
418
|
-
"brave-browser",
|
|
419
|
-
"brave.exe",
|
|
420
|
-
"vivaldi",
|
|
421
|
-
"vivaldi-stable",
|
|
422
|
-
"vivaldi.exe",
|
|
423
|
-
"opera",
|
|
424
|
-
"opera-stable",
|
|
425
|
-
"opera.exe"
|
|
426
|
-
];
|
|
427
|
-
async function resolveChromiumExecutable() {
|
|
428
|
-
for (const candidate of SYSTEM_PATHS) {
|
|
429
|
-
if (existsSync(candidate))
|
|
430
|
-
return candidate;
|
|
431
|
-
}
|
|
432
|
-
for (const candidate of PATH_CANDIDATES) {
|
|
433
|
-
const found = await findTool(candidate);
|
|
434
|
-
if (found)
|
|
435
|
-
return found;
|
|
436
|
-
}
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
async function requireChromiumExecutable() {
|
|
440
|
-
const found = await resolveChromiumExecutable();
|
|
441
|
-
if (found)
|
|
442
|
-
return found;
|
|
443
|
-
throw new Error([
|
|
444
|
-
"No Chrome / Chromium / Edge binary found. Gutterpress needs a Chromium-based browser to render PDFs.",
|
|
445
|
-
"",
|
|
446
|
-
"Install one of:",
|
|
447
|
-
INSTALL_HINTS.chromium.body,
|
|
448
|
-
"",
|
|
449
|
-
"Or point to an existing install:",
|
|
450
|
-
" CHROMIUM_PATH=/path/to/chrome gutterpress build ...",
|
|
451
|
-
"",
|
|
452
|
-
"The Gutterpress desktop app includes its own browser and needs no separate browser installation."
|
|
453
|
-
].join(`
|
|
454
|
-
`));
|
|
455
|
-
}
|
|
456
|
-
|
|
457
209
|
// src/lib/ghostscript.ts
|
|
458
|
-
import { existsSync
|
|
459
|
-
import { readFile
|
|
210
|
+
import { existsSync } from "node:fs";
|
|
211
|
+
import { readFile, writeFile, unlink, rename, readdir } from "node:fs/promises";
|
|
460
212
|
import { join as join2, basename, resolve } from "node:path";
|
|
461
213
|
var WINDOWS_GHOSTSCRIPT_NAMES = ["gswin64c", "gswin32c", "gs"];
|
|
462
214
|
var POSIX_GHOSTSCRIPT_NAMES = ["gs"];
|
|
@@ -490,7 +242,7 @@ async function findWindowsGhostscriptInstall(env) {
|
|
|
490
242
|
for (const version of versions) {
|
|
491
243
|
for (const executable of ["gswin64c.exe", "gswin32c.exe"]) {
|
|
492
244
|
const candidate = join2(installRoot, version.name, "bin", executable);
|
|
493
|
-
if (
|
|
245
|
+
if (existsSync(candidate))
|
|
494
246
|
return candidate;
|
|
495
247
|
}
|
|
496
248
|
}
|
|
@@ -499,7 +251,7 @@ async function findWindowsGhostscriptInstall(env) {
|
|
|
499
251
|
}
|
|
500
252
|
async function resolveGhostscript(targetPlatform = process.platform, env = process.env) {
|
|
501
253
|
const override = envValue(env, "GHOSTSCRIPT_PATH");
|
|
502
|
-
if (override &&
|
|
254
|
+
if (override && existsSync(override))
|
|
503
255
|
return override;
|
|
504
256
|
const names = targetPlatform === "win32" ? WINDOWS_GHOSTSCRIPT_NAMES : POSIX_GHOSTSCRIPT_NAMES;
|
|
505
257
|
for (const name of names) {
|
|
@@ -513,7 +265,7 @@ async function stripAnnotations(pdfPath, stagingDir) {
|
|
|
513
265
|
const tmp = join2(stagingDir, "annotations-stripped.pdf");
|
|
514
266
|
try {
|
|
515
267
|
await run("qpdf", [pdfPath, tmp, "--flatten-annotations=all"]);
|
|
516
|
-
await
|
|
268
|
+
await rename(tmp, pdfPath);
|
|
517
269
|
} finally {
|
|
518
270
|
await unlink(tmp).catch(() => {});
|
|
519
271
|
}
|
|
@@ -585,11 +337,11 @@ ${docInfoConformance}/DOCINFO pdfmark
|
|
|
585
337
|
}
|
|
586
338
|
async function stampCreator(pdfPath) {
|
|
587
339
|
const { PDFDocument } = await import("pdf-lib");
|
|
588
|
-
const bytes = await
|
|
340
|
+
const bytes = await readFile(pdfPath);
|
|
589
341
|
const doc = await PDFDocument.load(bytes, { updateMetadata: false });
|
|
590
342
|
doc.setCreator("gutterpress");
|
|
591
343
|
const out = await doc.save();
|
|
592
|
-
await
|
|
344
|
+
await writeFile(pdfPath, out);
|
|
593
345
|
}
|
|
594
346
|
async function convertToPdfxCmyk(inputPdf, outPdf, config) {
|
|
595
347
|
const iccPath = resolve(config.iccPath);
|
|
@@ -618,7 +370,7 @@ async function convertToPdfxCmyk(inputPdf, outPdf, config) {
|
|
|
618
370
|
inputPdf
|
|
619
371
|
];
|
|
620
372
|
try {
|
|
621
|
-
await
|
|
373
|
+
await writeFile(tmpDef, makePdfxDefPs({
|
|
622
374
|
iccPath,
|
|
623
375
|
pdfx: config.pdfx,
|
|
624
376
|
title: config.title ?? basename(outPdf),
|
|
@@ -634,6 +386,254 @@ async function convertToPdfxCmyk(inputPdf, outPdf, config) {
|
|
|
634
386
|
}
|
|
635
387
|
}
|
|
636
388
|
|
|
389
|
+
// src/lib/remote-auth/token-store.ts
|
|
390
|
+
import { chmod, mkdir, readFile as readFile2, rename as rename2, writeFile as writeFile2 } from "node:fs/promises";
|
|
391
|
+
import os from "node:os";
|
|
392
|
+
import path from "node:path";
|
|
393
|
+
function credentialHostKey(hostOrUrl) {
|
|
394
|
+
const trimmed = String(hostOrUrl ?? "").trim();
|
|
395
|
+
if (!trimmed)
|
|
396
|
+
return "";
|
|
397
|
+
const scp = /^[\w.-]+@([\w.][\w.-]*):/.exec(trimmed);
|
|
398
|
+
if (scp)
|
|
399
|
+
return stripWww(scp[1].toLowerCase());
|
|
400
|
+
const candidate = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
401
|
+
try {
|
|
402
|
+
const url = new URL(candidate);
|
|
403
|
+
if (!url.hostname)
|
|
404
|
+
return "";
|
|
405
|
+
const host = url.port ? `${url.hostname}:${url.port}`.toLowerCase() : url.hostname.toLowerCase();
|
|
406
|
+
return stripWww(host);
|
|
407
|
+
} catch {
|
|
408
|
+
return "";
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function stripWww(host) {
|
|
412
|
+
return host.startsWith("www.") && host.length > 4 ? host.slice(4) : host;
|
|
413
|
+
}
|
|
414
|
+
function defaultConfigDir() {
|
|
415
|
+
const override = process.env.GUTTERPRESS_CONFIG_DIR?.trim();
|
|
416
|
+
if (override)
|
|
417
|
+
return override;
|
|
418
|
+
if (process.platform === "win32" && process.env.APPDATA) {
|
|
419
|
+
return path.join(process.env.APPDATA, "gutterpress");
|
|
420
|
+
}
|
|
421
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
422
|
+
return path.join(xdg || path.join(os.homedir(), ".config"), "gutterpress");
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
class FileTokenStore {
|
|
426
|
+
filePath;
|
|
427
|
+
queue = Promise.resolve();
|
|
428
|
+
constructor(filePath) {
|
|
429
|
+
this.filePath = filePath ?? path.join(defaultConfigDir(), "credentials.json");
|
|
430
|
+
}
|
|
431
|
+
async read() {
|
|
432
|
+
let raw;
|
|
433
|
+
try {
|
|
434
|
+
raw = await readFile2(this.filePath, "utf8");
|
|
435
|
+
} catch (e) {
|
|
436
|
+
if (e?.code === "ENOENT") {
|
|
437
|
+
return { version: 1, credentials: {} };
|
|
438
|
+
}
|
|
439
|
+
throw e;
|
|
440
|
+
}
|
|
441
|
+
try {
|
|
442
|
+
const parsed = JSON.parse(raw);
|
|
443
|
+
if (parsed && typeof parsed === "object" && parsed.credentials)
|
|
444
|
+
return parsed;
|
|
445
|
+
} catch {
|
|
446
|
+
await writeFile2(`${this.filePath}.corrupt`, raw, {
|
|
447
|
+
encoding: "utf8",
|
|
448
|
+
mode: 384
|
|
449
|
+
}).catch(() => {});
|
|
450
|
+
}
|
|
451
|
+
return { version: 1, credentials: {} };
|
|
452
|
+
}
|
|
453
|
+
async write(data) {
|
|
454
|
+
await mkdir(path.dirname(this.filePath), { recursive: true });
|
|
455
|
+
const tmpPath = `${this.filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
456
|
+
await writeFile2(tmpPath, JSON.stringify(data, null, 2), {
|
|
457
|
+
encoding: "utf8",
|
|
458
|
+
mode: 384
|
|
459
|
+
});
|
|
460
|
+
await rename2(tmpPath, this.filePath);
|
|
461
|
+
await chmod(this.filePath, 384);
|
|
462
|
+
}
|
|
463
|
+
enqueue(fn) {
|
|
464
|
+
const run2 = this.queue.then(fn, fn);
|
|
465
|
+
this.queue = run2.catch(() => {
|
|
466
|
+
return;
|
|
467
|
+
});
|
|
468
|
+
return run2;
|
|
469
|
+
}
|
|
470
|
+
get(host) {
|
|
471
|
+
return this.enqueue(async () => {
|
|
472
|
+
try {
|
|
473
|
+
const data = await this.read();
|
|
474
|
+
return data.credentials[normalizeHost(host)] ?? null;
|
|
475
|
+
} catch {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
set(host, credential) {
|
|
481
|
+
return this.enqueue(async () => {
|
|
482
|
+
const data = await this.read();
|
|
483
|
+
data.credentials[normalizeHost(host)] = credential;
|
|
484
|
+
await this.write(data);
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
delete(host) {
|
|
488
|
+
return this.enqueue(async () => {
|
|
489
|
+
const data = await this.read();
|
|
490
|
+
delete data.credentials[normalizeHost(host)];
|
|
491
|
+
await this.write(data);
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
list() {
|
|
495
|
+
return this.enqueue(async () => {
|
|
496
|
+
try {
|
|
497
|
+
const data = await this.read();
|
|
498
|
+
return Object.values(data.credentials);
|
|
499
|
+
} catch {
|
|
500
|
+
return [];
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function normalizeHost(host) {
|
|
506
|
+
return host.trim().toLowerCase();
|
|
507
|
+
}
|
|
508
|
+
function extractUrlCredential(url) {
|
|
509
|
+
let parsed;
|
|
510
|
+
try {
|
|
511
|
+
parsed = new URL(url);
|
|
512
|
+
} catch {
|
|
513
|
+
return { cleanUrl: url };
|
|
514
|
+
}
|
|
515
|
+
if (!/^https?:$/.test(parsed.protocol))
|
|
516
|
+
return { cleanUrl: url };
|
|
517
|
+
if (!parsed.username && !parsed.password)
|
|
518
|
+
return { cleanUrl: url };
|
|
519
|
+
const token = parsed.password ? decodeURIComponent(parsed.password) : decodeURIComponent(parsed.username);
|
|
520
|
+
const username = parsed.password ? decodeURIComponent(parsed.username) : undefined;
|
|
521
|
+
parsed.username = "";
|
|
522
|
+
parsed.password = "";
|
|
523
|
+
const credential = {
|
|
524
|
+
host: credentialHostKey(parsed.toString()),
|
|
525
|
+
kind: "token",
|
|
526
|
+
token,
|
|
527
|
+
...username ? { username } : {},
|
|
528
|
+
createdAt: Date.now()
|
|
529
|
+
};
|
|
530
|
+
return { cleanUrl: parsed.toString(), credential };
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/lib/diagnostics.ts
|
|
534
|
+
import { platform as platform2, arch, release } from "node:os";
|
|
535
|
+
|
|
536
|
+
// src/lib/chromium.ts
|
|
537
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
538
|
+
|
|
539
|
+
// src/lib/install-hints.ts
|
|
540
|
+
var INSTALL_HINTS = {
|
|
541
|
+
chromium: {
|
|
542
|
+
label: "Google Chrome, Chromium, or Microsoft Edge",
|
|
543
|
+
body: ` macOS: brew install --cask google-chrome
|
|
544
|
+
` + ` Ubuntu: sudo apt install -y chromium-browser
|
|
545
|
+
` + " Windows: https://www.google.com/chrome/ (Edge is auto-detected if pre-installed)"
|
|
546
|
+
},
|
|
547
|
+
gs: {
|
|
548
|
+
label: "Ghostscript",
|
|
549
|
+
body: ` macOS: brew install ghostscript
|
|
550
|
+
` + ` Ubuntu: sudo apt install -y ghostscript
|
|
551
|
+
` + " Windows: https://www.ghostscript.com/releases/gsdnld.html (standard installs are auto-detected; or: choco install ghostscript)"
|
|
552
|
+
},
|
|
553
|
+
qpdf: {
|
|
554
|
+
label: "qpdf",
|
|
555
|
+
body: ` macOS: brew install qpdf
|
|
556
|
+
` + ` Ubuntu: sudo apt install -y qpdf
|
|
557
|
+
` + " Windows: choco install qpdf (or: https://github.com/qpdf/qpdf/releases)"
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
function fullInstallHint(tool) {
|
|
561
|
+
const hint = INSTALL_HINTS[tool];
|
|
562
|
+
return `Install ${hint.label}:
|
|
563
|
+
${hint.body}`;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// src/lib/chromium.ts
|
|
567
|
+
var SYSTEM_PATHS = [
|
|
568
|
+
process.env.CHROMIUM_PATH,
|
|
569
|
+
process.env.PUPPETEER_EXECUTABLE_PATH,
|
|
570
|
+
"/usr/bin/google-chrome",
|
|
571
|
+
"/usr/bin/google-chrome-stable",
|
|
572
|
+
"/usr/bin/chromium",
|
|
573
|
+
"/usr/bin/chromium-browser",
|
|
574
|
+
"/snap/bin/chromium",
|
|
575
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
576
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
577
|
+
"/opt/homebrew/bin/chromium",
|
|
578
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
579
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
580
|
+
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
581
|
+
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
582
|
+
process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe` : undefined,
|
|
583
|
+
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
584
|
+
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
585
|
+
process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\Microsoft\\Edge\\Application\\msedge.exe` : undefined,
|
|
586
|
+
process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe` : undefined
|
|
587
|
+
].filter(Boolean);
|
|
588
|
+
var PATH_CANDIDATES = [
|
|
589
|
+
"google-chrome",
|
|
590
|
+
"google-chrome-stable",
|
|
591
|
+
"chromium",
|
|
592
|
+
"chromium-browser",
|
|
593
|
+
"chrome",
|
|
594
|
+
"chrome.exe",
|
|
595
|
+
"msedge",
|
|
596
|
+
"msedge.exe",
|
|
597
|
+
"brave",
|
|
598
|
+
"brave-browser",
|
|
599
|
+
"brave.exe",
|
|
600
|
+
"vivaldi",
|
|
601
|
+
"vivaldi-stable",
|
|
602
|
+
"vivaldi.exe",
|
|
603
|
+
"opera",
|
|
604
|
+
"opera-stable",
|
|
605
|
+
"opera.exe"
|
|
606
|
+
];
|
|
607
|
+
async function resolveChromiumExecutable() {
|
|
608
|
+
for (const candidate of SYSTEM_PATHS) {
|
|
609
|
+
if (existsSync2(candidate))
|
|
610
|
+
return candidate;
|
|
611
|
+
}
|
|
612
|
+
for (const candidate of PATH_CANDIDATES) {
|
|
613
|
+
const found = await findTool(candidate);
|
|
614
|
+
if (found)
|
|
615
|
+
return found;
|
|
616
|
+
}
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
async function requireChromiumExecutable() {
|
|
620
|
+
const found = await resolveChromiumExecutable();
|
|
621
|
+
if (found)
|
|
622
|
+
return found;
|
|
623
|
+
throw new Error([
|
|
624
|
+
"No Chrome / Chromium / Edge binary found. Gutterpress needs a Chromium-based browser to render PDFs.",
|
|
625
|
+
"",
|
|
626
|
+
"Install one of:",
|
|
627
|
+
INSTALL_HINTS.chromium.body,
|
|
628
|
+
"",
|
|
629
|
+
"Or point to an existing install:",
|
|
630
|
+
" CHROMIUM_PATH=/path/to/chrome gutterpress build ...",
|
|
631
|
+
"",
|
|
632
|
+
"The Gutterpress desktop app includes its own browser and needs no separate browser installation."
|
|
633
|
+
].join(`
|
|
634
|
+
`));
|
|
635
|
+
}
|
|
636
|
+
|
|
637
637
|
// src/lib/version.ts
|
|
638
638
|
var PACKAGE_META = {
|
|
639
639
|
version: package_default.version ?? "unknown",
|
|
@@ -739,7 +739,7 @@ async function getSystemDiagnostics() {
|
|
|
739
739
|
},
|
|
740
740
|
tools: [chromium, ...tools],
|
|
741
741
|
configDir: defaultConfigDir(),
|
|
742
|
-
docsUrl: "https://github.com/dimm-city/gutterpress/blob/main/examples/gutterpress-user-guide/
|
|
742
|
+
docsUrl: "https://github.com/dimm-city/gutterpress/blob/main/examples/gutterpress-user-guide/07-system-setup.md"
|
|
743
743
|
};
|
|
744
744
|
}
|
|
745
745
|
|
|
@@ -86,6 +86,9 @@ async function detectProjectSource(folderPath) {
|
|
|
86
86
|
}
|
|
87
87
|
return { type: "local-folder", path: folderPath };
|
|
88
88
|
}
|
|
89
|
+
function repoRootForSource(source, fallbackDir) {
|
|
90
|
+
return source.type === "local-git-folder" ? source.repoRoot || fallbackDir : fallbackDir;
|
|
91
|
+
}
|
|
89
92
|
function capabilitiesFor(source) {
|
|
90
93
|
switch (source.type) {
|
|
91
94
|
case "local-folder":
|
|
@@ -121,4 +124,4 @@ function capabilitiesFor(source) {
|
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
126
|
|
|
124
|
-
export {
|
|
127
|
+
export { syncRemoteFor, findEnclosingRepoDir, repoSubPath, detectProjectSource, repoRootForSource, capabilitiesFor };
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
capabilitiesFor,
|
|
3
3
|
detectProjectSource,
|
|
4
4
|
findEnclosingRepoDir
|
|
5
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-wchtvxvw.js";
|
|
6
6
|
|
|
7
7
|
// src/lib/source-provider.ts
|
|
8
8
|
import * as fs from "node:fs";
|
|
@@ -461,4 +461,4 @@ async function restoreVersionWithBackup(options) {
|
|
|
461
461
|
});
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
-
export { resolveLogger, shortOid, gitScopeFor, HISTORY_PAGE_LIMIT,
|
|
464
|
+
export { resolveLogger, shortOid, gitScopeFor, HISTORY_PAGE_LIMIT, withRepoLock, __repoLockQueueSizeForTests, resolveGitAuthor, listWorkdirChanges, stageChanges, hasPendingChanges, hasUncommittedChanges, snapshotWorkingTreeUnlocked, isNoChangesError, providerFor, gitDirFor, snapshotStagingMarkerPath, RESTORE_BACKUP_MESSAGE, AUTO_SNAPSHOT_MESSAGE, restoreVersionWithBackup };
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
UsageError,
|
|
8
8
|
package_default,
|
|
9
9
|
rejectUnknownFlags
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-e5zhb0xs.js";
|
|
11
11
|
import {
|
|
12
12
|
__require
|
|
13
13
|
} from "./cli-37x76zdn.js";
|
|
@@ -16,17 +16,17 @@ import {
|
|
|
16
16
|
import { defineCommand, parseArgs, runMain } from "citty";
|
|
17
17
|
import { statSync } from "node:fs";
|
|
18
18
|
var SUBCOMMANDS = {
|
|
19
|
-
new: () => import("./new-
|
|
20
|
-
preview: () => import("./preview-
|
|
21
|
-
build: () => import("./build-
|
|
22
|
-
publish: () => import("./publish-
|
|
23
|
-
lint: () => import("./lint-
|
|
24
|
-
validate: () => import("./validate-
|
|
25
|
-
audit: () => import("./audit-
|
|
26
|
-
preflight: () => import("./preflight-
|
|
27
|
-
repair: () => import("./repair-
|
|
28
|
-
doctor: () => import("./doctor-
|
|
29
|
-
plugin: () => import("./plugin-
|
|
19
|
+
new: () => import("./new-8p38wavc.js").then((m) => m.default),
|
|
20
|
+
preview: () => import("./preview-y5a2zen1.js").then((m) => m.default),
|
|
21
|
+
build: () => import("./build-san7fv2z.js").then((m) => m.default),
|
|
22
|
+
publish: () => import("./publish-rm9yb3wh.js").then((m) => m.default),
|
|
23
|
+
lint: () => import("./lint-96j9hrj4.js").then((m) => m.default),
|
|
24
|
+
validate: () => import("./validate-nr0xa6sa.js").then((m) => m.default),
|
|
25
|
+
audit: () => import("./audit-nhn2pjz3.js").then((m) => m.default),
|
|
26
|
+
preflight: () => import("./preflight-1q6c2edh.js").then((m) => m.default),
|
|
27
|
+
repair: () => import("./repair-zgq7q2g6.js").then((m) => m.default),
|
|
28
|
+
doctor: () => import("./doctor-hrk0kxxz.js").then((m) => m.default),
|
|
29
|
+
plugin: () => import("./plugin-ees6nhkc.js").then((m) => m.default)
|
|
30
30
|
};
|
|
31
31
|
var VERSION = package_default.version;
|
|
32
32
|
var main = defineCommand({
|
|
@@ -51,7 +51,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
51
51
|
const [command, ...commandArgs] = rawArgs;
|
|
52
52
|
try {
|
|
53
53
|
if (command === "new") {
|
|
54
|
-
const { newArgs } = await import("./new-
|
|
54
|
+
const { newArgs } = await import("./new-8p38wavc.js");
|
|
55
55
|
rejectUnknownFlags(commandArgs, newArgs, "new");
|
|
56
56
|
const parsed2 = parseArgs(commandArgs, {
|
|
57
57
|
...newArgs,
|
|
@@ -63,7 +63,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
if (command === "preflight") {
|
|
66
|
-
const { preflightArgs } = await import("./preflight-
|
|
66
|
+
const { preflightArgs } = await import("./preflight-1q6c2edh.js");
|
|
67
67
|
rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
|
|
68
68
|
const parsed2 = parseArgs(commandArgs, {
|
|
69
69
|
...preflightArgs,
|
|
@@ -87,7 +87,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
87
87
|
if (subcommand !== "add") {
|
|
88
88
|
throw new UsageError(`gutterpress plugin: unknown command "${subcommand}"`);
|
|
89
89
|
}
|
|
90
|
-
const { pluginAddArgs } = await import("./plugin-
|
|
90
|
+
const { pluginAddArgs } = await import("./plugin-ees6nhkc.js");
|
|
91
91
|
rejectUnknownFlags(subcommandArgs, pluginAddArgs, "plugin add");
|
|
92
92
|
const parsed = parseArgs(subcommandArgs, {
|
|
93
93
|
...pluginAddArgs,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSystemDiagnostics,
|
|
3
3
|
log
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-najycadg.js";
|
|
5
5
|
import {
|
|
6
6
|
UsageError,
|
|
7
7
|
rejectExtraPositionals,
|
|
8
8
|
rejectUnknownFlags
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-e5zhb0xs.js";
|
|
10
10
|
import"./cli-37x76zdn.js";
|
|
11
11
|
|
|
12
12
|
// src/commands/doctor.ts
|