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,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform abstraction contract (GitHub #41).
|
|
3
|
+
*
|
|
4
|
+
* The desktop talks to its host through ONE seam so that the app code never
|
|
5
|
+
* branches on `electron` vs `web` directly. Today the only host is Electron
|
|
6
|
+
* (IPC + native dialogs). When the PWA lands (0.6.0, #...), a `WebAdapter`
|
|
7
|
+
* backed by the File System Access API drops in behind the same interface and
|
|
8
|
+
* the app code does not change.
|
|
9
|
+
*
|
|
10
|
+
* This module is **types only** — it is imported by the browser SPA via
|
|
11
|
+
* `import type`, so it must never pull in a Node runtime dependency.
|
|
12
|
+
*
|
|
13
|
+
* Canonical home: `gutterpress`. The desktop re-exports these types
|
|
14
|
+
* from `src/lib/platform/` and implements them in `electron-adapter.ts` /
|
|
15
|
+
* `web-adapter.ts`. Keep the implementations in lockstep with this contract.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The narrow set of capabilities whose implementation genuinely differs between
|
|
19
|
+
* a desktop (Electron) host and a browser (PWA) host: native dialogs, raw file
|
|
20
|
+
* IO, filesystem watching, and OS-keychain-backed secrets.
|
|
21
|
+
*
|
|
22
|
+
* Host RPC services that are *also* host-divergent (preview/build/doctor/prefs/
|
|
23
|
+
* updater) are modelled separately as {@link HostServices} so this primitive
|
|
24
|
+
* surface stays small and easy to reason about. The full thing the app consumes
|
|
25
|
+
* is {@link Platform} = `PlatformAdapter & HostServices`.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Filesystem metadata for a single path (GitHub #44 — external-edit detection).
|
|
29
|
+
* `mtimeMs` is the modification time in epoch milliseconds; `exists` is `false`
|
|
30
|
+
* (with `mtimeMs`/`size` = 0) when the path is absent rather than throwing, so
|
|
31
|
+
* the editor can distinguish "deleted out from under us" from a read error.
|
|
32
|
+
*/
|
|
33
|
+
export interface FileStat {
|
|
34
|
+
mtimeMs: number;
|
|
35
|
+
size: number;
|
|
36
|
+
exists: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Result of a successful {@link PlatformAdapter.writeFile} (GitHub #44). Carries
|
|
40
|
+
* the post-write modification time so the editor can record the on-disk baseline
|
|
41
|
+
* mtime without a follow-up `statFile` round-trip — this is what lets
|
|
42
|
+
* external-edit detection suppress the self-echo of our own debounced save.
|
|
43
|
+
*/
|
|
44
|
+
export interface FileWriteResult {
|
|
45
|
+
mtimeMs: number;
|
|
46
|
+
}
|
|
47
|
+
export interface PlatformAdapter {
|
|
48
|
+
/** Which host backs this adapter. Lets the rare unavoidable branch be explicit. */
|
|
49
|
+
readonly platform: "electron" | "web";
|
|
50
|
+
/**
|
|
51
|
+
* Prompt the user to choose a project folder.
|
|
52
|
+
* @returns the absolute path, or `null` if the user cancelled.
|
|
53
|
+
* Electron: native directory dialog. Web: File System Access API.
|
|
54
|
+
*/
|
|
55
|
+
openFolder(): Promise<string | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Read a UTF-8 text file by absolute path.
|
|
58
|
+
* Editor seam for #38/#39 — no current consumer in 0.4.0.
|
|
59
|
+
*/
|
|
60
|
+
readFile(path: string): Promise<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Write a UTF-8 text file by absolute path, creating/overwriting it.
|
|
63
|
+
* Resolves with the post-write {@link FileWriteResult} (`{ mtimeMs }`) so the
|
|
64
|
+
* editor (#44) can record the on-disk baseline mtime; callers that ignore the
|
|
65
|
+
* value are unaffected (additive widening — was `Promise<void>`).
|
|
66
|
+
*/
|
|
67
|
+
writeFile(path: string, content: string): Promise<FileWriteResult>;
|
|
68
|
+
/**
|
|
69
|
+
* List the immediate entries of a directory (single level, no recursion).
|
|
70
|
+
* @returns each entry's `name`, absolute `path`, and whether it `isDir`.
|
|
71
|
+
* Editor seam for #38 (file-tree sidebar). Electron: `node:fs/promises`
|
|
72
|
+
* `readdir`. Web: File System Access API (0.6.0).
|
|
73
|
+
*/
|
|
74
|
+
listDir(path: string): Promise<Array<{
|
|
75
|
+
name: string;
|
|
76
|
+
path: string;
|
|
77
|
+
isDir: boolean;
|
|
78
|
+
}>>;
|
|
79
|
+
/**
|
|
80
|
+
* Stat a file by absolute path (GitHub #44). Used by the editor to confirm a
|
|
81
|
+
* `watchFolder` event reflects a real on-disk change (mtime moved) versus the
|
|
82
|
+
* self-echo of our own `writeFile`. Resolves with `exists: false` rather than
|
|
83
|
+
* rejecting when the path is absent. Web throws until 0.6.0 (FS Access API).
|
|
84
|
+
*/
|
|
85
|
+
statFile(path: string): Promise<FileStat>;
|
|
86
|
+
/**
|
|
87
|
+
* Watch a folder for changes, invoking `cb` on each change.
|
|
88
|
+
* @returns an unsubscribe function.
|
|
89
|
+
* Web has no general recursive-watch primitive — `WebAdapter` throws here
|
|
90
|
+
* until 0.6.0. Electron wiring lands with the in-app editor (#38).
|
|
91
|
+
*/
|
|
92
|
+
watchFolder(path: string, cb: () => void): () => void;
|
|
93
|
+
/**
|
|
94
|
+
* Read a secret by key (e.g. a GitHub token). Lands with #12.
|
|
95
|
+
* Electron: OS keychain via `safeStorage`. Web: encrypted localStorage.
|
|
96
|
+
*/
|
|
97
|
+
getSecret(key: string): Promise<string | null>;
|
|
98
|
+
/** Store a secret by key. Lands with #12. */
|
|
99
|
+
setSecret(key: string, value: string): Promise<void>;
|
|
100
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addNpmPlugin,
|
|
3
|
+
parseNpmPluginSpec
|
|
4
|
+
} from "./cli-7ykx7pp0.js";
|
|
5
|
+
import"./cli-h7phg3ka.js";
|
|
6
|
+
import {
|
|
7
|
+
EXIT_CODES,
|
|
8
|
+
UsageError,
|
|
9
|
+
rejectExtraPositionals,
|
|
10
|
+
rejectUnknownFlags
|
|
11
|
+
} from "./cli-hvqjs342.js";
|
|
12
|
+
import"./cli-5bxx0c4y.js";
|
|
13
|
+
import"./cli-1tyj4bk3.js";
|
|
14
|
+
import"./cli-yja077f6.js";
|
|
15
|
+
import"./cli-37x76zdn.js";
|
|
16
|
+
|
|
17
|
+
// src/commands/plugin.ts
|
|
18
|
+
import { defineCommand } from "citty";
|
|
19
|
+
import { stat } from "node:fs/promises";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
var pluginAddArgs = {
|
|
22
|
+
package: {
|
|
23
|
+
type: "positional",
|
|
24
|
+
description: "npm package name, optionally followed by @version or @dist-tag",
|
|
25
|
+
required: true
|
|
26
|
+
},
|
|
27
|
+
dir: {
|
|
28
|
+
type: "positional",
|
|
29
|
+
description: "Project directory (defaults to the current directory)",
|
|
30
|
+
required: false
|
|
31
|
+
},
|
|
32
|
+
export: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Named module export to use as the plugin function",
|
|
35
|
+
required: false
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var parentArgs = {};
|
|
39
|
+
function exitForUsage(error) {
|
|
40
|
+
if (error instanceof UsageError) {
|
|
41
|
+
console.error(error.message);
|
|
42
|
+
process.exit(error.exitCode);
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
function rejectParentFlags(rawArgs) {
|
|
47
|
+
if (rawArgs[0] === "add" || rawArgs[0] === undefined || !rawArgs[0].startsWith("-")) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
rejectUnknownFlags(rawArgs, parentArgs, "plugin");
|
|
52
|
+
} catch (error) {
|
|
53
|
+
exitForUsage(error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
var add = defineCommand({
|
|
57
|
+
meta: {
|
|
58
|
+
name: "add",
|
|
59
|
+
description: "Download, verify, and vendor an npm markdown-it plugin"
|
|
60
|
+
},
|
|
61
|
+
args: pluginAddArgs,
|
|
62
|
+
async run({ args, rawArgs }) {
|
|
63
|
+
try {
|
|
64
|
+
rejectUnknownFlags(rawArgs, pluginAddArgs, "plugin add");
|
|
65
|
+
rejectExtraPositionals(args._, 2, "plugin add");
|
|
66
|
+
} catch (error) {
|
|
67
|
+
exitForUsage(error);
|
|
68
|
+
}
|
|
69
|
+
const projectDir = path.resolve(typeof args.dir === "string" && args.dir ? args.dir : process.cwd());
|
|
70
|
+
const packageSpec = String(args.package);
|
|
71
|
+
const exportName = typeof args.export === "string" ? args.export.trim() : undefined;
|
|
72
|
+
try {
|
|
73
|
+
try {
|
|
74
|
+
parseNpmPluginSpec(packageSpec);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new UsageError(error instanceof Error ? error.message : String(error));
|
|
77
|
+
}
|
|
78
|
+
if (typeof args.export === "string" && !exportName) {
|
|
79
|
+
throw new UsageError("gutterpress plugin add: --export requires a non-empty name");
|
|
80
|
+
}
|
|
81
|
+
let projectInfo;
|
|
82
|
+
try {
|
|
83
|
+
projectInfo = await stat(projectDir);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error.code === "ENOENT") {
|
|
86
|
+
throw new UsageError(`Project directory does not exist: ${projectDir}`);
|
|
87
|
+
}
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
if (!projectInfo.isDirectory()) {
|
|
91
|
+
throw new UsageError(`Project path is not a directory: ${projectDir}`);
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
exitForUsage(error);
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const installed = await addNpmPlugin(projectDir, packageSpec, exportName);
|
|
98
|
+
if (installed.version) {
|
|
99
|
+
console.log(`Installed ${installed.ref}@${installed.version}`);
|
|
100
|
+
console.log(` project: ${projectDir}`);
|
|
101
|
+
console.log(" vendored under: plugins/npm");
|
|
102
|
+
console.log(" manifest: exact version pinned");
|
|
103
|
+
for (const warning of installed.warnings ?? [])
|
|
104
|
+
console.warn(`Warning: ${warning}`);
|
|
105
|
+
} else {
|
|
106
|
+
console.log(`Enabled bundled plugin ${installed.ref}`);
|
|
107
|
+
console.log(` project: ${projectDir}`);
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(`Could not install plugin: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
+
process.exit(EXIT_CODES.PIPELINE);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
var plugin_default = defineCommand({
|
|
116
|
+
meta: {
|
|
117
|
+
name: "plugin",
|
|
118
|
+
description: "Manage project markdown-it plugins"
|
|
119
|
+
},
|
|
120
|
+
args: parentArgs,
|
|
121
|
+
setup({ rawArgs }) {
|
|
122
|
+
rejectParentFlags(rawArgs);
|
|
123
|
+
},
|
|
124
|
+
subCommands: { add }
|
|
125
|
+
});
|
|
126
|
+
export {
|
|
127
|
+
pluginAddArgs,
|
|
128
|
+
plugin_default as default
|
|
129
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
executeValidation,
|
|
3
|
+
reportMissingTools
|
|
4
|
+
} from "./cli-7ykx7pp0.js";
|
|
5
|
+
import {
|
|
6
|
+
log
|
|
7
|
+
} from "./cli-h7phg3ka.js";
|
|
8
|
+
import {
|
|
9
|
+
EXIT_CODES,
|
|
10
|
+
UsageError,
|
|
11
|
+
rejectExtraPositionals,
|
|
12
|
+
rejectUnknownFlags
|
|
13
|
+
} from "./cli-hvqjs342.js";
|
|
14
|
+
import"./cli-5bxx0c4y.js";
|
|
15
|
+
import"./cli-1tyj4bk3.js";
|
|
16
|
+
import"./cli-yja077f6.js";
|
|
17
|
+
import"./cli-37x76zdn.js";
|
|
18
|
+
|
|
19
|
+
// src/commands/preflight.ts
|
|
20
|
+
import { defineCommand } from "citty";
|
|
21
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
22
|
+
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
23
|
+
function computeStatus(errors, warnings, missingTools, skippedRequired) {
|
|
24
|
+
if (errors > 0 || skippedRequired)
|
|
25
|
+
return "NO-GO";
|
|
26
|
+
if (warnings > 0 || missingTools > 0)
|
|
27
|
+
return "FIX";
|
|
28
|
+
return "GO";
|
|
29
|
+
}
|
|
30
|
+
function severityRank(severity) {
|
|
31
|
+
if (severity === "error")
|
|
32
|
+
return 0;
|
|
33
|
+
if (severity === "warning")
|
|
34
|
+
return 1;
|
|
35
|
+
return 2;
|
|
36
|
+
}
|
|
37
|
+
function buildRequiredChecks(execution) {
|
|
38
|
+
if (execution.profile !== "dtrpg")
|
|
39
|
+
return [];
|
|
40
|
+
const requiredIds = [
|
|
41
|
+
"pdf.structure.qpdf",
|
|
42
|
+
"pdf.print.pdfx-markers",
|
|
43
|
+
"pdf.print.pdfx-metadata",
|
|
44
|
+
"pdf.print.embedded-fonts"
|
|
45
|
+
];
|
|
46
|
+
const skipped = new Set(execution.tools.skippedChecks);
|
|
47
|
+
const failed = new Set(execution.report.errors.map((item) => item.checkId));
|
|
48
|
+
const passed = new Set(execution.report.passed);
|
|
49
|
+
return requiredIds.map((id) => {
|
|
50
|
+
if (skipped.has(id))
|
|
51
|
+
return { id, status: "skipped" };
|
|
52
|
+
if (failed.has(id))
|
|
53
|
+
return { id, status: "fail" };
|
|
54
|
+
if (passed.has(id))
|
|
55
|
+
return { id, status: "pass" };
|
|
56
|
+
return { id, status: "fail" };
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function buildPreflightPayload(execution) {
|
|
60
|
+
const sortedIssues = [...execution.report.results].sort((a, b) => {
|
|
61
|
+
const severityCmp = severityRank(a.severity) - severityRank(b.severity);
|
|
62
|
+
if (severityCmp !== 0)
|
|
63
|
+
return severityCmp;
|
|
64
|
+
const checkCmp = a.checkId.localeCompare(b.checkId);
|
|
65
|
+
if (checkCmp !== 0)
|
|
66
|
+
return checkCmp;
|
|
67
|
+
const fileCmp = (a.file ?? "").localeCompare(b.file ?? "");
|
|
68
|
+
if (fileCmp !== 0)
|
|
69
|
+
return fileCmp;
|
|
70
|
+
const lineCmp = (a.line ?? 0) - (b.line ?? 0);
|
|
71
|
+
if (lineCmp !== 0)
|
|
72
|
+
return lineCmp;
|
|
73
|
+
const colCmp = (a.column ?? 0) - (b.column ?? 0);
|
|
74
|
+
if (colCmp !== 0)
|
|
75
|
+
return colCmp;
|
|
76
|
+
return a.message.localeCompare(b.message);
|
|
77
|
+
}).map((item) => ({
|
|
78
|
+
checkId: item.checkId,
|
|
79
|
+
severity: item.severity,
|
|
80
|
+
message: item.message,
|
|
81
|
+
file: item.file,
|
|
82
|
+
line: item.line,
|
|
83
|
+
column: item.column
|
|
84
|
+
}));
|
|
85
|
+
const requiredChecks = buildRequiredChecks(execution);
|
|
86
|
+
const skippedRequired = requiredChecks.some((check) => check.status === "skipped");
|
|
87
|
+
return {
|
|
88
|
+
schemaVersion: 1,
|
|
89
|
+
profile: execution.profile ?? null,
|
|
90
|
+
status: computeStatus(execution.report.summary.errors, execution.report.summary.warnings, execution.tools.missing.length, skippedRequired),
|
|
91
|
+
pdf: execution.context.pdfPath ?? "",
|
|
92
|
+
summary: { ...execution.report.summary },
|
|
93
|
+
tools: {
|
|
94
|
+
missing: [...execution.tools.missing].sort((a, b) => a.localeCompare(b)),
|
|
95
|
+
skippedChecks: [...execution.tools.skippedChecks].sort((a, b) => a.localeCompare(b))
|
|
96
|
+
},
|
|
97
|
+
requiredChecks,
|
|
98
|
+
issues: sortedIssues
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function toPreflightMarkdown(payload) {
|
|
102
|
+
const lines = [];
|
|
103
|
+
lines.push("# gutterpress preflight");
|
|
104
|
+
lines.push("");
|
|
105
|
+
lines.push(`- Status: **${payload.status}**`);
|
|
106
|
+
lines.push(`- Profile: ${payload.profile ?? "none"}`);
|
|
107
|
+
lines.push(`- PDF: ${payload.pdf}`);
|
|
108
|
+
lines.push(`- Summary: ${payload.summary.errors} error(s), ${payload.summary.warnings} warning(s), ${payload.summary.passed}/${payload.summary.total} checks passed`);
|
|
109
|
+
if (payload.tools.missing.length > 0) {
|
|
110
|
+
lines.push("");
|
|
111
|
+
lines.push("## Missing Tools");
|
|
112
|
+
for (const tool of payload.tools.missing) {
|
|
113
|
+
lines.push(`- ${tool}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (payload.requiredChecks.length > 0) {
|
|
117
|
+
lines.push("");
|
|
118
|
+
lines.push("## Required Checks");
|
|
119
|
+
for (const check of payload.requiredChecks) {
|
|
120
|
+
lines.push(`- ${check.id}: ${check.status}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (payload.issues.length > 0) {
|
|
124
|
+
lines.push("");
|
|
125
|
+
lines.push("## Issues");
|
|
126
|
+
for (const issue of payload.issues) {
|
|
127
|
+
lines.push(`- [${issue.severity}] ${issue.checkId}: ${issue.message}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return `${lines.join(`
|
|
131
|
+
`)}
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
function defaultReportName(pdfPath) {
|
|
135
|
+
const ext = extname(pdfPath);
|
|
136
|
+
const base = ext ? basename(pdfPath, ext) : basename(pdfPath);
|
|
137
|
+
return `${base}.preflight`;
|
|
138
|
+
}
|
|
139
|
+
var preflightArgs = {
|
|
140
|
+
dir: {
|
|
141
|
+
type: "positional",
|
|
142
|
+
description: "Project directory (default: cwd). Sets the pre-build source directory unless --input is also given.",
|
|
143
|
+
required: false
|
|
144
|
+
},
|
|
145
|
+
pdf: {
|
|
146
|
+
type: "string",
|
|
147
|
+
description: "Path to the PDF file to preflight",
|
|
148
|
+
required: true
|
|
149
|
+
},
|
|
150
|
+
input: {
|
|
151
|
+
type: "string",
|
|
152
|
+
description: "Optional source directory for pre-build checks (overrides the positional directory)"
|
|
153
|
+
},
|
|
154
|
+
manifest: {
|
|
155
|
+
type: "string",
|
|
156
|
+
description: "Path to manifest.yaml"
|
|
157
|
+
},
|
|
158
|
+
profile: {
|
|
159
|
+
type: "string",
|
|
160
|
+
description: "Validation profile lock (currently: dtrpg)"
|
|
161
|
+
},
|
|
162
|
+
"report-dir": {
|
|
163
|
+
type: "string",
|
|
164
|
+
description: "Output directory for preflight reports"
|
|
165
|
+
},
|
|
166
|
+
name: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Base filename for report outputs"
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
var preflight_default = defineCommand({
|
|
172
|
+
meta: {
|
|
173
|
+
name: "preflight",
|
|
174
|
+
description: "Run deterministic print preflight for a built PDF"
|
|
175
|
+
},
|
|
176
|
+
args: preflightArgs,
|
|
177
|
+
async run({ args, rawArgs }) {
|
|
178
|
+
const positionalDir = typeof args.dir === "string" ? args.dir : undefined;
|
|
179
|
+
const inputFlag = typeof args.input === "string" ? args.input : undefined;
|
|
180
|
+
const input = inputFlag ?? positionalDir;
|
|
181
|
+
let execution;
|
|
182
|
+
try {
|
|
183
|
+
rejectUnknownFlags(rawArgs, preflightArgs, "preflight");
|
|
184
|
+
rejectExtraPositionals(args._, 1, "preflight");
|
|
185
|
+
execution = await executeValidation({
|
|
186
|
+
manifest: typeof args.manifest === "string" ? args.manifest : undefined,
|
|
187
|
+
pdf: typeof args.pdf === "string" ? args.pdf : undefined,
|
|
188
|
+
input,
|
|
189
|
+
phase: "post-build",
|
|
190
|
+
profile: typeof args.profile === "string" ? args.profile : undefined
|
|
191
|
+
});
|
|
192
|
+
} catch (error) {
|
|
193
|
+
log.error(error instanceof Error ? error.message : String(error));
|
|
194
|
+
process.exit(error instanceof UsageError ? error.exitCode : EXIT_CODES.USAGE);
|
|
195
|
+
}
|
|
196
|
+
if (!execution)
|
|
197
|
+
return;
|
|
198
|
+
reportMissingTools(execution.tools);
|
|
199
|
+
const payload = buildPreflightPayload(execution);
|
|
200
|
+
const pdfPath = execution.context.pdfPath;
|
|
201
|
+
const reportDir = resolve(typeof args["report-dir"] === "string" ? args["report-dir"] : dirname(pdfPath));
|
|
202
|
+
const baseName = typeof args.name === "string" && args.name.trim().length > 0 ? args.name.trim() : defaultReportName(pdfPath);
|
|
203
|
+
const jsonPath = join(reportDir, `${baseName}.json`);
|
|
204
|
+
const markdownPath = join(reportDir, `${baseName}.md`);
|
|
205
|
+
await mkdir(reportDir, { recursive: true });
|
|
206
|
+
await writeFile(jsonPath, `${JSON.stringify(payload, null, 2)}
|
|
207
|
+
`, "utf8");
|
|
208
|
+
await writeFile(markdownPath, toPreflightMarkdown(payload), "utf8");
|
|
209
|
+
log.info(`Preflight status: ${payload.status}`);
|
|
210
|
+
log.info(`JSON report: ${jsonPath}`);
|
|
211
|
+
log.info(`Markdown report: ${markdownPath}`);
|
|
212
|
+
if (payload.status === "NO-GO") {
|
|
213
|
+
process.exit(EXIT_CODES.FINDINGS);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
export {
|
|
218
|
+
toPreflightMarkdown,
|
|
219
|
+
preflightArgs,
|
|
220
|
+
preflight_default as default,
|
|
221
|
+
buildPreflightPayload
|
|
222
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File watcher setup and management for preview server
|
|
3
|
+
*
|
|
4
|
+
* Handles watching input files and triggering rebuilds on changes.
|
|
5
|
+
* Uses the simplified markdown pipeline (renderChapters from lib/markdown).
|
|
6
|
+
*/
|
|
7
|
+
import { type FSWatcher } from 'chokidar';
|
|
8
|
+
import type { ServerState } from './server-context';
|
|
9
|
+
import type { ResolvedPluginConfig } from '../schema/manifest.types';
|
|
10
|
+
/**
|
|
11
|
+
* Whether the double-buffered preview shell is active. The historical env name
|
|
12
|
+
* is retained because users may already set it; chapter splicing is gone and
|
|
13
|
+
* every source change now performs a full-document pagination.
|
|
14
|
+
*/
|
|
15
|
+
export declare function incrementalPreviewEnabled(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Shared preview render path. renderChapters() does all Markdown, CSS, and
|
|
18
|
+
* Paged.js-slot work.
|
|
19
|
+
*
|
|
20
|
+
* Named `renderPreviewBook` (ARCH finding #53) to distinguish it from
|
|
21
|
+
* build-runner.ts's `renderBook` — same name, different module, and a
|
|
22
|
+
* genuinely different contract: this one is degrade-and-report (a plugin the
|
|
23
|
+
* author enabled but hasn't installed yet is skipped with a loud warning so
|
|
24
|
+
* the rest of the live preview still renders); build-runner.ts's is
|
|
25
|
+
* fail-fast, because a final artifact must never silently drop a plugin.
|
|
26
|
+
* Both preambles now share {@link loadPluginsWithCss}.
|
|
27
|
+
*/
|
|
28
|
+
export declare function renderPreviewBook(inputPath: string, config: {
|
|
29
|
+
title?: string;
|
|
30
|
+
styles?: string[];
|
|
31
|
+
plugins?: ResolvedPluginConfig[];
|
|
32
|
+
}, opts: {
|
|
33
|
+
files: string[] | null;
|
|
34
|
+
wrapChapters: boolean;
|
|
35
|
+
}): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Rewrite rendered book HTML for the live preview. Injects, in order:
|
|
38
|
+
* 1. pagedjs-interface.js — defines window.previewAPI for in-iframe controls
|
|
39
|
+
* 2. pagedjs-bridge.js — postMessage bridge for cross-origin toolbar (desktop)
|
|
40
|
+
* 3. BREAK_INSIDE_HANDLER — polyfill for break-inside: avoid
|
|
41
|
+
* 4. Paged.js polyfill itself, served directly from the process-wide
|
|
42
|
+
* embedded-assets dir by the HTTP server (see http-server.ts route
|
|
43
|
+
* for /vendor/*). We no longer copy it into the per-project tempDir
|
|
44
|
+
* because:
|
|
45
|
+
* - The polyfill is 904 KB and copying it per open is wasted IO
|
|
46
|
+
* (one of the worst-case Defender scan targets on Windows).
|
|
47
|
+
* - The per-process extracted copy is identical across opens so
|
|
48
|
+
* serving it from a stable disk path lets the OS file-cache
|
|
49
|
+
* and Defender hash-cache stay warm across sessions.
|
|
50
|
+
*
|
|
51
|
+
* PAGINATION FIDELITY: this injects NO page-break rule. It used to add
|
|
52
|
+
* `<style>.gutterpress-chapter{break-before:page}</style>` whenever the incremental
|
|
53
|
+
* preview was on (i.e. by default), which started EVERY source file on a new
|
|
54
|
+
* page in the live view. `gutterpress build` emits no such rule — assembleBookHtml
|
|
55
|
+
* in lib/markdown/assemble.ts concatenates source files flat into <body> and
|
|
56
|
+
* breaks only where project CSS or a markdown-it-paged marker says to — so any
|
|
57
|
+
* project that splits one chapter across several source files previewed with
|
|
58
|
+
* different page boundaries than the PDF it built. Preview and build now take
|
|
59
|
+
* their breaks from exactly the same rules.
|
|
60
|
+
*
|
|
61
|
+
* Chapter identity is attached to existing source-mapped blocks. No wrapper or
|
|
62
|
+
* preview-only CSS is emitted, so selectors see exactly the same document tree
|
|
63
|
+
* as the build.
|
|
64
|
+
*/
|
|
65
|
+
export declare function injectPreviewScripts(html: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Generate HTML from markdown and write book.html to the temp directory.
|
|
68
|
+
* The desktop's iframe loads `book.html` via a relative URL — same name in
|
|
69
|
+
* dev and in published static-site builds.
|
|
70
|
+
*
|
|
71
|
+
* Empty `inputPath` writes a static placeholder — the desktop app (packages/desktop)
|
|
72
|
+
* supplies a real path via its own folder picker.
|
|
73
|
+
*/
|
|
74
|
+
export declare function generateAndWriteHtml(inputPath: string, tempDir: string, config: {
|
|
75
|
+
title?: string;
|
|
76
|
+
styles?: string[];
|
|
77
|
+
source?: {
|
|
78
|
+
files?: string[] | null;
|
|
79
|
+
};
|
|
80
|
+
plugins?: ResolvedPluginConfig[];
|
|
81
|
+
}): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Chokidar 5's `ignored` matcher (regex or function) is tested against the
|
|
84
|
+
* fully-qualified, forward-slash-normalized ABSOLUTE path — never a path
|
|
85
|
+
* relative to whatever root was passed to `watch()` (see chokidar's internal
|
|
86
|
+
* `matchPatterns`/`normalizePath`, which run before any matcher, function or
|
|
87
|
+
* regex, ever sees the string). The previous `ignored: /(^|[\/\\])\../`
|
|
88
|
+
* therefore matched a dot segment ANYWHERE in that absolute path — including
|
|
89
|
+
* every ANCESTOR directory of the project, not just the project's own dot
|
|
90
|
+
* files/dirs. A project rooted under a dot-prefixed parent (e.g.
|
|
91
|
+
* `~/.local/share/gutterpress/books/mybook`, or any `~/.config/...` tree) had
|
|
92
|
+
* every single path rejected by this rule, which silently disabled the
|
|
93
|
+
* watcher entirely — no error, just a preview that never picked up an edit.
|
|
94
|
+
*
|
|
95
|
+
* The fix: strip the (normalized) watch root off the front of the path
|
|
96
|
+
* first, and apply the dotfile rule only to what's left — i.e. to the
|
|
97
|
+
* PROJECT's own files/dirs, regardless of which ancestor directories the
|
|
98
|
+
* project itself happens to live under.
|
|
99
|
+
*/
|
|
100
|
+
export declare function isDotPathUnderRoot(candidatePath: string, root: string): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Whether the watcher should ignore a path.
|
|
103
|
+
*
|
|
104
|
+
* IN-PROJECT paths get the dotfile rule ({@link isDotPathUnderRoot}) — a
|
|
105
|
+
* project's own `.git/`, `.DS_Store`, editor swap files, and so on are noise.
|
|
106
|
+
*
|
|
107
|
+
* A path OUTSIDE the project is only ever seen because it is a DECLARED
|
|
108
|
+
* external dependency the manifest named explicitly (see
|
|
109
|
+
* {@link externalWatchTargets}); it is never ignored. Running the dotfile rule
|
|
110
|
+
* on it would test every ANCESTOR segment of its absolute path — so a shared
|
|
111
|
+
* foundation checked out under, say, `~/.local/share/books/shared/` would be
|
|
112
|
+
* silently dropped, which is the exact failure mode the in-project rule was
|
|
113
|
+
* rewritten to avoid.
|
|
114
|
+
*/
|
|
115
|
+
export declare function isIgnoredWatchPath(candidatePath: string, projectRoot: string): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* External watcher roots may be broader than one dependency when a declared
|
|
118
|
+
* file or its parent directory does not exist yet. Traverse only paths that are
|
|
119
|
+
* either a desired file or one of its ancestors; this keeps a nearest-existing
|
|
120
|
+
* ancestor watch from scanning unrelated sibling trees such as `.git/`.
|
|
121
|
+
*/
|
|
122
|
+
export declare function isExternalWatchCandidate(candidatePath: string, targets: Iterable<string>): boolean;
|
|
123
|
+
/** Directories chokidar must subscribe to for exact external file targets. */
|
|
124
|
+
export declare function externalWatchRoots(targets: Iterable<string>): Promise<string[]>;
|
|
125
|
+
/**
|
|
126
|
+
* Everything the book reads from OUTSIDE its own folder — absolute paths,
|
|
127
|
+
* deduped. The project watch root covers in-book files; this is what it can't
|
|
128
|
+
* see.
|
|
129
|
+
*
|
|
130
|
+
* A multi-book repository keeps its shared foundation next to the books
|
|
131
|
+
* (`shared/styles/publisher-components.css`, `shared/plugins/components.js`)
|
|
132
|
+
* and each book's manifest points at it directly: a `styles:` entry is a path
|
|
133
|
+
* to READ (asset-inline.ts inlines it; nothing is staged or copied) and an
|
|
134
|
+
* authored plugin `path:` resolves against the manifest directory. Both may sit
|
|
135
|
+
* above the book root.
|
|
136
|
+
*
|
|
137
|
+
* The stylesheet side is the DEPENDENCY CLOSURE, not just the declared entry —
|
|
138
|
+
* `collectStyleDependencies` follows each active stylesheet's `@import` chain
|
|
139
|
+
* and every local `url()` it references. A shared theme's
|
|
140
|
+
* `url("../../fonts/Publisher.woff2")` is a file a design tool can replace
|
|
141
|
+
* without touching one line of CSS; watching only `theme.css` would leave the
|
|
142
|
+
* preview stale after that swap with nothing downstream to correct it. The
|
|
143
|
+
* closure is computed from ALL active stylesheets, including in-book ones,
|
|
144
|
+
* because a local stylesheet can reference a shared font just as easily — only
|
|
145
|
+
* the results that land outside the book are added here.
|
|
146
|
+
*
|
|
147
|
+
* Watching is per-FILE, never per-directory, so the set stays exact and cannot
|
|
148
|
+
* accidentally pull a large sibling tree into the watcher.
|
|
149
|
+
*/
|
|
150
|
+
export declare function externalWatchTargets(projectDir: string, config: {
|
|
151
|
+
styles?: string[];
|
|
152
|
+
plugins?: ResolvedPluginConfig[];
|
|
153
|
+
}): Promise<string[]>;
|
|
154
|
+
/**
|
|
155
|
+
* Create and configure a file watcher for the project's input directory plus
|
|
156
|
+
* the book's declared external dependencies (see {@link externalWatchTargets}).
|
|
157
|
+
*
|
|
158
|
+
* Nothing is mirrored anywhere: the old external-asset-root watching (a sibling
|
|
159
|
+
* `../_shared` directory copied under its own name into the temp dir) went away
|
|
160
|
+
* with `copyAssets` and the manifest's `source.assets` field it depended on.
|
|
161
|
+
* The project is served straight from disk and stylesheets are inlined at
|
|
162
|
+
* render time, so an external dependency needs watching, not staging.
|
|
163
|
+
*/
|
|
164
|
+
export declare function createFileWatcher(state: ServerState): FSWatcher;
|
|
165
|
+
/**
|
|
166
|
+
* Start file watching if not disabled via options. No-input mode skips the
|
|
167
|
+
* watcher entirely (nothing to watch yet) — restartPreview wires up a
|
|
168
|
+
* watcher once the user picks a directory through the desktop.
|
|
169
|
+
*/
|
|
170
|
+
export declare function startFileWatcher(state: ServerState): void;
|
|
171
|
+
/**
|
|
172
|
+
* Stop the file watcher and clean up resources
|
|
173
|
+
*/
|
|
174
|
+
export declare function stopFileWatcher(state: ServerState): Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js-compatible preview HTTP server with WebSocket-based live reload.
|
|
3
|
+
*
|
|
4
|
+
* Uses node:http + the `ws` package in place of Bun.serve so this module
|
|
5
|
+
* runs under both Bun (dev / compiled binary) and Node.js (Electron in-process).
|
|
6
|
+
*
|
|
7
|
+
* This module deliberately avoids any bundler runtime (vite/rollup/esbuild)
|
|
8
|
+
* — see ADR `docs/adr/0001-no-bundlers-at-runtime.md`.
|
|
9
|
+
*/
|
|
10
|
+
import type { ServerState } from './server-context.ts';
|
|
11
|
+
/**
|
|
12
|
+
* Public handle for the running preview server.
|
|
13
|
+
*/
|
|
14
|
+
export interface PreviewServer {
|
|
15
|
+
/** Port the server is listening on. */
|
|
16
|
+
port: number;
|
|
17
|
+
/** Stop the server and close all connections. */
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Broadcast a `{ type: "full-reload" }` message to every connected HMR
|
|
21
|
+
* client. Safe to call after `close()` (no-op).
|
|
22
|
+
*/
|
|
23
|
+
broadcastReload(): void;
|
|
24
|
+
}
|
|
25
|
+
export declare function isPortAvailable(port: number, host?: string): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Find the next available port starting from `startPort`.
|
|
28
|
+
*
|
|
29
|
+
* @throws {UsageError} If the start port itself is invalid.
|
|
30
|
+
* @throws {BuildError} If valid ports are exhausted or the host cannot bind.
|
|
31
|
+
*/
|
|
32
|
+
export declare function findAvailablePort(startPort: number, host?: string): Promise<number>;
|
|
33
|
+
/**
|
|
34
|
+
* Create and start a preview HTTP+WebSocket server.
|
|
35
|
+
*
|
|
36
|
+
* `book.html` — the one file gutterpress generates — is served from
|
|
37
|
+
* `state.tempDir`. Everything else a served page can ask for (an `<img src>`
|
|
38
|
+
* at its authored project-relative path, or any other project file) is
|
|
39
|
+
* served DIRECTLY from `state.currentInputPath`, the real project directory,
|
|
40
|
+
* not a copy of it — see lifecycle.ts's `initializePreviewDirectories` for
|
|
41
|
+
* why. This is what makes preview asset resolution identical to the build's
|
|
42
|
+
* BY CONSTRUCTION: both resolve a reference against the same real project
|
|
43
|
+
* tree, so a path that works in one works in the other.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createPreviewServer(state: ServerState, port: number): Promise<PreviewServer>;
|