@tokenoftrust/storefront-runner 2.2.22 → 2.2.24

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "2.2.22",
3
+ "version": "2.2.24",
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",
@@ -612,6 +612,24 @@ export const TRACKING_ID_STEP_NAME = "assign stable tracking ids";
612
612
  export const CTA_MISSING_ID_FIX =
613
613
  "assign stable tracking ids: GET/POST /api/admin/tracking-writeback proposes a data-tot-el for every element that's missing one, as a reviewable candidate PR (GET first for a dry-run preview) — or run `tot validate` to see the full list before you submit.";
614
614
 
615
+ // `public/**` is git-tracked and wholesale-ingested into R2 on every publish
616
+ // with no content-hash dedup (ingestAssetVersion re-copies every file under a
617
+ // new version key, changed or not) — see docs/versioned-assets-contract.md.
618
+ // A large binary there works, but it compounds: every future publish re-pays
619
+ // its storage cost, and the tenant's Gitea repo keeps that blob permanently.
620
+ // WARN only — never blocks a submit. Idea tracked for a built-in fix (auto
621
+ // relocation to a deduped, content-addressed store): fb-1790956035713-snpovm.
622
+ export const LARGE_PUBLIC_ASSET_BYTES = 100 * 1024;
623
+ export const LARGE_PUBLIC_ASSET_IDEA_ID = "fb-1790956035713-snpovm";
624
+ export const LARGE_PUBLIC_ASSET_FIX =
625
+ `storing it under public/ will work, but every publish re-copies it into R2 and ` +
626
+ `your Gitea repo keeps it forever — on a tenant with many of these, expect ` +
627
+ `slower publishes and slower clones over time. Today, host it on a shared drive ` +
628
+ `you control and tell us the URL so we can pull it in and serve it from R2 directly, ` +
629
+ `rather than committing it to the tenant repo. We're tracking a built-in fix ` +
630
+ `(automatic relocation to deduped storage, idea ${LARGE_PUBLIC_ASSET_IDEA_ID}) — ` +
631
+ `vote for it if you'd like this handled for you sooner.`;
632
+
615
633
  /**
616
634
  * The advisory rules LOUD enough to call out by NAME at `tot validate` / `tot
617
635
  * submit` / `tot preview` — none of them block, but each ships a page that
@@ -641,6 +659,11 @@ export const LOUD_ADVISORY_RULES = [
641
659
  `actionable element with no governed identity (data-tot-el) — needs to ${TRACKING_ID_STEP_NAME}`,
642
660
  `It renders and works fine, but it's invisible to interaction tracking — nothing about it is ever recorded. ${CTA_MISSING_ID_FIX}`,
643
661
  ],
662
+ [
663
+ "large-public-asset",
664
+ `a public/ asset is ${(LARGE_PUBLIC_ASSET_BYTES / 1024).toFixed(0)}KB or larger`,
665
+ LARGE_PUBLIC_ASSET_FIX,
666
+ ],
644
667
  [
645
668
  "cta-id-drift",
646
669
  "a previously-declared data-tot-el changed value",
@@ -1183,6 +1206,9 @@ export function validateTenant(tenantDir, opts = {}) {
1183
1206
  }
1184
1207
  }
1185
1208
 
1209
+ // 6. large public assets — advisory (never blocks); see LARGE_PUBLIC_ASSET_FIX.
1210
+ findings.push(...findLargePublicAssets(publicDir, rel));
1211
+
1186
1212
  const ok = !findings.some((f) => f.level === ERROR);
1187
1213
  return { ok, findings };
1188
1214
  }
@@ -1253,6 +1279,22 @@ function checkAsset(src, file, publicDir, tenantId) {
1253
1279
  return null;
1254
1280
  }
1255
1281
 
1282
+ /**
1283
+ * Every file under `public/**` at or above `LARGE_PUBLIC_ASSET_BYTES`. WARN only —
1284
+ * the file works fine, this is a cost/perf nudge toward the hosted-upload path
1285
+ * (see LARGE_PUBLIC_ASSET_FIX for why: no R2 dedup, permanent Gitea growth).
1286
+ */
1287
+ function findLargePublicAssets(publicDir, rel) {
1288
+ const out = [];
1289
+ for (const p of walk(publicDir, () => true)) {
1290
+ const size = statSync(p).size;
1291
+ if (size >= LARGE_PUBLIC_ASSET_BYTES) {
1292
+ out.push(mk(WARN, "large-public-asset", rel(p), `${(size / 1024).toFixed(0)}KB`));
1293
+ }
1294
+ }
1295
+ return out;
1296
+ }
1297
+
1256
1298
  const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1257
1299
 
1258
1300
  // --- CLI ---------------------------------------------------------------------