gazetta 0.6.0 → 0.7.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/admin-dist/assets/index-BO9-CXmW.css +1 -0
- package/admin-dist/assets/index-Ufu8zZH_.js +668 -0
- package/admin-dist/index.html +2 -2
- package/dist/admin-api/error-response.d.ts +21 -0
- package/dist/admin-api/error-response.d.ts.map +1 -0
- package/dist/admin-api/error-response.js +12 -0
- package/dist/admin-api/error-response.js.map +1 -0
- package/dist/admin-api/index.d.ts +0 -2
- package/dist/admin-api/index.d.ts.map +1 -1
- package/dist/admin-api/index.js +4 -24
- package/dist/admin-api/index.js.map +1 -1
- package/dist/admin-api/routes/assets.d.ts +16 -0
- package/dist/admin-api/routes/assets.d.ts.map +1 -0
- package/dist/admin-api/routes/assets.js +433 -0
- package/dist/admin-api/routes/assets.js.map +1 -0
- package/dist/admin-api/routes/fragments.d.ts.map +1 -1
- package/dist/admin-api/routes/fragments.js +30 -4
- package/dist/admin-api/routes/fragments.js.map +1 -1
- package/dist/admin-api/routes/pages.d.ts.map +1 -1
- package/dist/admin-api/routes/pages.js +37 -4
- package/dist/admin-api/routes/pages.js.map +1 -1
- package/dist/admin-api/routes/publish.d.ts.map +1 -1
- package/dist/admin-api/routes/publish.js +68 -35
- package/dist/admin-api/routes/publish.js.map +1 -1
- package/dist/admin-api/schemas/assets.d.ts +48 -0
- package/dist/admin-api/schemas/assets.d.ts.map +1 -0
- package/dist/admin-api/schemas/assets.js +44 -0
- package/dist/admin-api/schemas/assets.js.map +1 -0
- package/dist/admin-api/schemas/index.d.ts +2 -0
- package/dist/admin-api/schemas/index.d.ts.map +1 -1
- package/dist/admin-api/schemas/index.js +2 -0
- package/dist/admin-api/schemas/index.js.map +1 -1
- package/dist/admin-api/source-context.d.ts +0 -7
- package/dist/admin-api/source-context.d.ts.map +1 -1
- package/dist/admin-api/source-context.js +0 -3
- package/dist/admin-api/source-context.js.map +1 -1
- package/dist/assets/analyze-audio.d.ts +3 -0
- package/dist/assets/analyze-audio.d.ts.map +1 -0
- package/dist/assets/analyze-audio.js +80 -0
- package/dist/assets/analyze-audio.js.map +1 -0
- package/dist/assets/analyze-image.d.ts +19 -0
- package/dist/assets/analyze-image.d.ts.map +1 -0
- package/dist/assets/analyze-image.js +123 -0
- package/dist/assets/analyze-image.js.map +1 -0
- package/dist/assets/analyze.d.ts +94 -0
- package/dist/assets/analyze.d.ts.map +1 -0
- package/dist/assets/analyze.js +45 -0
- package/dist/assets/analyze.js.map +1 -0
- package/dist/assets/asset-deps.d.ts +30 -0
- package/dist/assets/asset-deps.d.ts.map +1 -0
- package/dist/assets/asset-deps.js +42 -0
- package/dist/assets/asset-deps.js.map +1 -0
- package/dist/assets/asset-paths.d.ts +155 -0
- package/dist/assets/asset-paths.d.ts.map +1 -0
- package/dist/assets/asset-paths.js +197 -0
- package/dist/assets/asset-paths.js.map +1 -0
- package/dist/assets/delete.d.ts +75 -0
- package/dist/assets/delete.d.ts.map +1 -0
- package/dist/assets/delete.js +82 -0
- package/dist/assets/delete.js.map +1 -0
- package/dist/assets/errors.d.ts +241 -0
- package/dist/assets/errors.d.ts.map +1 -0
- package/dist/assets/errors.js +300 -0
- package/dist/assets/errors.js.map +1 -0
- package/dist/assets/find-refs.d.ts +37 -0
- package/dist/assets/find-refs.d.ts.map +1 -0
- package/dist/assets/find-refs.js +35 -0
- package/dist/assets/find-refs.js.map +1 -0
- package/dist/assets/hash.d.ts +13 -0
- package/dist/assets/hash.d.ts.map +1 -0
- package/dist/assets/hash.js +43 -0
- package/dist/assets/hash.js.map +1 -0
- package/dist/assets/image-metadata.d.ts +11 -0
- package/dist/assets/image-metadata.d.ts.map +1 -0
- package/dist/assets/image-metadata.js +31 -0
- package/dist/assets/image-metadata.js.map +1 -0
- package/dist/assets/ingest-locale.d.ts +86 -0
- package/dist/assets/ingest-locale.d.ts.map +1 -0
- package/dist/assets/ingest-locale.js +209 -0
- package/dist/assets/ingest-locale.js.map +1 -0
- package/dist/assets/ingest.d.ts +96 -0
- package/dist/assets/ingest.d.ts.map +1 -0
- package/dist/assets/ingest.js +308 -0
- package/dist/assets/ingest.js.map +1 -0
- package/dist/assets/kind-compat.d.ts +34 -0
- package/dist/assets/kind-compat.d.ts.map +1 -0
- package/dist/assets/kind-compat.js +33 -0
- package/dist/assets/kind-compat.js.map +1 -0
- package/dist/assets/list.d.ts +46 -0
- package/dist/assets/list.d.ts.map +1 -0
- package/dist/assets/list.js +102 -0
- package/dist/assets/list.js.map +1 -0
- package/dist/assets/manifest-default.d.ts +56 -0
- package/dist/assets/manifest-default.d.ts.map +1 -0
- package/dist/assets/manifest-default.js +120 -0
- package/dist/assets/manifest-default.js.map +1 -0
- package/dist/assets/manifest-filename.d.ts +52 -0
- package/dist/assets/manifest-filename.d.ts.map +1 -0
- package/dist/assets/manifest-filename.js +104 -0
- package/dist/assets/manifest-filename.js.map +1 -0
- package/dist/assets/manifest-locale.d.ts +60 -0
- package/dist/assets/manifest-locale.d.ts.map +1 -0
- package/dist/assets/manifest-locale.js +206 -0
- package/dist/assets/manifest-locale.js.map +1 -0
- package/dist/assets/manifest-merge.d.ts +66 -0
- package/dist/assets/manifest-merge.d.ts.map +1 -0
- package/dist/assets/manifest-merge.js +82 -0
- package/dist/assets/manifest-merge.js.map +1 -0
- package/dist/assets/manifest.d.ts +83 -0
- package/dist/assets/manifest.d.ts.map +1 -0
- package/dist/assets/manifest.js +93 -0
- package/dist/assets/manifest.js.map +1 -0
- package/dist/assets/mime-sniff.d.ts +18 -0
- package/dist/assets/mime-sniff.d.ts.map +1 -0
- package/dist/assets/mime-sniff.js +84 -0
- package/dist/assets/mime-sniff.js.map +1 -0
- package/dist/assets/preprocess-svg.d.ts +3 -0
- package/dist/assets/preprocess-svg.d.ts.map +1 -0
- package/dist/assets/preprocess-svg.js +49 -0
- package/dist/assets/preprocess-svg.js.map +1 -0
- package/dist/assets/preprocess.d.ts +62 -0
- package/dist/assets/preprocess.d.ts.map +1 -0
- package/dist/assets/preprocess.js +86 -0
- package/dist/assets/preprocess.js.map +1 -0
- package/dist/assets/publish-plan.d.ts +41 -0
- package/dist/assets/publish-plan.d.ts.map +1 -0
- package/dist/assets/publish-plan.js +49 -0
- package/dist/assets/publish-plan.js.map +1 -0
- package/dist/assets/publish.d.ts +33 -0
- package/dist/assets/publish.d.ts.map +1 -0
- package/dist/assets/publish.js +81 -0
- package/dist/assets/publish.js.map +1 -0
- package/dist/assets/refs.d.ts +37 -0
- package/dist/assets/refs.d.ts.map +1 -0
- package/dist/assets/refs.js +33 -0
- package/dist/assets/refs.js.map +1 -0
- package/dist/assets/remove-override.d.ts +42 -0
- package/dist/assets/remove-override.d.ts.map +1 -0
- package/dist/assets/remove-override.js +53 -0
- package/dist/assets/remove-override.js.map +1 -0
- package/dist/assets/rename.d.ts +43 -0
- package/dist/assets/rename.d.ts.map +1 -0
- package/dist/assets/rename.js +271 -0
- package/dist/assets/rename.js.map +1 -0
- package/dist/assets/replace.d.ts +37 -0
- package/dist/assets/replace.d.ts.map +1 -0
- package/dist/assets/replace.js +195 -0
- package/dist/assets/replace.js.map +1 -0
- package/dist/assets/resolve.d.ts +141 -0
- package/dist/assets/resolve.d.ts.map +1 -0
- package/dist/assets/resolve.js +381 -0
- package/dist/assets/resolve.js.map +1 -0
- package/dist/assets/rewrite-manifest-asset-ref.d.ts +44 -0
- package/dist/assets/rewrite-manifest-asset-ref.d.ts.map +1 -0
- package/dist/assets/rewrite-manifest-asset-ref.js +51 -0
- package/dist/assets/rewrite-manifest-asset-ref.js.map +1 -0
- package/dist/assets/scan-manifest-for-asset.d.ts +63 -0
- package/dist/assets/scan-manifest-for-asset.d.ts.map +1 -0
- package/dist/assets/scan-manifest-for-asset.js +105 -0
- package/dist/assets/scan-manifest-for-asset.js.map +1 -0
- package/dist/assets/serve-route.d.ts +45 -0
- package/dist/assets/serve-route.d.ts.map +1 -0
- package/dist/assets/serve-route.js +123 -0
- package/dist/assets/serve-route.js.map +1 -0
- package/dist/assets/svg-sanitize.d.ts +38 -0
- package/dist/assets/svg-sanitize.d.ts.map +1 -0
- package/dist/assets/svg-sanitize.js +209 -0
- package/dist/assets/svg-sanitize.js.map +1 -0
- package/dist/assets/update-metadata.d.ts +61 -0
- package/dist/assets/update-metadata.d.ts.map +1 -0
- package/dist/assets/update-metadata.js +82 -0
- package/dist/assets/update-metadata.js.map +1 -0
- package/dist/assets/url.d.ts +82 -0
- package/dist/assets/url.d.ts.map +1 -0
- package/dist/assets/url.js +103 -0
- package/dist/assets/url.js.map +1 -0
- package/dist/assets/validate.d.ts +74 -0
- package/dist/assets/validate.d.ts.map +1 -0
- package/dist/assets/validate.js +136 -0
- package/dist/assets/validate.js.map +1 -0
- package/dist/assets/variants.d.ts +23 -0
- package/dist/assets/variants.d.ts.map +1 -0
- package/dist/assets/variants.js +74 -0
- package/dist/assets/variants.js.map +1 -0
- package/dist/cli/assets-cli.d.ts +58 -0
- package/dist/cli/assets-cli.d.ts.map +1 -0
- package/dist/cli/assets-cli.js +233 -0
- package/dist/cli/assets-cli.js.map +1 -0
- package/dist/cli/assets-display.d.ts +112 -0
- package/dist/cli/assets-display.d.ts.map +1 -0
- package/dist/cli/assets-display.js +106 -0
- package/dist/cli/assets-display.js.map +1 -0
- package/dist/cli/bootstrap.d.ts +0 -2
- package/dist/cli/bootstrap.d.ts.map +1 -1
- package/dist/cli/bootstrap.js +0 -1
- package/dist/cli/bootstrap.js.map +1 -1
- package/dist/cli/index.js +64 -18
- package/dist/cli/index.js.map +1 -1
- package/dist/compare.d.ts.map +1 -1
- package/dist/compare.js +15 -12
- package/dist/compare.js.map +1 -1
- package/dist/dep-sidecars.d.ts +127 -0
- package/dist/dep-sidecars.d.ts.map +1 -0
- package/dist/dep-sidecars.js +122 -0
- package/dist/dep-sidecars.js.map +1 -0
- package/dist/editor/AssetEmbeddedWidget.d.ts +3 -0
- package/dist/editor/AssetEmbeddedWidget.d.ts.map +1 -0
- package/dist/editor/AssetEmbeddedWidget.js +146 -0
- package/dist/editor/AssetEmbeddedWidget.js.map +1 -0
- package/dist/editor/mount.d.ts +12 -1
- package/dist/editor/mount.d.ts.map +1 -1
- package/dist/editor/mount.js +36 -5
- package/dist/editor/mount.js.map +1 -1
- package/dist/format.d.ts +44 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +65 -0
- package/dist/format.js.map +1 -0
- package/dist/fragment-deps.d.ts +24 -0
- package/dist/fragment-deps.d.ts.map +1 -0
- package/dist/fragment-deps.js +20 -0
- package/dist/fragment-deps.js.map +1 -0
- package/dist/hash.d.ts +0 -6
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js +0 -18
- package/dist/hash.js.map +1 -1
- package/dist/history-provider.d.ts.map +1 -1
- package/dist/history-provider.js +30 -8
- package/dist/history-provider.js.map +1 -1
- package/dist/history-recorder.d.ts +7 -3
- package/dist/history-recorder.d.ts.map +1 -1
- package/dist/history-recorder.js +9 -1
- package/dist/history-recorder.js.map +1 -1
- package/dist/history-restorer.d.ts.map +1 -1
- package/dist/history-restorer.js +34 -2
- package/dist/history-restorer.js.map +1 -1
- package/dist/history.d.ts +26 -8
- package/dist/history.d.ts.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/locale.d.ts +20 -0
- package/dist/locale.d.ts.map +1 -1
- package/dist/locale.js +38 -0
- package/dist/locale.js.map +1 -1
- package/dist/providers/_atomic-write.d.ts +9 -0
- package/dist/providers/_atomic-write.d.ts.map +1 -0
- package/dist/providers/_atomic-write.js +72 -0
- package/dist/providers/_atomic-write.js.map +1 -0
- package/dist/providers/_rm-ignore-missing.d.ts +31 -0
- package/dist/providers/_rm-ignore-missing.d.ts.map +1 -0
- package/dist/providers/_rm-ignore-missing.js +12 -0
- package/dist/providers/_rm-ignore-missing.js.map +1 -0
- package/dist/providers/_stream-interop.d.ts +23 -0
- package/dist/providers/_stream-interop.d.ts.map +1 -0
- package/dist/providers/_stream-interop.js +21 -0
- package/dist/providers/_stream-interop.js.map +1 -0
- package/dist/providers/azure-blob.d.ts.map +1 -1
- package/dist/providers/azure-blob.js +60 -0
- package/dist/providers/azure-blob.js.map +1 -1
- package/dist/providers/filesystem.d.ts +4 -0
- package/dist/providers/filesystem.d.ts.map +1 -1
- package/dist/providers/filesystem.js +63 -2
- package/dist/providers/filesystem.js.map +1 -1
- package/dist/providers/s3.d.ts.map +1 -1
- package/dist/providers/s3.js +84 -1
- package/dist/providers/s3.js.map +1 -1
- package/dist/publish-rendered.d.ts +37 -17
- package/dist/publish-rendered.d.ts.map +1 -1
- package/dist/publish-rendered.js +71 -67
- package/dist/publish-rendered.js.map +1 -1
- package/dist/publish.d.ts +13 -12
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +23 -47
- package/dist/publish.js.map +1 -1
- package/dist/resolver.d.ts +12 -2
- package/dist/resolver.d.ts.map +1 -1
- package/dist/resolver.js +54 -9
- package/dist/resolver.js.map +1 -1
- package/dist/schema/dimensions.d.ts +78 -0
- package/dist/schema/dimensions.d.ts.map +1 -0
- package/dist/schema/dimensions.js +97 -0
- package/dist/schema/dimensions.js.map +1 -0
- package/dist/schema/helpers.d.ts +108 -0
- package/dist/schema/helpers.d.ts.map +1 -0
- package/dist/schema/helpers.js +133 -0
- package/dist/schema/helpers.js.map +1 -0
- package/dist/schema/index.d.ts +27 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +25 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/types.d.ts +390 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +25 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/selector-chain.d.ts +63 -0
- package/dist/selector-chain.d.ts.map +1 -0
- package/dist/selector-chain.js +58 -0
- package/dist/selector-chain.js.map +1 -0
- package/dist/sidecars.d.ts +19 -18
- package/dist/sidecars.d.ts.map +1 -1
- package/dist/sidecars.js +70 -62
- package/dist/sidecars.js.map +1 -1
- package/dist/targets.d.ts.map +1 -1
- package/dist/targets.js +15 -37
- package/dist/targets.js.map +1 -1
- package/dist/themes.d.ts +69 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +85 -0
- package/dist/themes.js.map +1 -0
- package/dist/transforms/adapter.d.ts +115 -0
- package/dist/transforms/adapter.d.ts.map +1 -0
- package/dist/transforms/adapter.js +2 -0
- package/dist/transforms/adapter.js.map +1 -0
- package/dist/transforms/cloudflare.d.ts +17 -0
- package/dist/transforms/cloudflare.d.ts.map +1 -0
- package/dist/transforms/cloudflare.js +110 -0
- package/dist/transforms/cloudflare.js.map +1 -0
- package/dist/transforms/index.d.ts +24 -0
- package/dist/transforms/index.d.ts.map +1 -0
- package/dist/transforms/index.js +30 -0
- package/dist/transforms/index.js.map +1 -0
- package/dist/transforms/sharp.d.ts +3 -0
- package/dist/transforms/sharp.d.ts.map +1 -0
- package/dist/transforms/sharp.js +43 -0
- package/dist/transforms/sharp.js.map +1 -0
- package/dist/types.d.ts +125 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +20 -1
- package/admin-dist/assets/index-B6pVot0Y.css +0 -1
- package/admin-dist/assets/index-DniLwxJA.js +0 -609
- package/dist/providers/r2.d.ts +0 -8
- package/dist/providers/r2.d.ts.map +0 -1
- package/dist/providers/r2.js +0 -86
- package/dist/providers/r2.js.map +0 -1
- package/dist/source-sidecars.d.ts +0 -32
- package/dist/source-sidecars.d.ts.map +0 -1
- package/dist/source-sidecars.js +0 -98
- package/dist/source-sidecars.js.map +0 -1
package/dist/sidecars.js
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sidecar file I/O for pages and fragments — one module owning all reads
|
|
3
|
-
* and writes of the
|
|
3
|
+
* and writes of the two sidecar kinds:
|
|
4
4
|
*
|
|
5
5
|
* .{8hex}.hash — content hash, used by compare-targets
|
|
6
|
-
* .
|
|
7
|
-
* .tpl-{template} — template name; used to flag republish-needed
|
|
6
|
+
* .pub-... — publish timestamp + noindex flag
|
|
8
7
|
*
|
|
9
|
-
* Filenames encode the
|
|
10
|
-
*
|
|
11
|
-
* listing calls, not GETs, at 10k pages.
|
|
8
|
+
* Filenames encode the publish-state picture — a single readDir returns
|
|
9
|
+
* the full sidecar state of an item without any content reads. Scaling
|
|
10
|
+
* goal: listing calls, not GETs, at 10k pages.
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* without touching every caller.
|
|
12
|
+
* Reverse dep relationships (fragment-deps, asset-refs) live in
|
|
13
|
+
* `.gazetta/{relation}/{target}/{source}` per-edge sidecars (see
|
|
14
|
+
* dep-sidecars.ts), not in per-item filename suffixes.
|
|
17
15
|
*/
|
|
18
|
-
import { parseSidecarName, parseSidecarLocale, sidecarNameFor,
|
|
16
|
+
import { parseSidecarName, parseSidecarLocale, sidecarNameFor, parsePubSidecarName, parsePubSidecarLocale, pubSidecarNameFor, } from './hash.js';
|
|
19
17
|
import { mapLimit } from './concurrency.js';
|
|
20
18
|
/**
|
|
21
19
|
* Read sidecar filenames for a single item directory. Returns null if
|
|
22
|
-
* the directory doesn't exist or has no hash sidecar.
|
|
23
|
-
* `template` default to empty/null when their sidecars are absent —
|
|
24
|
-
* old items published before we started writing them will still work,
|
|
25
|
-
* the caller just won't have dependency info for them.
|
|
20
|
+
* the directory doesn't exist or has no hash sidecar.
|
|
26
21
|
*/
|
|
27
22
|
export async function readSidecars(storage, dir) {
|
|
28
23
|
let entries;
|
|
@@ -33,8 +28,6 @@ export async function readSidecars(storage, dir) {
|
|
|
33
28
|
return null;
|
|
34
29
|
}
|
|
35
30
|
let hash = null;
|
|
36
|
-
const uses = [];
|
|
37
|
-
let template = null;
|
|
38
31
|
let pub = null;
|
|
39
32
|
for (const e of entries) {
|
|
40
33
|
if (e.isDirectory)
|
|
@@ -44,48 +37,43 @@ export async function readSidecars(storage, dir) {
|
|
|
44
37
|
hash = h;
|
|
45
38
|
continue;
|
|
46
39
|
}
|
|
47
|
-
const u = parseUsesSidecarName(e.name);
|
|
48
|
-
if (u) {
|
|
49
|
-
uses.push(u);
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
const t = parseTemplateSidecarName(e.name);
|
|
53
|
-
if (t) {
|
|
54
|
-
template = t;
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
40
|
const p = parsePubSidecarName(e.name);
|
|
58
41
|
if (p)
|
|
59
42
|
pub = p;
|
|
60
43
|
}
|
|
61
44
|
if (!hash)
|
|
62
45
|
return null;
|
|
63
|
-
return { hash,
|
|
46
|
+
return { hash, pub };
|
|
64
47
|
}
|
|
65
48
|
/**
|
|
66
49
|
* Write (or rewrite) sidecars for one item, optionally locale-scoped.
|
|
67
50
|
* When `locale` is set, only locale-specific sidecars (.hash.fr, .pub.fr)
|
|
68
|
-
* are written/cleaned — default-locale sidecars are untouched.
|
|
69
|
-
*
|
|
51
|
+
* are written/cleaned — default-locale sidecars are untouched.
|
|
52
|
+
*
|
|
53
|
+
* Concurrency:
|
|
54
|
+
* Calls targeting the same directory are serialized via `withDirLock`.
|
|
55
|
+
* Without serialization, Call A's cleanup phase (readDir → rm stale)
|
|
56
|
+
* would see Call B's in-flight `write-file-atomic` temp files and
|
|
57
|
+
* mistake them for stale sidecars — B's rename would then fail with
|
|
58
|
+
* ENOENT. Queueing at dir granularity eliminates the race class,
|
|
59
|
+
* matching the same idiom `write-file-atomic` itself uses per-file
|
|
60
|
+
* within a process.
|
|
70
61
|
*/
|
|
71
62
|
export async function writeSidecars(storage, dir, state, locale) {
|
|
63
|
+
return withDirLock(dir, () => doWriteSidecars(storage, dir, state, locale));
|
|
64
|
+
}
|
|
65
|
+
async function doWriteSidecars(storage, dir, state, locale) {
|
|
72
66
|
const want = new Set([sidecarNameFor(state.hash, locale)]);
|
|
73
|
-
// Structural sidecars are locale-agnostic — only write for default locale
|
|
74
|
-
if (!locale) {
|
|
75
|
-
for (const frag of state.uses)
|
|
76
|
-
want.add(usesSidecarNameFor(frag));
|
|
77
|
-
if (state.template)
|
|
78
|
-
want.add(templateSidecarNameFor(state.template));
|
|
79
|
-
}
|
|
80
67
|
if (state.pub)
|
|
81
68
|
want.add(pubSidecarNameFor(new Date(state.pub.lastPublished), state.pub.noindex, locale));
|
|
82
69
|
// Remove stale sidecars of the SAME locale scope that aren't in `want`.
|
|
70
|
+
// Safe because `withDirLock` serializes concurrent callers on this dir —
|
|
71
|
+
// no other writer's atomic-write temp files can be in flight right now.
|
|
83
72
|
try {
|
|
84
73
|
const entries = await storage.readDir(dir);
|
|
85
74
|
for (const e of entries) {
|
|
86
75
|
if (want.has(e.name))
|
|
87
76
|
continue;
|
|
88
|
-
// Only clean sidecars matching this locale scope
|
|
89
77
|
const hashLocale = parseSidecarLocale(e.name);
|
|
90
78
|
const pubLocale = parsePubSidecarLocale(e.name);
|
|
91
79
|
if (parseSidecarName(e.name) && hashLocale === (locale ?? undefined)) {
|
|
@@ -104,16 +92,6 @@ export async function writeSidecars(storage, dir, state, locale) {
|
|
|
104
92
|
/* already gone */
|
|
105
93
|
}
|
|
106
94
|
}
|
|
107
|
-
else if (!locale && (parseUsesSidecarName(e.name) || parseTemplateSidecarName(e.name))) {
|
|
108
|
-
if (!want.has(e.name)) {
|
|
109
|
-
try {
|
|
110
|
-
await storage.rm(`${dir}/${e.name}`);
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
/* already gone */
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
95
|
}
|
|
118
96
|
}
|
|
119
97
|
catch {
|
|
@@ -122,6 +100,48 @@ export async function writeSidecars(storage, dir, state, locale) {
|
|
|
122
100
|
await storage.mkdir(dir);
|
|
123
101
|
await Promise.all([...want].map(name => storage.writeFile(`${dir}/${name}`, '')));
|
|
124
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Per-directory Promise-queue serialization for `writeSidecars`.
|
|
105
|
+
*
|
|
106
|
+
* Single responsibility: ensure at most one `writeSidecars` call is
|
|
107
|
+
* operating on a given directory at a time within this process. The
|
|
108
|
+
* race we're closing:
|
|
109
|
+
*
|
|
110
|
+
* Call A: readDir → sees `.hash` → rm `.hash` → writeFile new `.hash`
|
|
111
|
+
* ↑ creates temp
|
|
112
|
+
* Call B (parallel): readDir → sees A's temp file
|
|
113
|
+
* → matches permissive regex → rm temp
|
|
114
|
+
* → A's rename ENOENTs
|
|
115
|
+
*
|
|
116
|
+
* With serialization, B's readDir can only observe finalized state from
|
|
117
|
+
* A's completed run. No temp files exist when any call does its cleanup.
|
|
118
|
+
*
|
|
119
|
+
* Shape: per-key Promise chain. Each caller awaits the prior Promise for
|
|
120
|
+
* its key before running, and publishes its own Promise as the next
|
|
121
|
+
* "current holder" for that key. Matches the pattern `write-file-atomic`
|
|
122
|
+
* uses per-file (node_modules/write-file-atomic/lib/index.js, the
|
|
123
|
+
* `activeFiles` map), lifted here to per-directory granularity.
|
|
124
|
+
*
|
|
125
|
+
* Cross-process safety: not provided — the map is in-process state.
|
|
126
|
+
* Gazetta's admin is a single writer (one dev server, one publish
|
|
127
|
+
* process); cross-process coordination would require a sibling `.lock`
|
|
128
|
+
* file (git's pattern), which we don't need in this regime.
|
|
129
|
+
*/
|
|
130
|
+
const dirLocks = new Map();
|
|
131
|
+
async function withDirLock(dir, fn) {
|
|
132
|
+
const prev = dirLocks.get(dir) ?? Promise.resolve();
|
|
133
|
+
const current = prev.then(fn, fn); // run `fn` whether prev resolved or rejected
|
|
134
|
+
dirLocks.set(dir, current);
|
|
135
|
+
try {
|
|
136
|
+
return await current;
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
// Clean up the map entry only if we're still the tail of the chain.
|
|
140
|
+
// Otherwise a later caller's Promise is in flight and owns the slot.
|
|
141
|
+
if (dirLocks.get(dir) === current)
|
|
142
|
+
dirLocks.delete(dir);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
125
145
|
/**
|
|
126
146
|
* Walk a directory tree collecting every sub-directory's sidecar state.
|
|
127
147
|
* Bounded-parallel recursion — flat Promise.all over 10k dirs would blow
|
|
@@ -164,8 +184,6 @@ export async function listSidecars(storage, rootDir) {
|
|
|
164
184
|
*/
|
|
165
185
|
function parseSidecarEntries(entries) {
|
|
166
186
|
let hash = null;
|
|
167
|
-
const uses = [];
|
|
168
|
-
let template = null;
|
|
169
187
|
let pub = null;
|
|
170
188
|
const localeHashes = new Map();
|
|
171
189
|
const localePubs = new Map();
|
|
@@ -181,16 +199,6 @@ function parseSidecarEntries(entries) {
|
|
|
181
199
|
hash = h;
|
|
182
200
|
continue;
|
|
183
201
|
}
|
|
184
|
-
const u = parseUsesSidecarName(e.name);
|
|
185
|
-
if (u) {
|
|
186
|
-
uses.push(u);
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
const t = parseTemplateSidecarName(e.name);
|
|
190
|
-
if (t) {
|
|
191
|
-
template = t;
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
202
|
const p = parsePubSidecarName(e.name);
|
|
195
203
|
if (p) {
|
|
196
204
|
const loc = parsePubSidecarLocale(e.name);
|
|
@@ -200,10 +208,10 @@ function parseSidecarEntries(entries) {
|
|
|
200
208
|
pub = p;
|
|
201
209
|
}
|
|
202
210
|
}
|
|
203
|
-
const defaultState = hash ? { hash,
|
|
211
|
+
const defaultState = hash ? { hash, pub } : null;
|
|
204
212
|
const locales = new Map();
|
|
205
213
|
for (const [loc, lHash] of localeHashes) {
|
|
206
|
-
locales.set(loc, { hash: lHash,
|
|
214
|
+
locales.set(loc, { hash: lHash, pub: localePubs.get(loc) ?? null });
|
|
207
215
|
}
|
|
208
216
|
return { default: defaultState, locales };
|
|
209
217
|
}
|
package/dist/sidecars.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecars.js","sourceRoot":"","sources":["../src/sidecars.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sidecars.js","sourceRoot":"","sources":["../src/sidecars.ts"],"names":[],"mappings":"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"}
|
package/dist/targets.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI9E;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;IAClC,gEAAgE;IAChE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAA;IACjD,8BAA8B;IAC9B,IAAI,IAAI,MAAM,EAAE,CAAA;IAChB;;;;OAIG;IACH,eAAe,IAAI,MAAM,CAAA;CAC1B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,IAAI,EAAE,MAAM;CAIzB;AACD,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GACpC,cAAc,CAsBhB;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,MAAM,EAAE,CAInF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG5E;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CAqE1B;AAUD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EACrC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CA6BvC"}
|
package/dist/targets.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { resolve, join } from 'node:path';
|
|
2
|
-
import { execSync } from 'node:child_process';
|
|
3
2
|
import { isEditable } from './types.js';
|
|
4
3
|
import { createFilesystemProvider } from './providers/filesystem.js';
|
|
5
4
|
export class UnknownTargetError extends Error {
|
|
@@ -103,7 +102,8 @@ export async function createStorageProvider(config, siteDir, targetName) {
|
|
|
103
102
|
});
|
|
104
103
|
}
|
|
105
104
|
catch {
|
|
106
|
-
throw new Error('S3 storage requires @aws-sdk/client-s3
|
|
105
|
+
throw new Error('S3 storage requires @aws-sdk/client-s3 and @aws-sdk/lib-storage. ' +
|
|
106
|
+
'Install them: npm install @aws-sdk/client-s3 @aws-sdk/lib-storage');
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
case 'r2': {
|
|
@@ -113,47 +113,25 @@ export async function createStorageProvider(config, siteDir, targetName) {
|
|
|
113
113
|
throw new Error('R2 storage requires "bucket"');
|
|
114
114
|
const accessKeyId = resolveEnvVars(config.accessKeyId);
|
|
115
115
|
const secretAccessKey = resolveEnvVars(config.secretAccessKey);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return createS3Provider({
|
|
121
|
-
endpoint: `https://${config.accountId}.r2.cloudflarestorage.com`,
|
|
122
|
-
bucket: config.bucket,
|
|
123
|
-
accessKeyId,
|
|
124
|
-
secretAccessKey,
|
|
125
|
-
region: config.region,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
throw new Error('R2 with S3 credentials requires @aws-sdk/client-s3. Install it: npm install @aws-sdk/client-s3');
|
|
130
|
-
}
|
|
116
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
117
|
+
throw new Error('R2 storage requires accessKeyId and secretAccessKey.\n' +
|
|
118
|
+
' Set R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY environment variables, or\n' +
|
|
119
|
+
' create an R2 API token at https://dash.cloudflare.com/<account>/r2/api-tokens');
|
|
131
120
|
}
|
|
132
|
-
// Fall back to Cloudflare REST API using wrangler auth
|
|
133
|
-
let apiToken;
|
|
134
121
|
try {
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
122
|
+
const { createS3Provider } = await import('./providers/s3.js');
|
|
123
|
+
return createS3Provider({
|
|
124
|
+
endpoint: `https://${config.accountId}.r2.cloudflarestorage.com`,
|
|
125
|
+
bucket: config.bucket,
|
|
126
|
+
accessKeyId,
|
|
127
|
+
secretAccessKey,
|
|
128
|
+
region: config.region,
|
|
139
129
|
});
|
|
140
|
-
// wrangler prints a banner before the token — extract the last non-empty line
|
|
141
|
-
apiToken =
|
|
142
|
-
output
|
|
143
|
-
.split('\n')
|
|
144
|
-
.map(l => l.trim())
|
|
145
|
-
.filter(l => l && !l.includes('wrangler') && !l.includes('───'))
|
|
146
|
-
.pop() ?? '';
|
|
147
130
|
}
|
|
148
131
|
catch {
|
|
149
|
-
throw new Error('R2 storage
|
|
150
|
-
'
|
|
151
|
-
' or run "npx wrangler login" to authenticate with Cloudflare.');
|
|
132
|
+
throw new Error('R2 storage requires @aws-sdk/client-s3 and @aws-sdk/lib-storage. ' +
|
|
133
|
+
'Install them: npm install @aws-sdk/client-s3 @aws-sdk/lib-storage');
|
|
152
134
|
}
|
|
153
|
-
if (!apiToken)
|
|
154
|
-
throw new Error('R2 storage: wrangler returned empty token. Run "npx wrangler login" to authenticate.');
|
|
155
|
-
const { createR2RestProvider } = await import('./providers/r2.js');
|
|
156
|
-
return createR2RestProvider({ accountId: config.accountId, bucket: config.bucket, apiToken });
|
|
157
135
|
}
|
|
158
136
|
default:
|
|
159
137
|
throw new Error(`Unknown storage type: ${config.type}`);
|
package/dist/targets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"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"}
|
package/dist/themes.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme resolution — single source of truth for theme configuration.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `locale.ts` for the theme dimension. Themes are an asset-override
|
|
5
|
+
* axis introduced in v1: each asset can carry per-theme byte overrides
|
|
6
|
+
* (typically `light` / `dark`) that the resolver picks per render context.
|
|
7
|
+
*
|
|
8
|
+
* Single responsibility: given a `SiteManifest`, return the resolved theme
|
|
9
|
+
* settings (supported list, default). Validation rules. Nothing about
|
|
10
|
+
* assets, manifests, or rendering — those are the resolver's concern.
|
|
11
|
+
*
|
|
12
|
+
* # Why a separate module from locale.ts
|
|
13
|
+
*
|
|
14
|
+
* Themes and locales are peer dimensions in the abstract model but they
|
|
15
|
+
* have different ergonomics: locale codes are open (BCP 47, thousands of
|
|
16
|
+
* valid values), theme codes are closed by convention (typically two or
|
|
17
|
+
* three names per site). The resolution logic is similar enough to feel
|
|
18
|
+
* shared and different enough to warrant separate modules — extracting
|
|
19
|
+
* a shared "dimension config" abstraction would couple them in ways that
|
|
20
|
+
* hurt clarity.
|
|
21
|
+
*/
|
|
22
|
+
import type { SiteManifest, ThemesConfig } from './types.js';
|
|
23
|
+
/** Resolved theme settings for a site. */
|
|
24
|
+
export interface ResolvedThemes {
|
|
25
|
+
/** All supported theme names, normalized to lowercase. */
|
|
26
|
+
supported: string[];
|
|
27
|
+
/** The default theme name. */
|
|
28
|
+
default: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validate a theme name as it would appear in storage / filenames.
|
|
32
|
+
*
|
|
33
|
+
* Strict on input — does NOT normalize. Mixed case, leading dots, etc.
|
|
34
|
+
* fail. Callers that want lenient parsing should `normalizeTheme` first
|
|
35
|
+
* and then check.
|
|
36
|
+
*
|
|
37
|
+
* Rejects:
|
|
38
|
+
* - empty / whitespace
|
|
39
|
+
* - dots (would collide with filename suffix scheme)
|
|
40
|
+
* - any uppercase character (filenames must be normalized to lowercase
|
|
41
|
+
* before reaching storage; uppercase reaching this validator is a bug)
|
|
42
|
+
* - BCP 47 locale codes (would be ambiguous in filename composition —
|
|
43
|
+
* `hero.asset.en.json` could be locale `en` or theme `en`)
|
|
44
|
+
*/
|
|
45
|
+
export declare function isValidTheme(theme: string): boolean;
|
|
46
|
+
/** Normalize a theme name to lowercase for filenames. */
|
|
47
|
+
export declare function normalizeTheme(theme: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve theme settings from a site manifest. Throws when the config is
|
|
50
|
+
* present but invalid (collision with locale codes, malformed names) so
|
|
51
|
+
* misconfiguration surfaces at boot rather than silently at render time.
|
|
52
|
+
*
|
|
53
|
+
* Returns `null` when `themes` is unset — that's the "no theme dimension
|
|
54
|
+
* for this site" signal. Asset overrides keyed by theme are rejected
|
|
55
|
+
* downstream when this is null.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveSiteThemes(site: SiteManifest): ResolvedThemes | null;
|
|
58
|
+
/**
|
|
59
|
+
* Subset themes to a config — used when a target overrides the site's theme
|
|
60
|
+
* set. Falls back to the site's resolved themes when the target doesn't
|
|
61
|
+
* narrow.
|
|
62
|
+
*
|
|
63
|
+
* v1 doesn't expose target-level theme override (assets are global to the
|
|
64
|
+
* site's theme set). The function is here for symmetry with locale
|
|
65
|
+
* resolution and future-proofs the API when targets may want to ship a
|
|
66
|
+
* subset (e.g. a target that only serves light mode).
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveTargetThemes(siteThemes: ResolvedThemes | null, override?: ThemesConfig): ResolvedThemes | null;
|
|
69
|
+
//# sourceMappingURL=themes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../src/themes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG5D,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAA;CAChB;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAMnD;AAED,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,IAAI,CA8B3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,cAAc,GAAG,IAAI,CAGrH"}
|
package/dist/themes.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { isValidLocale } from './locale.js';
|
|
2
|
+
/**
|
|
3
|
+
* Theme name pattern: lowercase ASCII letters, digits, hyphens, underscores.
|
|
4
|
+
* No dots (collide with filename composition), no whitespace, non-empty.
|
|
5
|
+
*/
|
|
6
|
+
const THEME_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
7
|
+
/**
|
|
8
|
+
* Validate a theme name as it would appear in storage / filenames.
|
|
9
|
+
*
|
|
10
|
+
* Strict on input — does NOT normalize. Mixed case, leading dots, etc.
|
|
11
|
+
* fail. Callers that want lenient parsing should `normalizeTheme` first
|
|
12
|
+
* and then check.
|
|
13
|
+
*
|
|
14
|
+
* Rejects:
|
|
15
|
+
* - empty / whitespace
|
|
16
|
+
* - dots (would collide with filename suffix scheme)
|
|
17
|
+
* - any uppercase character (filenames must be normalized to lowercase
|
|
18
|
+
* before reaching storage; uppercase reaching this validator is a bug)
|
|
19
|
+
* - BCP 47 locale codes (would be ambiguous in filename composition —
|
|
20
|
+
* `hero.asset.en.json` could be locale `en` or theme `en`)
|
|
21
|
+
*/
|
|
22
|
+
export function isValidTheme(theme) {
|
|
23
|
+
if (!THEME_PATTERN.test(theme))
|
|
24
|
+
return false;
|
|
25
|
+
// Theme names must not collide with valid BCP 47 locale codes.
|
|
26
|
+
// `en`, `fr`, `pt-br`, etc. are reserved for the locale dimension.
|
|
27
|
+
if (isValidLocale(theme))
|
|
28
|
+
return false;
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
/** Normalize a theme name to lowercase for filenames. */
|
|
32
|
+
export function normalizeTheme(theme) {
|
|
33
|
+
return theme.toLowerCase();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve theme settings from a site manifest. Throws when the config is
|
|
37
|
+
* present but invalid (collision with locale codes, malformed names) so
|
|
38
|
+
* misconfiguration surfaces at boot rather than silently at render time.
|
|
39
|
+
*
|
|
40
|
+
* Returns `null` when `themes` is unset — that's the "no theme dimension
|
|
41
|
+
* for this site" signal. Asset overrides keyed by theme are rejected
|
|
42
|
+
* downstream when this is null.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveSiteThemes(site) {
|
|
45
|
+
const config = site.themes;
|
|
46
|
+
if (!config)
|
|
47
|
+
return null;
|
|
48
|
+
if (!Array.isArray(config.supported) || config.supported.length === 0) {
|
|
49
|
+
throw new Error('themes.supported must be a non-empty array of theme names');
|
|
50
|
+
}
|
|
51
|
+
const supported = [];
|
|
52
|
+
for (const raw of config.supported) {
|
|
53
|
+
const norm = normalizeTheme(raw);
|
|
54
|
+
if (!isValidTheme(norm)) {
|
|
55
|
+
throw new Error(`Invalid theme name "${raw}". Must be lowercase ASCII (a-z, 0-9, -, _), ` +
|
|
56
|
+
`start with a letter, and not collide with BCP 47 locale codes.`);
|
|
57
|
+
}
|
|
58
|
+
if (supported.includes(norm)) {
|
|
59
|
+
throw new Error(`Duplicate theme name "${norm}" in themes.supported`);
|
|
60
|
+
}
|
|
61
|
+
supported.push(norm);
|
|
62
|
+
}
|
|
63
|
+
const defaultRaw = config.default ?? supported[0];
|
|
64
|
+
const defaultTheme = normalizeTheme(defaultRaw);
|
|
65
|
+
if (!supported.includes(defaultTheme)) {
|
|
66
|
+
throw new Error(`themes.default "${config.default}" is not in themes.supported [${supported.join(', ')}]`);
|
|
67
|
+
}
|
|
68
|
+
return { supported, default: defaultTheme };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Subset themes to a config — used when a target overrides the site's theme
|
|
72
|
+
* set. Falls back to the site's resolved themes when the target doesn't
|
|
73
|
+
* narrow.
|
|
74
|
+
*
|
|
75
|
+
* v1 doesn't expose target-level theme override (assets are global to the
|
|
76
|
+
* site's theme set). The function is here for symmetry with locale
|
|
77
|
+
* resolution and future-proofs the API when targets may want to ship a
|
|
78
|
+
* subset (e.g. a target that only serves light mode).
|
|
79
|
+
*/
|
|
80
|
+
export function resolveTargetThemes(siteThemes, override) {
|
|
81
|
+
if (override)
|
|
82
|
+
return resolveSiteThemes({ name: '', themes: override });
|
|
83
|
+
return siteThemes;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=themes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themes.js","sourceRoot":"","sources":["../src/themes.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAU3C;;;GAGG;AACH,MAAM,aAAa,GAAG,oBAAoB,CAAA;AAE1C;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC5C,+DAA+D;IAC/D,mEAAmE;IACnE,IAAI,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,OAAO,IAAI,CAAA;AACb,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,KAAK,CAAC,WAAW,EAAE,CAAA;AAC5B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAkB;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC1B,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAExB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;IAC9E,CAAC;IAED,MAAM,SAAS,GAAa,EAAE,CAAA;IAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,uBAAuB,GAAG,+CAA+C;gBACvE,gEAAgE,CACnE,CAAA;QACH,CAAC;QACD,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,uBAAuB,CAAC,CAAA;QACvE,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACtB,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC,CAAE,CAAA;IAClD,MAAM,YAAY,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;IAC/C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,OAAO,iCAAiC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC5G,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,CAAA;AAC7C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAiC,EAAE,QAAuB;IAC5F,IAAI,QAAQ;QAAE,OAAO,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAkB,CAAC,CAAA;IACtF,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TransformAdapter — delivery strategy for asset bytes.
|
|
3
|
+
*
|
|
4
|
+
* Per Q8 lock, an adapter owns three coupled concerns:
|
|
5
|
+
* 1. URL composition for the primary asset URL and srcset (where
|
|
6
|
+
* different from the origin's pre-generated ladder)
|
|
7
|
+
* 2. Cache policy for the URLs it produces (since cache semantics
|
|
8
|
+
* depend on whether bytes are origin-served vs CDN-served)
|
|
9
|
+
* 3. Optional server-side route mounting for adapters that mediate
|
|
10
|
+
* delivery (e.g. proxy adapters that route through our origin)
|
|
11
|
+
*
|
|
12
|
+
* # Why all three on one interface
|
|
13
|
+
*
|
|
14
|
+
* URL + cache + delivery are coupled. The hardcoded
|
|
15
|
+
* `Cache-Control: immutable` in the serve-route was correct for the
|
|
16
|
+
* sharp adapter but wrong for any adapter that signs URLs with a
|
|
17
|
+
* short-TTL HMAC (future imgproxy) or routes through a CDN with its
|
|
18
|
+
* own cache (cloudflare). Co-locating the policy with the URL builder
|
|
19
|
+
* keeps the contract honest.
|
|
20
|
+
*
|
|
21
|
+
* # Why mountRoutes is optional
|
|
22
|
+
*
|
|
23
|
+
* Origin-passthrough (sharp) and CDN adapters (cloudflare) don't need
|
|
24
|
+
* server-side routes — the existing `assets/serve-route.ts` handles
|
|
25
|
+
* origin bytes; the CDN handles its own. Future proxy adapters
|
|
26
|
+
* (imgproxy, signed-URL workers) would implement `mountRoutes` to
|
|
27
|
+
* add their own handlers.
|
|
28
|
+
*
|
|
29
|
+
* # Why required (not optional) in the resolver context
|
|
30
|
+
*
|
|
31
|
+
* Adapter is always present. Resolver code paths don't branch on
|
|
32
|
+
* "does an adapter exist" — the factory at boot constructs one
|
|
33
|
+
* (defaulting to `sharpAdapter`), and every URL goes through it.
|
|
34
|
+
* Eliminates the conditional URL construction throughout the resolver.
|
|
35
|
+
*/
|
|
36
|
+
import type { Hono } from 'hono';
|
|
37
|
+
import type { Selector } from '../schema/dimensions.js';
|
|
38
|
+
import type { AssetVariant } from '../schema/types.js';
|
|
39
|
+
/**
|
|
40
|
+
* Input for adapter URL builders. Carries everything an adapter could
|
|
41
|
+
* possibly need; concrete adapters pick what they use. The sharp
|
|
42
|
+
* adapter reads `variants` for srcset; the cloudflare adapter reads
|
|
43
|
+
* `width`/`height` to skip upscaling but ignores `variants`.
|
|
44
|
+
*/
|
|
45
|
+
export interface AssetUrlInput {
|
|
46
|
+
/** Asset name (the canonical identifier). */
|
|
47
|
+
name: string;
|
|
48
|
+
/** 8-char SHA-256 prefix of the bytes. For locale-bytes overrides this is the override's hash. */
|
|
49
|
+
hash: string;
|
|
50
|
+
/** File extension without the dot (e.g., 'jpg'). */
|
|
51
|
+
ext: string;
|
|
52
|
+
/** Selector identifying which override these bytes are (null = default). */
|
|
53
|
+
selector: Selector | null;
|
|
54
|
+
/** Optional site URL — absolute prefix for cross-origin delivery. */
|
|
55
|
+
siteUrl?: string;
|
|
56
|
+
/** Pre-generated variants from the manifest. Adapters that ignore this (cloudflare) don't read it. */
|
|
57
|
+
variants: readonly AssetVariant[];
|
|
58
|
+
/** Source width in pixels. Null for non-images. */
|
|
59
|
+
width: number | null;
|
|
60
|
+
/** Source height in pixels. Null for non-images. */
|
|
61
|
+
height: number | null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Cache headers an adapter dictates for the URLs it produced. The
|
|
65
|
+
* asset-serve route applies these when serving origin bytes; CDN
|
|
66
|
+
* adapters return the same policy for documentation (the CDN owns
|
|
67
|
+
* actual caching, but the origin response still carries headers
|
|
68
|
+
* because the CDN re-emits or honors them depending on config).
|
|
69
|
+
*/
|
|
70
|
+
export interface CachePolicy {
|
|
71
|
+
/** `Cache-Control` header value. */
|
|
72
|
+
cacheControl: string;
|
|
73
|
+
/** Optional `Vary` header (theme/locale-aware delivery, format negotiation). */
|
|
74
|
+
vary?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Delivery strategy for asset bytes. Per-target — wired into the
|
|
78
|
+
* resolver context at boot via the `transforms` factory.
|
|
79
|
+
*/
|
|
80
|
+
export interface TransformAdapter {
|
|
81
|
+
/** Stable identifier — used in telemetry, logs, and adapter selection. */
|
|
82
|
+
readonly name: string;
|
|
83
|
+
/**
|
|
84
|
+
* Build the primary URL for an asset's bytes-of-record. This is the
|
|
85
|
+
* URL that goes into `<img src>`, `<a href>`, or `@font-face src`.
|
|
86
|
+
*/
|
|
87
|
+
primaryUrl(input: AssetUrlInput): string;
|
|
88
|
+
/**
|
|
89
|
+
* Build a `srcset` string for responsive image delivery, OR return
|
|
90
|
+
* null when responsive delivery isn't supported (non-image assets,
|
|
91
|
+
* or images with no variant ladder).
|
|
92
|
+
*
|
|
93
|
+
* Adapter decides ladder semantics:
|
|
94
|
+
* - sharp adapter reads `input.variants` (pre-generated at upload)
|
|
95
|
+
* - cloudflare adapter generates ladder from a width set the
|
|
96
|
+
* adapter chooses (typically 400/800/1200/1600)
|
|
97
|
+
*/
|
|
98
|
+
srcset(input: AssetUrlInput): string | null;
|
|
99
|
+
/**
|
|
100
|
+
* Cache policy for a URL this adapter produced. Returned headers
|
|
101
|
+
* are applied by whichever serving layer handles the URL — origin
|
|
102
|
+
* route for origin-served adapters, propagated to CDN config for
|
|
103
|
+
* upstream adapters.
|
|
104
|
+
*/
|
|
105
|
+
cachePolicy(input: AssetUrlInput): CachePolicy;
|
|
106
|
+
/**
|
|
107
|
+
* Mount adapter-specific server-side routes. Called once per app
|
|
108
|
+
* construction by the bootstrap. Origin-passthrough adapters
|
|
109
|
+
* (sharp) and pure CDN adapters (cloudflare) leave this undefined;
|
|
110
|
+
* mediating adapters (future imgproxy, signed URL workers)
|
|
111
|
+
* implement it.
|
|
112
|
+
*/
|
|
113
|
+
mountRoutes?(app: Hono): void;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/transforms/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,kGAAkG;IAClG,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAA;IACX,4EAA4E;IAC5E,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sGAAsG;IACtG,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAA;IACjC,mDAAmD;IACnD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,oDAAoD;IACpD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAAA;IAExC;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAAA;IAE3C;;;;;OAKG;IACH,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,WAAW,CAAA;IAE9C;;;;;;OAMG;IACH,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAA;CAC9B"}
|