gutterpress 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +422 -0
- package/dist/CGATS21_CRPC1-g0e3k7kr.icc +0 -0
- package/dist/api/index.d.ts +76 -0
- package/dist/api/index.js +272 -0
- package/dist/assets/preview/scripts/pagedjs-bridge.d.ts +1 -0
- package/dist/assets/preview/scripts/pagedjs-interface.d.ts +1 -0
- package/dist/assets/preview/scripts/preview-shell.d.ts +1 -0
- package/dist/audit-1jrwwacz.js +66 -0
- package/dist/build-5s92kgpc.js +77 -0
- package/dist/chapter-01-6fn9pvd0.md +31 -0
- package/dist/chapter-01-7jwqg1ct.md +20 -0
- package/dist/chapter-01-jj8ftn4c.md +29 -0
- package/dist/chapter-01-rkpyvjna.md +26 -0
- package/dist/checks/asset/approved-fonts.d.ts +3 -0
- package/dist/checks/asset/extensions.d.ts +41 -0
- package/dist/checks/asset/font-license.d.ts +3 -0
- package/dist/checks/asset/image-alpha.d.ts +3 -0
- package/dist/checks/asset/image-color-space.d.ts +3 -0
- package/dist/checks/asset/image-file-size.d.ts +3 -0
- package/dist/checks/asset/image-resolution.d.ts +3 -0
- package/dist/checks/asset/image-tac.d.ts +3 -0
- package/dist/checks/asset/index.d.ts +7 -0
- package/dist/checks/formatter.d.ts +3 -0
- package/dist/checks/heuristic/index.d.ts +4 -0
- package/dist/checks/heuristic/layer-count.d.ts +3 -0
- package/dist/checks/heuristic/placement-variance.d.ts +3 -0
- package/dist/checks/heuristic/section-density.d.ts +3 -0
- package/dist/checks/heuristic/text-density.d.ts +3 -0
- package/dist/checks/pdf/bleed.d.ts +3 -0
- package/dist/checks/pdf/bookmarks.d.ts +3 -0
- package/dist/checks/pdf/color-spaces.d.ts +3 -0
- package/dist/checks/pdf/cross-refs.d.ts +3 -0
- package/dist/checks/pdf/embedded-fonts.d.ts +3 -0
- package/dist/checks/pdf/image-resolution.d.ts +3 -0
- package/dist/checks/pdf/index.d.ts +15 -0
- package/dist/checks/pdf/ink-coverage.d.ts +3 -0
- package/dist/checks/pdf/page-labels.d.ts +3 -0
- package/dist/checks/pdf/page-size.d.ts +3 -0
- package/dist/checks/pdf/pdfx-markers.d.ts +3 -0
- package/dist/checks/pdf/pdfx-metadata.d.ts +3 -0
- package/dist/checks/pdf/pdfx-structure.d.ts +6 -0
- package/dist/checks/pdf/qpdf-structure.d.ts +3 -0
- package/dist/checks/pdf/rasterized-pages.d.ts +3 -0
- package/dist/checks/pdf/toc-links.d.ts +3 -0
- package/dist/checks/pdf/transparency.d.ts +3 -0
- package/dist/checks/policy.d.ts +61 -0
- package/dist/checks/register-builtins.d.ts +17 -0
- package/dist/checks/registry.d.ts +40 -0
- package/dist/checks/runner.d.ts +25 -0
- package/dist/checks/source/accessibility-alt-text.d.ts +3 -0
- package/dist/checks/source/accessibility-heading-order.d.ts +3 -0
- package/dist/checks/source/config-file.d.ts +8 -0
- package/dist/checks/source/htmlhint.d.ts +3 -0
- package/dist/checks/source/index.d.ts +6 -0
- package/dist/checks/source/local-refs.d.ts +3 -0
- package/dist/checks/source/markdownlint.d.ts +3 -0
- package/dist/checks/source/stylelint.d.ts +3 -0
- package/dist/checks/tool-check.d.ts +23 -0
- package/dist/checks/types.d.ts +52 -0
- package/dist/cli-1tyj4bk3.js +124 -0
- package/dist/cli-37x76zdn.js +4 -0
- package/dist/cli-506tg37g.js +26 -0
- package/dist/cli-5bxx0c4y.js +464 -0
- package/dist/cli-7ykx7pp0.js +12378 -0
- package/dist/cli-h7phg3ka.js +746 -0
- package/dist/cli-hvqjs342.js +284 -0
- package/dist/cli-yja077f6.js +92 -0
- package/dist/cli.js +157 -0
- package/dist/constants.d.ts +17 -0
- package/dist/doctor-25zjt8dz.js +57 -0
- package/dist/favicon-wkbm9cjn.ico +0 -0
- package/dist/git-http-yrb4ag6z.js +17 -0
- package/dist/index-1tyj4bk3.js +124 -0
- package/dist/index-37x76zdn.js +4 -0
- package/dist/index-3h3fef7r.js +15218 -0
- package/dist/index-5bxx0c4y.js +464 -0
- package/dist/index-yja077f6.js +92 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +310 -0
- package/dist/lib/app-heartbeat.d.ts +102 -0
- package/dist/lib/asset-inline.d.ts +73 -0
- package/dist/lib/browser-pool.d.ts +17 -0
- package/dist/lib/build-error.d.ts +52 -0
- package/dist/lib/build-fingerprint.d.ts +15 -0
- package/dist/lib/build-preflight.d.ts +43 -0
- package/dist/lib/build-runner.d.ts +161 -0
- package/dist/lib/build-staging.d.ts +64 -0
- package/dist/lib/chromium.d.ts +20 -0
- package/dist/lib/cli-args.d.ts +45 -0
- package/dist/lib/desktop.d.ts +14 -0
- package/dist/lib/diagnostics.d.ts +64 -0
- package/dist/lib/embedded-assets.d.ts +29 -0
- package/dist/lib/exec.d.ts +84 -0
- package/dist/lib/fetch-timeout.d.ts +41 -0
- package/dist/lib/ghostscript.d.ts +48 -0
- package/dist/lib/host-policy.d.ts +75 -0
- package/dist/lib/image-inspect.d.ts +32 -0
- package/dist/lib/install-hints.d.ts +21 -0
- package/dist/lib/lint-runner.d.ts +10 -0
- package/dist/lib/manifest-config.d.ts +31 -0
- package/dist/lib/manifest-doc.d.ts +25 -0
- package/dist/lib/manifest.d.ts +41 -0
- package/dist/lib/markdown/assemble.d.ts +78 -0
- package/dist/lib/markdown/chapter-id.d.ts +24 -0
- package/dist/lib/markdown/images.d.ts +34 -0
- package/dist/lib/markdown/index.d.ts +78 -0
- package/dist/lib/markdown/markdown-it-paged.d.ts +30 -0
- package/dist/lib/markdown/plugins.d.ts +69 -0
- package/dist/lib/markdown/renderer.d.ts +111 -0
- package/dist/lib/npm-plugin-installer.d.ts +33 -0
- package/dist/lib/open-path.d.ts +5 -0
- package/dist/lib/output-paths.d.ts +23 -0
- package/dist/lib/pagedjs-marker.d.ts +42 -0
- package/dist/lib/pagedjs.d.ts +26 -0
- package/dist/lib/pagination.d.ts +169 -0
- package/dist/lib/pdf-inspect.d.ts +123 -0
- package/dist/lib/pdf-parse.d.ts +57 -0
- package/dist/lib/plugin-manager.d.ts +108 -0
- package/dist/lib/plugin-vendor.d.ts +107 -0
- package/dist/lib/presets.d.ts +45 -0
- package/dist/lib/printsafe.d.ts +17 -0
- package/dist/lib/project-scaffold.d.ts +116 -0
- package/dist/lib/project-source.d.ts +140 -0
- package/dist/lib/project-templates.d.ts +49 -0
- package/dist/lib/publish/butler.d.ts +10 -0
- package/dist/lib/publish/command-runner.d.ts +18 -0
- package/dist/lib/publish/connect.d.ts +23 -0
- package/dist/lib/publish/manifest-publish.d.ts +9 -0
- package/dist/lib/publish/providers/azure-swa.d.ts +3 -0
- package/dist/lib/publish/providers/drivethrurpg.d.ts +10 -0
- package/dist/lib/publish/providers/guided.d.ts +3 -0
- package/dist/lib/publish/providers/itch.d.ts +5 -0
- package/dist/lib/publish/providers/kdp.d.ts +9 -0
- package/dist/lib/publish/providers/shopify.d.ts +5 -0
- package/dist/lib/publish/registry.d.ts +5 -0
- package/dist/lib/publish/run-publish.d.ts +30 -0
- package/dist/lib/publish/selections.d.ts +25 -0
- package/dist/lib/publish/types.d.ts +258 -0
- package/dist/lib/remote-auth/clone.d.ts +87 -0
- package/dist/lib/remote-auth/conflict-resolution.d.ts +29 -0
- package/dist/lib/remote-auth/diagnose.d.ts +77 -0
- package/dist/lib/remote-auth/generic-auth.d.ts +97 -0
- package/dist/lib/remote-auth/git-http.d.ts +85 -0
- package/dist/lib/remote-auth/github-auth.d.ts +69 -0
- package/dist/lib/remote-auth/github-repos.d.ts +64 -0
- package/dist/lib/remote-auth/operation-log.d.ts +66 -0
- package/dist/lib/remote-auth/recovery/abort-interrupted-operation.d.ts +103 -0
- package/dist/lib/remote-auth/recovery/backup.d.ts +113 -0
- package/dist/lib/remote-auth/recovery/classify.d.ts +109 -0
- package/dist/lib/remote-auth/recovery/context.d.ts +47 -0
- package/dist/lib/remote-auth/recovery/dispatch.d.ts +33 -0
- package/dist/lib/remote-auth/recovery/failsafe.d.ts +33 -0
- package/dist/lib/remote-auth/recovery/inspect.d.ts +74 -0
- package/dist/lib/remote-auth/recovery/manual-guidance.d.ts +28 -0
- package/dist/lib/remote-auth/recovery/outcome-mapping.d.ts +58 -0
- package/dist/lib/remote-auth/recovery/policy.d.ts +47 -0
- package/dist/lib/remote-auth/recovery/recover-auth.d.ts +42 -0
- package/dist/lib/remote-auth/recovery/recover-binary-conflict.d.ts +37 -0
- package/dist/lib/remote-auth/recovery/recover-corrupt-index.d.ts +40 -0
- package/dist/lib/remote-auth/recovery/recover-detached-head.d.ts +70 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-cherry-pick.d.ts +23 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-merge.d.ts +28 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-rebase.d.ts +39 -0
- package/dist/lib/remote-auth/recovery/recover-merge-conflict.d.ts +34 -0
- package/dist/lib/remote-auth/recovery/recover-missing-git-dir.d.ts +37 -0
- package/dist/lib/remote-auth/recovery/recover-missing-objects.d.ts +56 -0
- package/dist/lib/remote-auth/recovery/recover-network.d.ts +34 -0
- package/dist/lib/remote-auth/recovery/recover-non-fast-forward.d.ts +27 -0
- package/dist/lib/remote-auth/recovery/recover-stale-lock.d.ts +76 -0
- package/dist/lib/remote-auth/recovery/recover-unrelated-histories.d.ts +44 -0
- package/dist/lib/remote-auth/recovery/recover-wrong-remote.d.ts +35 -0
- package/dist/lib/remote-auth/recovery/types.d.ts +235 -0
- package/dist/lib/remote-auth/resolution-plan.d.ts +64 -0
- package/dist/lib/remote-auth/sync-messages.d.ts +26 -0
- package/dist/lib/remote-auth/sync-types.d.ts +225 -0
- package/dist/lib/remote-auth/sync.d.ts +45 -0
- package/dist/lib/remote-auth/test-access.d.ts +47 -0
- package/dist/lib/remote-auth/test-support/git-http-server.d.ts +71 -0
- package/dist/lib/remote-auth/token-store.d.ts +95 -0
- package/dist/lib/remote-auth/transport.d.ts +105 -0
- package/dist/lib/slug.d.ts +28 -0
- package/dist/lib/snippets.d.ts +39 -0
- package/dist/lib/source-provider.d.ts +244 -0
- package/dist/lib/static-serve.d.ts +54 -0
- package/dist/lib/style-resolver.d.ts +30 -0
- package/dist/lib/theme-import.d.ts +70 -0
- package/dist/lib/theme-manager.d.ts +128 -0
- package/dist/lib/tool-probe.d.ts +37 -0
- package/dist/lib/validation-exec.d.ts +47 -0
- package/dist/lib/validation-profile.d.ts +18 -0
- package/dist/lib/version.d.ts +9 -0
- package/dist/lint-f63nxjfj.js +65 -0
- package/dist/manifest-n1gh3qw5.yaml +9 -0
- package/dist/manifest-ryyg71nf.yaml +9 -0
- package/dist/manifest.schema-rn1dpdpn.json +564 -0
- package/dist/new-7b08a42h.js +105 -0
- package/dist/paged.polyfill-n95pbxfn.js +33288 -0
- package/dist/pagedjs-bridge-vn4hk9fx.js +111 -0
- package/dist/pagedjs-interface-80g3xa8p.js +498 -0
- package/dist/platform.d.ts +100 -0
- package/dist/plugin-wf2cbmwc.js +129 -0
- package/dist/preflight-tg4mpz1h.js +222 -0
- package/dist/preview/file-watcher.d.ts +174 -0
- package/dist/preview/http-server.d.ts +45 -0
- package/dist/preview/lifecycle.d.ts +67 -0
- package/dist/preview/server-context.d.ts +36 -0
- package/dist/preview-h2bwbb2x.js +102 -0
- package/dist/preview-shell-rghtfmc8.js +155 -0
- package/dist/project-source-0tg0r6vm.js +17 -0
- package/dist/publish-ztaet53r.js +233 -0
- package/dist/render.d.ts +20 -0
- package/dist/render.js +682 -0
- package/dist/repair-jkp4n3j8.js +171 -0
- package/dist/schema/manifest.types.d.ts +218 -0
- package/dist/server.d.ts +34 -0
- package/dist/source-provider-hp96b5jf.js +46 -0
- package/dist/test-helpers/testkit.d.ts +91 -0
- package/dist/theme-0yzvthe8.css +65 -0
- package/dist/theme-570zmh2t.css +58 -0
- package/dist/theme-6a2fngc8.json +6 -0
- package/dist/theme-cd6efzjw.json +6 -0
- package/dist/theme-nya4nqh6.css +70 -0
- package/dist/theme-tqfypc1w.json +6 -0
- package/dist/theme-xt0hjb1b.json +6 -0
- package/dist/theme-zz2ktzqs.css +60 -0
- package/dist/types.d.ts +31 -0
- package/dist/utils/file-utils.d.ts +53 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/validate-k2drs19j.js +99 -0
- package/package.json +102 -0
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
import {
|
|
2
|
+
package_default
|
|
3
|
+
} from "./cli-hvqjs342.js";
|
|
4
|
+
import {
|
|
5
|
+
__require
|
|
6
|
+
} from "./cli-37x76zdn.js";
|
|
7
|
+
|
|
8
|
+
// src/utils/logger.ts
|
|
9
|
+
var currentLevel = "INFO";
|
|
10
|
+
var LEVELS = {
|
|
11
|
+
DEBUG: 0,
|
|
12
|
+
INFO: 1,
|
|
13
|
+
WARN: 2,
|
|
14
|
+
ERROR: 3
|
|
15
|
+
};
|
|
16
|
+
function setLogLevel(level) {
|
|
17
|
+
currentLevel = level;
|
|
18
|
+
}
|
|
19
|
+
function emit(level, message, ...args) {
|
|
20
|
+
if (LEVELS[level] < LEVELS[currentLevel])
|
|
21
|
+
return;
|
|
22
|
+
const colors = {
|
|
23
|
+
DEBUG: "\x1B[36m",
|
|
24
|
+
INFO: "\x1B[32m",
|
|
25
|
+
WARN: "\x1B[33m",
|
|
26
|
+
ERROR: "\x1B[31m"
|
|
27
|
+
};
|
|
28
|
+
const reset = "\x1B[0m";
|
|
29
|
+
const timestamp = new Date().toISOString().slice(11, 19);
|
|
30
|
+
const prefix = `${colors[level]}[${timestamp}] ${level}${reset}:`;
|
|
31
|
+
if (level === "ERROR") {
|
|
32
|
+
console.error(prefix, message, ...args);
|
|
33
|
+
} else {
|
|
34
|
+
console.log(prefix, message, ...args);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function debug(message, ...args) {
|
|
38
|
+
emit("DEBUG", message, ...args);
|
|
39
|
+
}
|
|
40
|
+
function info(message, ...args) {
|
|
41
|
+
emit("INFO", message, ...args);
|
|
42
|
+
}
|
|
43
|
+
function warn(message, ...args) {
|
|
44
|
+
emit("WARN", message, ...args);
|
|
45
|
+
}
|
|
46
|
+
function error(message, ...args) {
|
|
47
|
+
emit("ERROR", message, ...args);
|
|
48
|
+
}
|
|
49
|
+
var RESET = "\x1B[0m";
|
|
50
|
+
var BOLD = "\x1B[1m";
|
|
51
|
+
var RED = "\x1B[31m";
|
|
52
|
+
var YELLOW = "\x1B[33m";
|
|
53
|
+
var GREEN = "\x1B[32m";
|
|
54
|
+
var CYAN = "\x1B[36m";
|
|
55
|
+
var log = {
|
|
56
|
+
info(msg, ...args) {
|
|
57
|
+
console.log(`${CYAN}info${RESET} ${msg}`, ...args);
|
|
58
|
+
},
|
|
59
|
+
warn(msg, ...args) {
|
|
60
|
+
console.warn(`${YELLOW}warn${RESET} ${msg}`, ...args);
|
|
61
|
+
},
|
|
62
|
+
error(msg, ...args) {
|
|
63
|
+
console.error(`${RED}${BOLD}error${RESET} ${msg}`, ...args);
|
|
64
|
+
},
|
|
65
|
+
success(msg, ...args) {
|
|
66
|
+
console.log(`${GREEN}ok${RESET} ${msg}`, ...args);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
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
|
+
// src/lib/tool-probe.ts
|
|
221
|
+
import { platform } from "node:os";
|
|
222
|
+
|
|
223
|
+
// src/lib/exec.ts
|
|
224
|
+
import { spawn } from "node:child_process";
|
|
225
|
+
import { join, resolve as resolvePath, delimiter } from "node:path";
|
|
226
|
+
function buildEnhancedPath(dir, existingPath, sep = delimiter) {
|
|
227
|
+
return `${dir}${sep}${existingPath}`;
|
|
228
|
+
}
|
|
229
|
+
var localBin = resolvePath(join(import.meta.dirname, "..", "..", "node_modules", ".bin"));
|
|
230
|
+
var enhancedPath = buildEnhancedPath(localBin, process.env.PATH ?? "");
|
|
231
|
+
function enhancedEnv() {
|
|
232
|
+
return { ...process.env, PATH: enhancedPath };
|
|
233
|
+
}
|
|
234
|
+
function run(cmd, args, opts = {}) {
|
|
235
|
+
return new Promise((resolve, reject) => {
|
|
236
|
+
const p = spawn(cmd, args, { stdio: "inherit", cwd: opts.cwd, env: enhancedEnv() });
|
|
237
|
+
p.on("error", reject);
|
|
238
|
+
p.on("exit", (code) => {
|
|
239
|
+
if (code === 0)
|
|
240
|
+
return resolve();
|
|
241
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
242
|
+
reject(new Error(`${cmd} ${args.join(" ")} (cwd=${cwd}) exited ${code}`));
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
var EXIT_FLUSH_GRACE_MS = 2000;
|
|
247
|
+
function keepTail(buffer, chunk, limit) {
|
|
248
|
+
const joined = buffer + chunk;
|
|
249
|
+
return limit !== undefined && joined.length > limit ? joined.slice(-limit) : joined;
|
|
250
|
+
}
|
|
251
|
+
function spawnCapture(cmd, args, opts = {}) {
|
|
252
|
+
return new Promise((resolve, reject) => {
|
|
253
|
+
const p = spawn(cmd, args, {
|
|
254
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
255
|
+
cwd: opts.cwd,
|
|
256
|
+
env: opts.env
|
|
257
|
+
});
|
|
258
|
+
let stdout = "";
|
|
259
|
+
let stderr = "";
|
|
260
|
+
let settled = false;
|
|
261
|
+
let exited = false;
|
|
262
|
+
let exitCode = null;
|
|
263
|
+
let exitSignal = null;
|
|
264
|
+
let killTimer;
|
|
265
|
+
let graceTimer;
|
|
266
|
+
const settle = (fn) => {
|
|
267
|
+
if (settled)
|
|
268
|
+
return;
|
|
269
|
+
settled = true;
|
|
270
|
+
if (killTimer)
|
|
271
|
+
clearTimeout(killTimer);
|
|
272
|
+
if (graceTimer)
|
|
273
|
+
clearTimeout(graceTimer);
|
|
274
|
+
fn();
|
|
275
|
+
};
|
|
276
|
+
const armKill = () => {
|
|
277
|
+
if (!opts.timeoutMs)
|
|
278
|
+
return;
|
|
279
|
+
if (killTimer)
|
|
280
|
+
clearTimeout(killTimer);
|
|
281
|
+
killTimer = setTimeout(() => {
|
|
282
|
+
settle(() => {
|
|
283
|
+
p.kill("SIGKILL");
|
|
284
|
+
reject(new Error(opts.timeoutMode === "idle" ? `${cmd} produced no output for ${opts.timeoutMs}ms and was stopped` : `${cmd} ${args.join(" ")} timed out after ${opts.timeoutMs}ms`));
|
|
285
|
+
});
|
|
286
|
+
}, opts.timeoutMs);
|
|
287
|
+
killTimer.unref();
|
|
288
|
+
};
|
|
289
|
+
armKill();
|
|
290
|
+
const finish = () => settle(() => resolve({ code: exitCode, signal: exitSignal, stdout, stderr }));
|
|
291
|
+
const armGrace = () => {
|
|
292
|
+
if (graceTimer)
|
|
293
|
+
clearTimeout(graceTimer);
|
|
294
|
+
graceTimer = setTimeout(finish, opts.exitGraceMs ?? EXIT_FLUSH_GRACE_MS);
|
|
295
|
+
graceTimer.unref();
|
|
296
|
+
};
|
|
297
|
+
const onData = (stream) => (d) => {
|
|
298
|
+
const text = d.toString();
|
|
299
|
+
if (stream === "stdout")
|
|
300
|
+
stdout = keepTail(stdout, text, opts.captureLimit);
|
|
301
|
+
else
|
|
302
|
+
stderr = keepTail(stderr, text, opts.captureLimit);
|
|
303
|
+
opts.onChunk?.(stream, text);
|
|
304
|
+
if (exited)
|
|
305
|
+
armGrace();
|
|
306
|
+
else if (opts.timeoutMode === "idle")
|
|
307
|
+
armKill();
|
|
308
|
+
};
|
|
309
|
+
p.stdout.on("data", onData("stdout"));
|
|
310
|
+
p.stderr.on("data", onData("stderr"));
|
|
311
|
+
p.on("error", (err) => settle(() => reject(err)));
|
|
312
|
+
p.on("exit", (code, signal) => {
|
|
313
|
+
exited = true;
|
|
314
|
+
exitCode = code;
|
|
315
|
+
exitSignal = signal;
|
|
316
|
+
if (killTimer) {
|
|
317
|
+
clearTimeout(killTimer);
|
|
318
|
+
killTimer = undefined;
|
|
319
|
+
}
|
|
320
|
+
armGrace();
|
|
321
|
+
});
|
|
322
|
+
p.on("close", finish);
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
async function execCapture(cmd, args, opts = {}) {
|
|
326
|
+
const { code, signal, stdout, stderr } = await spawnCapture(cmd, args, {
|
|
327
|
+
cwd: opts.cwd,
|
|
328
|
+
env: enhancedEnv(),
|
|
329
|
+
timeoutMs: opts.timeoutMs
|
|
330
|
+
});
|
|
331
|
+
if (code === 0)
|
|
332
|
+
return { stdout, stderr };
|
|
333
|
+
throw new Error(code === null ? `${cmd} was killed by signal ${signal}
|
|
334
|
+
${stderr}` : `${cmd} exited ${code}
|
|
335
|
+
${stderr}`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/lib/tool-probe.ts
|
|
339
|
+
var IS_WINDOWS = platform() === "win32";
|
|
340
|
+
var PROBE_CMD = IS_WINDOWS ? "where.exe" : "which";
|
|
341
|
+
async function isToolAvailable(tool) {
|
|
342
|
+
try {
|
|
343
|
+
await execCapture(PROBE_CMD, [tool]);
|
|
344
|
+
return true;
|
|
345
|
+
} catch {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async function findTool(tool) {
|
|
350
|
+
try {
|
|
351
|
+
const { stdout } = await execCapture(PROBE_CMD, [tool]);
|
|
352
|
+
const firstLine = stdout.split(/\r?\n/).find((line) => line.trim().length > 0);
|
|
353
|
+
return firstLine?.trim() || undefined;
|
|
354
|
+
} catch {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
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
|
+
// src/lib/ghostscript.ts
|
|
458
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
459
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, rename as rename2, readdir } from "node:fs/promises";
|
|
460
|
+
import { join as join2, basename, resolve } from "node:path";
|
|
461
|
+
var WINDOWS_GHOSTSCRIPT_NAMES = ["gswin64c", "gswin32c", "gs"];
|
|
462
|
+
var POSIX_GHOSTSCRIPT_NAMES = ["gs"];
|
|
463
|
+
function envValue(env, name) {
|
|
464
|
+
const direct = env[name]?.trim();
|
|
465
|
+
if (direct)
|
|
466
|
+
return direct;
|
|
467
|
+
const key = Object.keys(env).find((candidate) => candidate.toLowerCase() === name.toLowerCase());
|
|
468
|
+
return key ? env[key]?.trim() || undefined : undefined;
|
|
469
|
+
}
|
|
470
|
+
async function findWindowsGhostscriptInstall(env) {
|
|
471
|
+
const roots = [
|
|
472
|
+
envValue(env, "ProgramW6432"),
|
|
473
|
+
envValue(env, "ProgramFiles"),
|
|
474
|
+
"C:\\Program Files",
|
|
475
|
+
envValue(env, "ProgramFiles(x86)"),
|
|
476
|
+
"C:\\Program Files (x86)"
|
|
477
|
+
];
|
|
478
|
+
const seen = new Set;
|
|
479
|
+
for (const root of roots) {
|
|
480
|
+
if (!root || seen.has(root.toLowerCase()))
|
|
481
|
+
continue;
|
|
482
|
+
seen.add(root.toLowerCase());
|
|
483
|
+
const installRoot = join2(root, "gs");
|
|
484
|
+
let versions;
|
|
485
|
+
try {
|
|
486
|
+
versions = (await readdir(installRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^gs\d/i.test(entry.name)).sort((a, b) => b.name.localeCompare(a.name, undefined, { numeric: true }));
|
|
487
|
+
} catch {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
for (const version of versions) {
|
|
491
|
+
for (const executable of ["gswin64c.exe", "gswin32c.exe"]) {
|
|
492
|
+
const candidate = join2(installRoot, version.name, "bin", executable);
|
|
493
|
+
if (existsSync2(candidate))
|
|
494
|
+
return candidate;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
async function resolveGhostscript(targetPlatform = process.platform, env = process.env) {
|
|
501
|
+
const override = envValue(env, "GHOSTSCRIPT_PATH");
|
|
502
|
+
if (override && existsSync2(override))
|
|
503
|
+
return override;
|
|
504
|
+
const names = targetPlatform === "win32" ? WINDOWS_GHOSTSCRIPT_NAMES : POSIX_GHOSTSCRIPT_NAMES;
|
|
505
|
+
for (const name of names) {
|
|
506
|
+
const found = await findTool(name);
|
|
507
|
+
if (found)
|
|
508
|
+
return found;
|
|
509
|
+
}
|
|
510
|
+
return targetPlatform === "win32" ? findWindowsGhostscriptInstall(env) : undefined;
|
|
511
|
+
}
|
|
512
|
+
async function stripAnnotations(pdfPath, stagingDir) {
|
|
513
|
+
const tmp = join2(stagingDir, "annotations-stripped.pdf");
|
|
514
|
+
try {
|
|
515
|
+
await run("qpdf", [pdfPath, tmp, "--flatten-annotations=all"]);
|
|
516
|
+
await rename2(tmp, pdfPath);
|
|
517
|
+
} finally {
|
|
518
|
+
await unlink(tmp).catch(() => {});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
function makePdfxDefPs(params) {
|
|
522
|
+
const pdfxVersion = params.pdfx === "x3" ? "PDF/X-3:2002" : "PDF/X-1:2001";
|
|
523
|
+
const pdfxConformance = params.pdfx === "x1a" ? "PDF/X-1a:2001" : null;
|
|
524
|
+
const outputCondition = "CGATS21_CRPC1";
|
|
525
|
+
const outputConditionId = params.pdfx === "x1a" ? "CGATS TR001" : outputCondition;
|
|
526
|
+
const maxTacNorm = ((params.maxTac ?? 240) / 100).toFixed(1);
|
|
527
|
+
const normalizedIccPath = params.iccPath.replace(/\\/g, "/");
|
|
528
|
+
const iccComponents = 4;
|
|
529
|
+
const docInfoConformance = pdfxConformance ? `/GTS_PDFXConformance (${pdfxConformance})
|
|
530
|
+
` : "";
|
|
531
|
+
return `
|
|
532
|
+
%!
|
|
533
|
+
% pdfx_def.ps generated by gutterpress
|
|
534
|
+
% Based on the Ghostscript PDF/X approach with custom GCR for TAC limiting
|
|
535
|
+
|
|
536
|
+
/ICCProfile (${normalizedIccPath}) def
|
|
537
|
+
|
|
538
|
+
% Maximum TAC = ${maxTacNorm} (${params.maxTac ?? 240}%)
|
|
539
|
+
/MaxTAC ${maxTacNorm} def
|
|
540
|
+
|
|
541
|
+
% UCR (Undercolor Removal) - aggressive GCR to reduce CMY in dark areas
|
|
542
|
+
% Takes K value, returns amount to subtract from CMY
|
|
543
|
+
/UCR {
|
|
544
|
+
% For dark colors, remove more CMY
|
|
545
|
+
dup 0.2 gt {
|
|
546
|
+
0.2 sub 1.5 mul % Remove 150% of K above 0.2 from CMY
|
|
547
|
+
1 min 0 max
|
|
548
|
+
} {
|
|
549
|
+
pop 0
|
|
550
|
+
} ifelse
|
|
551
|
+
} bind def
|
|
552
|
+
|
|
553
|
+
% BG (Black Generation) - standard K generation
|
|
554
|
+
/BG {
|
|
555
|
+
% Pass through K value
|
|
556
|
+
} bind def
|
|
557
|
+
|
|
558
|
+
% Set UCR and BG functions for color conversion
|
|
559
|
+
<< /UCRFunction { UCR } /BGFunction { BG } >> setpagedevice
|
|
560
|
+
|
|
561
|
+
[/Title (${params.title})
|
|
562
|
+
/Creator (gutterpress)
|
|
563
|
+
/GTS_PDFXVersion (${pdfxVersion})
|
|
564
|
+
/Trapped /False
|
|
565
|
+
${docInfoConformance}/DOCINFO pdfmark
|
|
566
|
+
|
|
567
|
+
[/_objdef {icc_PDFX} /type /stream /OBJ pdfmark
|
|
568
|
+
[{icc_PDFX} << /N ${iccComponents} >> /PUT pdfmark
|
|
569
|
+
[{icc_PDFX} ICCProfile (r) file /PUT pdfmark
|
|
570
|
+
|
|
571
|
+
[/_objdef {OutputIntent_PDFX} /type /dict /OBJ pdfmark
|
|
572
|
+
|
|
573
|
+
[{OutputIntent_PDFX} <<
|
|
574
|
+
/Type /OutputIntent
|
|
575
|
+
/S /GTS_PDFX
|
|
576
|
+
/OutputConditionIdentifier (${outputConditionId})
|
|
577
|
+
/OutputCondition (${outputCondition})
|
|
578
|
+
/Info (${outputCondition})
|
|
579
|
+
/RegistryName (http://www.color.org)
|
|
580
|
+
/DestOutputProfile {icc_PDFX}
|
|
581
|
+
>> /PUT pdfmark
|
|
582
|
+
|
|
583
|
+
[{Catalog} << /OutputIntents [ {OutputIntent_PDFX} ] >> /PUT pdfmark
|
|
584
|
+
`;
|
|
585
|
+
}
|
|
586
|
+
async function stampCreator(pdfPath) {
|
|
587
|
+
const { PDFDocument } = await import("pdf-lib");
|
|
588
|
+
const bytes = await readFile2(pdfPath);
|
|
589
|
+
const doc = await PDFDocument.load(bytes, { updateMetadata: false });
|
|
590
|
+
doc.setCreator("gutterpress");
|
|
591
|
+
const out = await doc.save();
|
|
592
|
+
await writeFile2(pdfPath, out);
|
|
593
|
+
}
|
|
594
|
+
async function convertToPdfxCmyk(inputPdf, outPdf, config) {
|
|
595
|
+
const iccPath = resolve(config.iccPath);
|
|
596
|
+
const tmpDef = join2(config.stagingDir, "pdfx-def.ps");
|
|
597
|
+
const args = [
|
|
598
|
+
"-dSAFER",
|
|
599
|
+
`--permit-file-read=${iccPath}`,
|
|
600
|
+
"-dBATCH",
|
|
601
|
+
"-dNOPAUSE",
|
|
602
|
+
"-sDEVICE=pdfwrite",
|
|
603
|
+
"-dPDFX",
|
|
604
|
+
"-dCompatibilityLevel=1.3",
|
|
605
|
+
"-dEmbedAllFonts=true",
|
|
606
|
+
"-dSubsetFonts=true",
|
|
607
|
+
"-dCompressFonts=true",
|
|
608
|
+
"-dDetectDuplicateImages=true",
|
|
609
|
+
"-dDownsampleColorImages=false",
|
|
610
|
+
"-dDownsampleGrayImages=false",
|
|
611
|
+
"-dDownsampleMonoImages=false",
|
|
612
|
+
"-sProcessColorModel=DeviceCMYK",
|
|
613
|
+
"-sColorConversionStrategy=CMYK",
|
|
614
|
+
"-dOverrideICC=true",
|
|
615
|
+
`-sOutputICCProfile=${iccPath}`,
|
|
616
|
+
`-sOutputFile=${outPdf}`,
|
|
617
|
+
tmpDef,
|
|
618
|
+
inputPdf
|
|
619
|
+
];
|
|
620
|
+
try {
|
|
621
|
+
await writeFile2(tmpDef, makePdfxDefPs({
|
|
622
|
+
iccPath,
|
|
623
|
+
pdfx: config.pdfx,
|
|
624
|
+
title: config.title ?? basename(outPdf),
|
|
625
|
+
maxTac: config.maxTac
|
|
626
|
+
}), "utf8");
|
|
627
|
+
const ghostscript = await resolveGhostscript();
|
|
628
|
+
if (!ghostscript) {
|
|
629
|
+
throw new Error("Ghostscript executable not found. Install Ghostscript or set GHOSTSCRIPT_PATH to its command-line executable.");
|
|
630
|
+
}
|
|
631
|
+
await run(ghostscript, args);
|
|
632
|
+
} finally {
|
|
633
|
+
await unlink(tmpDef).catch(() => {});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// src/lib/version.ts
|
|
638
|
+
var PACKAGE_META = {
|
|
639
|
+
version: package_default.version ?? "unknown",
|
|
640
|
+
dependencies: package_default.dependencies ?? {},
|
|
641
|
+
devDependencies: package_default.devDependencies ?? {}
|
|
642
|
+
};
|
|
643
|
+
var PACKAGE_VERSION = PACKAGE_META.version;
|
|
644
|
+
|
|
645
|
+
// src/lib/diagnostics.ts
|
|
646
|
+
var INSTALL_HINTS2 = {
|
|
647
|
+
chromium: `${fullInstallHint("chromium")}
|
|
648
|
+
Or set CHROMIUM_PATH=/path/to/chrome`,
|
|
649
|
+
gs: `${fullInstallHint("gs")}
|
|
650
|
+
Or set GHOSTSCRIPT_PATH=/path/to/ghostscript`,
|
|
651
|
+
qpdf: fullInstallHint("qpdf")
|
|
652
|
+
};
|
|
653
|
+
var TOOLS_TO_PROBE = [
|
|
654
|
+
{
|
|
655
|
+
id: "gs",
|
|
656
|
+
bin: "gs",
|
|
657
|
+
name: "Ghostscript",
|
|
658
|
+
hintKey: "gs",
|
|
659
|
+
usedBy: [
|
|
660
|
+
{ feature: "PDF/X CMYK conversion (build --format pdfx)", severity: "required" },
|
|
661
|
+
{ feature: "validate: pdf.print.ink-coverage, asset.image-tac", severity: "optional" }
|
|
662
|
+
]
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
id: "qpdf",
|
|
666
|
+
bin: "qpdf",
|
|
667
|
+
name: "qpdf",
|
|
668
|
+
hintKey: "qpdf",
|
|
669
|
+
usedBy: [
|
|
670
|
+
{ feature: "PDF/X annotation stripping (build --format pdfx)", severity: "required" },
|
|
671
|
+
{ feature: "validate: PDF/X OutputIntent + metadata checks", severity: "optional" }
|
|
672
|
+
]
|
|
673
|
+
}
|
|
674
|
+
];
|
|
675
|
+
var GET_VERSION_TIMEOUT_MS = 2000;
|
|
676
|
+
async function getVersion(bin, args = ["--version"]) {
|
|
677
|
+
try {
|
|
678
|
+
const { stdout, stderr } = await execCapture(bin, args, { timeoutMs: GET_VERSION_TIMEOUT_MS });
|
|
679
|
+
const combined = (stdout || stderr).trim();
|
|
680
|
+
return combined.split(/\r?\n/)[0]?.trim() || undefined;
|
|
681
|
+
} catch {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
async function getSystemDiagnostics() {
|
|
686
|
+
const libVersion = PACKAGE_VERSION;
|
|
687
|
+
const chromiumPath = await resolveChromiumExecutable();
|
|
688
|
+
const chromiumVersion = undefined;
|
|
689
|
+
const chromium = {
|
|
690
|
+
id: "chromium",
|
|
691
|
+
name: "Chromium-based browser",
|
|
692
|
+
bin: "chrome / chromium / msedge",
|
|
693
|
+
found: !!chromiumPath,
|
|
694
|
+
path: chromiumPath,
|
|
695
|
+
version: chromiumVersion,
|
|
696
|
+
usedBy: [
|
|
697
|
+
{ feature: "Save PDF (every PDF render)", severity: "required" }
|
|
698
|
+
],
|
|
699
|
+
installHint: INSTALL_HINTS2.chromium
|
|
700
|
+
};
|
|
701
|
+
const ghostscriptPath = await resolveGhostscript();
|
|
702
|
+
const tools = await Promise.all(TOOLS_TO_PROBE.map(async (t) => {
|
|
703
|
+
if (t.id === "gs") {
|
|
704
|
+
return {
|
|
705
|
+
id: t.id,
|
|
706
|
+
name: t.name,
|
|
707
|
+
bin: t.bin,
|
|
708
|
+
found: !!ghostscriptPath,
|
|
709
|
+
path: ghostscriptPath,
|
|
710
|
+
version: ghostscriptPath ? await getVersion(ghostscriptPath) : undefined,
|
|
711
|
+
usedBy: t.usedBy,
|
|
712
|
+
installHint: INSTALL_HINTS2[t.hintKey]
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
const [path2, available] = await Promise.all([
|
|
716
|
+
findTool(t.bin),
|
|
717
|
+
isToolAvailable(t.bin)
|
|
718
|
+
]);
|
|
719
|
+
const found = available || !!path2;
|
|
720
|
+
const version = found ? await getVersion(t.bin) : undefined;
|
|
721
|
+
return {
|
|
722
|
+
id: t.id,
|
|
723
|
+
name: t.name,
|
|
724
|
+
bin: t.bin,
|
|
725
|
+
found,
|
|
726
|
+
path: path2,
|
|
727
|
+
version,
|
|
728
|
+
usedBy: t.usedBy,
|
|
729
|
+
installHint: INSTALL_HINTS2[t.hintKey]
|
|
730
|
+
};
|
|
731
|
+
}));
|
|
732
|
+
return {
|
|
733
|
+
libVersion,
|
|
734
|
+
platform: {
|
|
735
|
+
os: platform2(),
|
|
736
|
+
arch: arch(),
|
|
737
|
+
release: release(),
|
|
738
|
+
node: process.versions.node
|
|
739
|
+
},
|
|
740
|
+
tools: [chromium, ...tools],
|
|
741
|
+
configDir: defaultConfigDir(),
|
|
742
|
+
docsUrl: "https://github.com/dimm-city/gutterpress/blob/main/examples/gutterpress-user-guide/08-system-setup.md"
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
export { setLogLevel, debug, info, warn, error, log, spawnCapture, execCapture, isToolAvailable, INSTALL_HINTS, resolveChromiumExecutable, requireChromiumExecutable, resolveGhostscript, stripAnnotations, stampCreator, convertToPdfxCmyk, PACKAGE_META, PACKAGE_VERSION, credentialHostKey, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics };
|