@tokenoftrust/storefront-runner 3.1.2 → 3.2.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.
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* - one per entry of {@link FORBIDDEN_PUBLIC_DIRS}: any file under a directory a media download
|
|
11
11
|
* writes (`public/catalog-images/` is `catalog-images-in-repo`, `public/blog/wp-content/uploads/`
|
|
12
|
-
* is `blog-media-in-repo`). Decided from paths alone, so a caller
|
|
13
|
-
* it. This list is the one source the validators and the reconcile
|
|
14
|
-
* pre-receive size guard names the same directories.
|
|
12
|
+
* is `blog-media-in-repo`), each with its own remedy. Decided from paths alone, so a caller
|
|
13
|
+
* without sizes still refuses it. This list is the one source the validators and the reconcile
|
|
14
|
+
* read; the Gitea pre-receive size guard names the same directories.
|
|
15
15
|
* - `public-binary-oversized` — one raster or media file over {@link PUBLIC_BINARY_LIMITS}
|
|
16
|
-
* `maxFileBytes`.
|
|
16
|
+
* `maxFileBytes`. An image's remedy is {@link IMAGE_ADD_COMMAND}.
|
|
17
17
|
* - `public-tree-over-budget` — the whole `public/` tree over `maxTotalBytes`.
|
|
18
18
|
*
|
|
19
19
|
* The size findings need `bytes`; an entry without it is judged by path only.
|
|
@@ -31,14 +31,24 @@ export const PUBLIC_BINARY_LIMITS = Object.freeze({
|
|
|
31
31
|
maxTotalBytes: 32 * 1024 * 1024,
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
+
/** The kit command that moves downloaded catalog images and blog media back to their source URLs. */
|
|
35
|
+
export const UNHOST_IMAGES_COMMAND = "node agency-kit/tools/import-catalog.mjs --store <checkout> --unhost-images --write";
|
|
36
|
+
|
|
37
|
+
/** The command that puts an image the author holds into the platform pool and prints its `/_a/` URL. */
|
|
38
|
+
export const IMAGE_ADD_COMMAND = "tot image add <file>";
|
|
39
|
+
|
|
34
40
|
/**
|
|
35
41
|
* The directories under `public/` a media download writes. No file under one may be committed.
|
|
42
|
+
* `remedy` is the fix for files of that kind.
|
|
36
43
|
*
|
|
37
|
-
* @type {ReadonlyArray<Readonly<{ dir: string, code: string, noun: string }>>}
|
|
44
|
+
* @type {ReadonlyArray<Readonly<{ dir: string, code: string, noun: string, remedy: string }>>}
|
|
38
45
|
*/
|
|
39
46
|
export const FORBIDDEN_PUBLIC_DIRS = Object.freeze([
|
|
40
|
-
Object.freeze({ dir: "catalog-images/", code: "catalog-images-in-repo", noun: "catalog image" }),
|
|
41
|
-
Object.freeze({
|
|
47
|
+
Object.freeze({ dir: "catalog-images/", code: "catalog-images-in-repo", noun: "catalog image", remedy: UNHOST_IMAGES_COMMAND }),
|
|
48
|
+
Object.freeze({
|
|
49
|
+
dir: "blog/wp-content/uploads/", code: "blog-media-in-repo", noun: "blog media",
|
|
50
|
+
remedy: `a new post image: ${IMAGE_ADD_COMMAND}, then reference the /_a/ URL it prints; media a migration downloaded: ${UNHOST_IMAGES_COMMAND}`,
|
|
51
|
+
}),
|
|
42
52
|
]);
|
|
43
53
|
|
|
44
54
|
/** The finding codes decided from paths alone. */
|
|
@@ -49,11 +59,11 @@ export function isForbiddenPublicPath(rel) {
|
|
|
49
59
|
return FORBIDDEN_PUBLIC_DIRS.some((d) => rel.startsWith(d.dir));
|
|
50
60
|
}
|
|
51
61
|
|
|
52
|
-
/** The kit command that moves downloaded catalog images and blog media back to their source URLs. */
|
|
53
|
-
export const UNHOST_IMAGES_COMMAND = "node agency-kit/tools/import-catalog.mjs --store <checkout> --unhost-images --write";
|
|
54
|
-
|
|
55
62
|
const RASTER_OR_MEDIA = /\.(?:jpe?g|png|gif|webp|avif|bmp|tiff?|heic|heif|ico|jxl|mp4|m4v|mov|webm|mkv|avi|mpe?g|mp3|wav|ogg|oga|m4a|aac|flac|opus)$/i;
|
|
56
63
|
|
|
64
|
+
/** The formats {@link IMAGE_ADD_COMMAND} accepts. */
|
|
65
|
+
const UPLOADABLE_IMAGE = /\.(?:jpe?g|png|gif|webp|avif)$/i;
|
|
66
|
+
|
|
57
67
|
const mb = (bytes) => `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
58
68
|
|
|
59
69
|
/**
|
|
@@ -66,7 +76,7 @@ export function publicBinaryFindings(entries, limits = {}) {
|
|
|
66
76
|
const maxFileBytes = limits.maxFileBytes ?? PUBLIC_BINARY_LIMITS.maxFileBytes;
|
|
67
77
|
const maxTotalBytes = limits.maxTotalBytes ?? PUBLIC_BINARY_LIMITS.maxTotalBytes;
|
|
68
78
|
const findings = [];
|
|
69
|
-
for (const { dir, code, noun } of FORBIDDEN_PUBLIC_DIRS) {
|
|
79
|
+
for (const { dir, code, noun, remedy } of FORBIDDEN_PUBLIC_DIRS) {
|
|
70
80
|
const files = entries.filter((e) => e.rel.startsWith(dir));
|
|
71
81
|
if (files.length === 0) continue;
|
|
72
82
|
const bytes = files.reduce((n, e) => n + (e.bytes ?? 0), 0);
|
|
@@ -74,8 +84,8 @@ export function publicBinaryFindings(entries, limits = {}) {
|
|
|
74
84
|
code,
|
|
75
85
|
path: `public/${dir}`,
|
|
76
86
|
message: `${files.length} ${noun} file(s)${bytes ? ` (${mb(bytes)})` : ""} are committed to the store repo; ` +
|
|
77
|
-
"images belong in the platform pool, not the repo
|
|
78
|
-
remedy
|
|
87
|
+
"images belong in the platform pool, not the repo",
|
|
88
|
+
remedy,
|
|
79
89
|
});
|
|
80
90
|
}
|
|
81
91
|
for (const e of entries) {
|
|
@@ -86,7 +96,9 @@ export function publicBinaryFindings(entries, limits = {}) {
|
|
|
86
96
|
path: `public/${e.rel}`,
|
|
87
97
|
message: `${mb(e.bytes)} raster/media file exceeds the ${mb(maxFileBytes)} per-file limit for the store repo; ` +
|
|
88
98
|
"images and media belong in the platform pool",
|
|
89
|
-
remedy:
|
|
99
|
+
remedy: UPLOADABLE_IMAGE.test(e.rel)
|
|
100
|
+
? `${IMAGE_ADD_COMMAND}, then reference the /_a/ URL it prints instead of the file`
|
|
101
|
+
: "reference the file by its source URL, or compress it under the limit",
|
|
90
102
|
});
|
|
91
103
|
}
|
|
92
104
|
}
|
|
@@ -98,7 +110,8 @@ export function publicBinaryFindings(entries, limits = {}) {
|
|
|
98
110
|
path: "public/",
|
|
99
111
|
message: `public/ holds ${mb(total)} across ${entries.length} file(s), over the ${mb(maxTotalBytes)} store-repo budget; ` +
|
|
100
112
|
"images and media belong in the platform pool",
|
|
101
|
-
remedy:
|
|
113
|
+
remedy: `upload images with ${IMAGE_ADD_COMMAND} and reference the /_a/ URLs it prints; ` +
|
|
114
|
+
"reference other large assets by their source URL",
|
|
102
115
|
});
|
|
103
116
|
}
|
|
104
117
|
}
|
|
@@ -44,7 +44,7 @@ export type ManifestEntry = {
|
|
|
44
44
|
address: string;
|
|
45
45
|
byteLength: number;
|
|
46
46
|
mediaType: string;
|
|
47
|
-
provenance?: { kind: "local" | "remote"; locator: string };
|
|
47
|
+
provenance?: { kind: "local" | "remote" | "upload"; locator: string };
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
function objectKey(tenantId: string, address: string): string {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
|
|
6
6
|
"packageManager": "pnpm@11.9.0",
|
|
@@ -28,7 +28,7 @@ export type CaptureRewrite = {
|
|
|
28
28
|
/** A sealed capture-manifest entry, as `original-image-capture.ts` writes it. */
|
|
29
29
|
export interface CapturedManifestEntry {
|
|
30
30
|
/** Remote `locator` is query-stripped for display; remote entries are matched by `locatorDigest`. */
|
|
31
|
-
provenance: { kind: "local" | "remote"; locator: string };
|
|
31
|
+
provenance: { kind: "local" | "remote" | "upload"; locator: string };
|
|
32
32
|
address: string;
|
|
33
33
|
mediaType: string;
|
|
34
34
|
/** Remote entries: digest of the exact fetched locator, query included (`captureLocatorDigest`). */
|
|
@@ -141,7 +141,7 @@ export async function digestCaptureManifest(manifest: {
|
|
|
141
141
|
version: 1;
|
|
142
142
|
revisionId: string;
|
|
143
143
|
entries: ReadonlyArray<{
|
|
144
|
-
provenance: { kind: "local" | "remote"; locator: string };
|
|
144
|
+
provenance: { kind: "local" | "remote" | "upload"; locator: string };
|
|
145
145
|
address: string;
|
|
146
146
|
byteLength: number;
|
|
147
147
|
mediaType: string;
|