@uniweb/unipress 0.8.10 → 0.8.12
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/package.json +6 -6
- package/src/foundation-loader.js +7 -23
- package/src/foundations-data.js +28 -11
- package/src/registry-base.js +91 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/unipress",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.12",
|
|
4
4
|
"description": "Compile a content directory into a document (PDF, EPUB, Paged.js HTML, Typst source bundle, DOCX, XLSX) using a Uniweb foundation. Five built-in templates: book, monograph, report, data-report, directory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"prompts": "^2.4.2",
|
|
50
50
|
"react": "^19.0.0",
|
|
51
51
|
"react-dom": "^19.0.0",
|
|
52
|
-
"@uniweb/
|
|
53
|
-
"@uniweb/core": "^0.
|
|
54
|
-
"@uniweb/runtime": "^0.12.
|
|
55
|
-
"@uniweb/
|
|
56
|
-
"@uniweb/
|
|
52
|
+
"@uniweb/build": "^0.25.0",
|
|
53
|
+
"@uniweb/core": "^0.11.1",
|
|
54
|
+
"@uniweb/runtime": "^0.12.9",
|
|
55
|
+
"@uniweb/semantic-parser": "^1.3.0",
|
|
56
|
+
"@uniweb/content-reader": "^1.2.4"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"vitest": "^4.1.7"
|
package/src/foundation-loader.js
CHANGED
|
@@ -33,6 +33,7 @@ import { resolve, isAbsolute, join, dirname } from 'node:path'
|
|
|
33
33
|
import { FoundationResolutionError } from './errors.js'
|
|
34
34
|
import { findCatalogEntry } from './catalog.js'
|
|
35
35
|
import { fetchFoundationToCache } from './foundation-fetch.js'
|
|
36
|
+
import { foundationUrl } from './registry-base.js'
|
|
36
37
|
|
|
37
38
|
const URL_PATTERN = /^https?:\/\//
|
|
38
39
|
const PATH_PATTERN = /^(\.\.?[\/\\]|[\/\\]|[A-Za-z]:[\/\\])/
|
|
@@ -42,32 +43,15 @@ const PATH_PATTERN = /^(\.\.?[\/\\]|[\/\\]|[A-Za-z]:[\/\\])/
|
|
|
42
43
|
// registry decides what's valid.
|
|
43
44
|
const REGISTRY_REF_PATTERN = /^@([a-z0-9][a-z0-9._-]*)\/([a-z0-9][a-z0-9._-]*)@([0-9a-z][0-9a-z.\-+]*)$/i
|
|
44
45
|
|
|
45
|
-
// unipress's bundled foundations are distributed as static artifacts on
|
|
46
|
-
// the unipress repo's GitHub Pages site. URL pattern:
|
|
47
|
-
//
|
|
48
|
-
// https://uniweb.github.io/unipress/foundations/<name>/<version>/entry.js
|
|
49
|
-
//
|
|
50
|
-
// The namespace portion of a registry ref is implicit — every foundation
|
|
51
|
-
// served from this base is under @uniweb/. Set UNIWEB_REGISTRY_URL to
|
|
52
|
-
// override (e.g., for testing against a local http.server during foundation
|
|
53
|
-
// development, or for users with a private alternative).
|
|
54
|
-
const DEFAULT_REGISTRY_BASE = 'https://uniweb.github.io/unipress'
|
|
55
46
|
const DEFAULT_BUILT_ENTRY = 'dist/entry.js'
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Build the URL for a registry ref. The namespace is preserved in the
|
|
63
|
-
// returned URL only when the base wants it; for the GH Pages distribution
|
|
64
|
-
// the namespace is implicit and the path is <base>/foundations/<name>/<ver>/.
|
|
65
|
-
// If a custom UNIWEB_REGISTRY_URL needs the namespace in the path, it can
|
|
66
|
-
// hold a path prefix that resolves accordingly (e.g., set
|
|
67
|
-
// `UNIWEB_REGISTRY_URL=https://my.host/by-ns/uniweb` and live without the
|
|
68
|
-
// per-namespace split, or maintain a redirect rule on that host).
|
|
48
|
+
// Build the URL for a registry ref. The base + layout live in registry-base.js,
|
|
49
|
+
// shared with the catalog so the URL we FETCH and the URL we SHOW cannot drift
|
|
50
|
+
// (and so both honour UNIWEB_REGISTRY_URL). The `namespace` is accepted and
|
|
51
|
+
// unused: every foundation under this layout is @uniweb/, so a ref's scope does
|
|
52
|
+
// not appear in the path — see foundationPath's note on per-namespace bases.
|
|
69
53
|
function buildRegistryUrl(namespace, name, version) {
|
|
70
|
-
return
|
|
54
|
+
return foundationUrl(name, version)
|
|
71
55
|
}
|
|
72
56
|
|
|
73
57
|
export async function resolveFoundationRef(ref, { anchorDir, onProgress = () => {} } = {}) {
|
package/src/foundations-data.js
CHANGED
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
* ─────────────────────────────────────────────────────────────────────────
|
|
15
15
|
*
|
|
16
16
|
* Foundations are deployed as static artifacts to the unipress repo's
|
|
17
|
-
* GitHub Pages site. URL
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* GitHub Pages site. **The base and the URL rule live in `registry-base.js`** —
|
|
18
|
+
* one definition, shared with `foundation-loader.js`, so what this catalog shows
|
|
19
|
+
* and what `compile` fetches cannot disagree.
|
|
20
20
|
*
|
|
21
21
|
* On every push to main, `.github/workflows/deploy-foundations.yml`
|
|
22
22
|
* builds each `foundations/<name>/` and layers the resulting `dist/` into
|
|
@@ -52,9 +52,23 @@
|
|
|
52
52
|
*
|
|
53
53
|
* Each entry's `foundation.source.url` is the human-meaningful "where this
|
|
54
54
|
* foundation lives" pointer shown in `list-templates` output and post-create
|
|
55
|
-
* messages. It
|
|
56
|
-
*
|
|
57
|
-
*
|
|
55
|
+
* messages. It does not itself drive resolution — the loader builds its own URL
|
|
56
|
+
* from `foundation.ref` + the configured base.
|
|
57
|
+
*
|
|
58
|
+
* ⚠️ **It is built from the same helper the loader resolves through**
|
|
59
|
+
* (`registry-base.js::foundationUrl`), and that is load-bearing rather than tidy.
|
|
60
|
+
* Until 2026-08-22 this file held its own hardcoded base, so it ignored
|
|
61
|
+
* `UNIWEB_REGISTRY_URL`: pointing unipress at a local registry left
|
|
62
|
+
* `list-templates` printing the GitHub Pages URL — an address the tool was not
|
|
63
|
+
* using, reported at exactly the moment someone was debugging which address it
|
|
64
|
+
* used. "Display only" is not "free to be wrong."
|
|
65
|
+
*
|
|
66
|
+
* ⛔ There is also a live fallback that DOES resolve from this field:
|
|
67
|
+
* `foundation-loader.js::resolveCatalogRef` fetches `source.url` directly when an
|
|
68
|
+
* entry carries no registry-shaped `foundation.ref` (the v0.1 legacy shape). No
|
|
69
|
+
* current entry hits it — all 8 carry a ref — but an entry added without one
|
|
70
|
+
* would resolve through this URL. Sharing the helper means that path honours the
|
|
71
|
+
* override too, instead of silently pinning to our origin.
|
|
58
72
|
*
|
|
59
73
|
* ─────────────────────────────────────────────────────────────────────────
|
|
60
74
|
* Storage format
|
|
@@ -62,14 +76,17 @@
|
|
|
62
76
|
*
|
|
63
77
|
* Stored as a plain JS module (not YAML) so `bun build --compile` can
|
|
64
78
|
* inline it at bundle time. The compiled binary has no filesystem for
|
|
65
|
-
* runtime reads.
|
|
79
|
+
* runtime reads. Its one import (`registry-base.js`) is a zero-import leaf, so
|
|
80
|
+
* the catalog stays inlinable; the base is still read from the environment at
|
|
81
|
+
* call time rather than frozen into the binary.
|
|
66
82
|
*/
|
|
67
83
|
|
|
68
|
-
|
|
84
|
+
import { foundationUrl } from './registry-base.js'
|
|
69
85
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
86
|
+
// `foundationUrl` is the SAME helper foundation-loader.js resolves through, so
|
|
87
|
+
// what we show here is what compile will fetch — including under a
|
|
88
|
+
// UNIWEB_REGISTRY_URL override, which the old local constant ignored.
|
|
89
|
+
const publicUrl = (name, version) => foundationUrl(name, version)
|
|
73
90
|
|
|
74
91
|
const BOOK_FOUNDATION = {
|
|
75
92
|
ref: '@uniweb/book@0.4.2',
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unipress foundation registry — its origin and its URL rule.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this is a module and not two constants
|
|
5
|
+
*
|
|
6
|
+
* unipress's bundled foundations are static artifacts on the unipress repo's
|
|
7
|
+
* GitHub Pages site, laid out as:
|
|
8
|
+
*
|
|
9
|
+
* <base>/foundations/<name>/<version>/entry.js
|
|
10
|
+
*
|
|
11
|
+
* That layout is **ours** — `.github/workflows/deploy-foundations.yml` writes it
|
|
12
|
+
* — so a default origin is the correct answer rather than a guessed one, and the
|
|
13
|
+
* filename rule is ours to name. But the base is overridable (`UNIWEB_REGISTRY_URL`),
|
|
14
|
+
* which makes this a **writer/reader pair**:
|
|
15
|
+
*
|
|
16
|
+
* reader foundation-loader.js buildRegistryUrl() — what `compile` FETCHES
|
|
17
|
+
* reader foundations-data.js each entry's `foundation.source.url` — what
|
|
18
|
+
* `create` and `list-templates` SHOW the user
|
|
19
|
+
*
|
|
20
|
+
* Before 2026-08-22 those held two hardcoded spellings of one base, decomposed
|
|
21
|
+
* differently — `foundations-data.js` baked `/foundations` into its constant while
|
|
22
|
+
* the loader kept it out and appended it when building. So the two edits needed to
|
|
23
|
+
* move the base did not look alike, and nothing caught a half-finished move. Worse,
|
|
24
|
+
* only the loader honoured `UNIWEB_REGISTRY_URL`: point unipress at a local
|
|
25
|
+
* registry and `list-templates` still printed the GitHub Pages URL, which is not
|
|
26
|
+
* the URL `compile` would fetch. A tool that reports an address it is not using is
|
|
27
|
+
* a bad instrument, and diagnostics is exactly when the override is in play.
|
|
28
|
+
*
|
|
29
|
+
* Same treatment as `@uniweb/core/icon-corpus`, for the same reason: one helper,
|
|
30
|
+
* no second spelling.
|
|
31
|
+
*
|
|
32
|
+
* ## ⛔ Keep this a LEAF — zero imports
|
|
33
|
+
*
|
|
34
|
+
* The import graph runs `foundation-loader.js` → `catalog.js` → `foundations-data.js`,
|
|
35
|
+
* so the catalog cannot import the loader — that is a cycle, and it is why the
|
|
36
|
+
* constant was duplicated in the first place rather than through carelessness. A
|
|
37
|
+
* leaf both sides import is the only shape that works. Keeping it import-free also
|
|
38
|
+
* keeps `bun build --compile` able to inline the catalog (see foundations-data.js
|
|
39
|
+
* § Storage format).
|
|
40
|
+
*
|
|
41
|
+
* @module unipress/registry-base
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Where unipress publishes its own foundations.
|
|
46
|
+
*
|
|
47
|
+
* Not a fallback for a missing address — it is the address of OUR artifact, and it
|
|
48
|
+
* is what makes `unipress create --template book` work with nothing configured.
|
|
49
|
+
*/
|
|
50
|
+
export const DEFAULT_REGISTRY_BASE = 'https://uniweb.github.io/unipress'
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The configured registry base: `UNIWEB_REGISTRY_URL` when set, else ours.
|
|
54
|
+
*
|
|
55
|
+
* Read at call time, not frozen at import, so a caller that sets the variable
|
|
56
|
+
* programmatically before invoking a command still gets it.
|
|
57
|
+
*
|
|
58
|
+
* @returns {string} the base, without a trailing slash
|
|
59
|
+
*/
|
|
60
|
+
export function getRegistryBase() {
|
|
61
|
+
const raw = process.env.UNIWEB_REGISTRY_URL || DEFAULT_REGISTRY_BASE
|
|
62
|
+
return String(raw).replace(/\/+$/, '')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The registry path for one foundation, relative to any base serving it.
|
|
67
|
+
*
|
|
68
|
+
* ⚠️ The **namespace is implicit** — every foundation under this layout is
|
|
69
|
+
* `@uniweb/`, so a ref's scope does not appear in the path. A custom
|
|
70
|
+
* `UNIWEB_REGISTRY_URL` that needs a per-namespace split carries it in the base
|
|
71
|
+
* (e.g. `https://my.host/by-ns/uniweb`) or answers it with a redirect.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} name - the foundation name, unscoped (e.g. 'book')
|
|
74
|
+
* @param {string} version
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
export function foundationPath(name, version) {
|
|
78
|
+
return `foundations/${name}/${version}/entry.js`
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The full URL for one foundation against a serving base.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} name - the foundation name, unscoped
|
|
85
|
+
* @param {string} version
|
|
86
|
+
* @param {string} [base] - serving base; defaults to the configured one
|
|
87
|
+
* @returns {string}
|
|
88
|
+
*/
|
|
89
|
+
export function foundationUrl(name, version, base = getRegistryBase()) {
|
|
90
|
+
return `${String(base).replace(/\/+$/, '')}/${foundationPath(name, version)}`
|
|
91
|
+
}
|