@blamejs/blamejs-shop 0.0.117 → 0.0.119

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.
Files changed (2) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -8,6 +8,10 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.0.x
10
10
 
11
+ - v0.0.119 (2026-05-24) — **Newsletter handler surfaces `X-Newsletter-Diag` header so the live 500 root cause is visible without wrangler tail.** v0.0.118 added missing-table resilience to the newsletter handler, but every submission still 500s — the underlying D1 error isn't matching the `"no such table" / "no such column"` resilience-trigger regex. Without wrangler tail access during the diagnostic loop, the actual error message stays invisible. This patch adds an `X-Newsletter-Diag: <ErrorClass>: <first 96 chars of message>` response header (redacted through `_redact` so secrets never leak) on the 500 path. The body remains the canonical operator-facing error page; the header surfaces the failing step. Operator probes `curl -sI` and reads the diag value to pinpoint the live root cause (likely a D1 binding shape mismatch / migration gap / module-load issue), then ships a targeted fix in the next patch. The diag header is intentionally short-lived — removable once the cause is identified and permanently fixed. **Added:** *`X-Newsletter-Diag` response header on the 500 path* — `_edgeNewsletter`'s outer catch now sets `X-Newsletter-Diag: <constructor.name>: <message[:96]>` (redacted through the framework's `b.redact.redact` pipeline). The body still renders the canonical 500 page; the header gives the operator a diagnostic surface without needing wrangler tail. Removable in a follow-up once the live root cause is identified and the underlying fix lands.
12
+
13
+ - v0.0.118 (2026-05-24) — **Newsletter signup — missing-table resilience + per-step error attribution.** POST `/newsletter` was returning a generic 500 for every submission — valid email, invalid email, empty form, every shape. The outer try/catch was swallowing whatever the D1 INSERT threw and falling into `renderInternalError`. Sub-step attribution wasn't logged, so wrangler tail saw `edge POST /newsletter failed:` with a stack but the visitor saw the 500 page. The most likely root cause: migration `0010_newsletter_signups.sql` hasn't been applied to live D1 yet, so the INSERT throws `no such table: newsletter_signups`. This patch wraps the INSERT in its own try/catch, logs the underlying D1 message via `console.error`, and returns a clean 503 `"Newsletter signup temporarily unavailable"` with `Retry-After: 60` when the table (or a column) is missing. Unknown D1 failures (constraint conflicts, network errors) still escalate to the outer catch and the existing 500 page. The visitor gets a clear retry signal instead of a generic error; the operator sees a specific signal that migrations need to be applied. **Fixed:** *Newsletter handler degrades gracefully when D1 schema is missing* — `worker/index.js#_edgeNewsletter` wraps the INSERT in a per-step try/catch. On `"no such table"` / `"no such column"` errors, returns `503 Newsletter signup temporarily unavailable.` with `Retry-After: 60` + the framework's security headers. Other D1 failures (constraint conflicts, network errors, etc.) re-throw to the outer catch — the existing 500 page renders, the underlying message lands in `console.error` → wrangler tail / Logpush. Mirrors the missing-table-resilience pattern shipped for blog queries in v0.0.109.
14
+
11
15
  - v0.0.117 (2026-05-24) — **Fix Add to Cart — `container.fetch` was auto-following 303 redirects and dropping `Set-Cookie`.** Add to Cart appeared to do nothing for visitors: the form POST returned 200 with the empty-cart page instead of the expected 303 + Set-Cookie + Location: /cart. Root cause: `_forwardToContainer` constructed the container-side Request with the Workers default `redirect: "follow"`, which auto-follows the storefront's 303 inside the Worker. The auto-followed GET /cart strips the `Set-Cookie: shop_sid=...` header from the intermediate 303 response — so the session cookie never reaches the visitor's browser, the subsequent (visible to the visitor) /cart GET arrives without the session, and the cart-line lookup keys on a fresh empty cart. End result for the visitor: the line WAS persisted to the container's session store, but every subsequent page load creates a new sessionless cart and shows it empty. Fix: `_attemptRequest` constructs the container-side Request with `redirect: "manual"` so the 303 + Set-Cookie chain passes through verbatim to the visitor's browser, which carries the cookie forward through the natural redirect navigation. Same bug affected `/cart/lines/<id>/update`, `/cart/lines/<id>/remove`, `/newsletter`, and any other server-side 303-with-cookie pattern routed through the container — all of those are fixed by the single line change. **Fixed:** *Cart-mutation 303 redirects preserve their `Set-Cookie` end-to-end* — `worker/index.js#_forwardToContainer` now constructs the container-side Request with `redirect: "manual"`. The storefront's POST handlers (`cart/lines`, `cart/lines/<id>/update`, `cart/lines/<id>/remove`, `newsletter`, future checkout submits) all reply with 303 + `Location` + `Set-Cookie: shop_sid=...` on the same response. Manual redirect handling passes that triple verbatim to the visitor's browser, which carries the cookie through the redirect navigation. Add to Cart now persists across the redirect; subsequent /cart loads show the line; the visitor sees what they expected to see when they clicked the button.
12
16
 
13
17
  - v0.0.116 (2026-05-24) — **Top-level Worker exception catcher — convert Cloudflare 1101 to a clean 503 warming page.** An uncaught exception in the Worker's fetch handler used to propagate to the Cloudflare runtime, which served the generic `Error 1101 — Worker threw exception` page (cf-branded interstitial referencing wrangler tail). Visitors saw a Cloudflare error instead of the framework's render. Every fetch invocation now runs inside `_withTopLevelCatch`: catches every escape, logs to `console.error` (so wrangler tail / Logpush still see the underlying cause), and serves the existing 503 warming-up page with the framework's security headers + a `Retry-After: 10` hint. Cold-start blips during deploys, sporadic D1 / R2 binding hiccups, and any other exception that would have surfaced as 1101 now serve a branded, refresh-aware page that respects the operator's CSP / Permissions-Policy / HSTS posture. **Added:** *Top-level Worker exception catcher (`_withTopLevelCatch`)* — Wraps every `fetch` invocation. On exception: logs the stack via `console.error` (Worker substrate's observability sink — surfaces in `wrangler tail` + Logpush), then returns 503 with the existing `_warmingHtml(request.url, 8)` page + the framework's full security-headers set + `Retry-After: 10` + `Cache-Control: no-store`. Cloudflare's generic 1101 page never reaches the visitor; the cf-managed `Please enable cookies` interstitial only fires when CF's edge layer (Bot Fight Mode / challenge platform) intervenes BEFORE the Worker runs, not from Worker-thrown exceptions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/blamejs-shop",
3
- "version": "0.0.117",
3
+ "version": "0.0.119",
4
4
  "description": "Open-source framework built on blamejs. Vendored stack, zero npm runtime deps, PQC-first crypto, security-on by default.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {