@blamejs/blamejs-shop 0.1.12 → 0.1.14

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 (223) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/address-validation.js +8 -12
  3. package/lib/addresses.js +4 -8
  4. package/lib/admin.js +22 -26
  5. package/lib/affiliates.js +18 -24
  6. package/lib/analytics.js +4 -9
  7. package/lib/announcement-bar.js +7 -11
  8. package/lib/api-keys.js +15 -21
  9. package/lib/assembly-instructions.js +9 -13
  10. package/lib/auto-discount.js +3 -7
  11. package/lib/auto-replenish.js +5 -9
  12. package/lib/backorder.js +5 -9
  13. package/lib/banner-ab-tests.js +11 -15
  14. package/lib/barcodes.js +5 -9
  15. package/lib/bin-locations.js +4 -8
  16. package/lib/blog-articles.js +13 -17
  17. package/lib/bundles.js +6 -10
  18. package/lib/business-hours.js +3 -7
  19. package/lib/captcha-gate.js +5 -11
  20. package/lib/carrier-accounts.js +16 -22
  21. package/lib/carrier-rates.js +7 -13
  22. package/lib/cart-abandonment.js +9 -13
  23. package/lib/cart-bulk-ops.js +9 -13
  24. package/lib/cart-recovery.js +9 -13
  25. package/lib/cart.js +7 -11
  26. package/lib/catalog-drafts.js +8 -10
  27. package/lib/catalog-import.js +3 -7
  28. package/lib/catalog.js +13 -20
  29. package/lib/category-navigation.js +3 -7
  30. package/lib/checkout.js +3 -7
  31. package/lib/click-and-collect.js +7 -11
  32. package/lib/clickstream.js +9 -13
  33. package/lib/cms-blocks.js +5 -9
  34. package/lib/code-minter.js +5 -9
  35. package/lib/collections.js +10 -18
  36. package/lib/compliance-export.js +5 -9
  37. package/lib/config.js +3 -7
  38. package/lib/consent-ledger.js +5 -12
  39. package/lib/cookie-consent.js +6 -13
  40. package/lib/cost-layers.js +6 -10
  41. package/lib/coupon-stacking.js +2 -6
  42. package/lib/credit-limits.js +5 -9
  43. package/lib/currency-display.js +6 -10
  44. package/lib/currency-rounding.js +4 -8
  45. package/lib/customer-activity.js +6 -10
  46. package/lib/customer-impersonation.js +11 -18
  47. package/lib/customer-import.js +9 -13
  48. package/lib/customer-merge.js +9 -12
  49. package/lib/customer-notes.js +18 -22
  50. package/lib/customer-portal.js +10 -17
  51. package/lib/customer-risk-profile.js +5 -20
  52. package/lib/customer-roles.js +5 -9
  53. package/lib/customer-segments.js +7 -11
  54. package/lib/customer-surveys.js +10 -14
  55. package/lib/customers.js +10 -14
  56. package/lib/cycle-counting.js +5 -9
  57. package/lib/damage-photos.js +6 -10
  58. package/lib/delivery-estimate.js +8 -15
  59. package/lib/demand-forecast.js +7 -11
  60. package/lib/discount-allocation.js +6 -10
  61. package/lib/discount-analytics.js +8 -12
  62. package/lib/dispute-resolution.js +4 -8
  63. package/lib/dropship-forwarding.js +7 -11
  64. package/lib/dunning.js +6 -10
  65. package/lib/email-ab-tests.js +5 -9
  66. package/lib/email-campaigns.js +8 -12
  67. package/lib/email-engagement-score.js +4 -19
  68. package/lib/email-suppressions.js +7 -14
  69. package/lib/email-templates.js +4 -8
  70. package/lib/email-warmup.js +6 -13
  71. package/lib/email.js +5 -9
  72. package/lib/error-log.js +3 -8
  73. package/lib/event-log.js +7 -11
  74. package/lib/experiments.js +5 -9
  75. package/lib/externaldb-d1.js +2 -6
  76. package/lib/fraud-screen.js +10 -29
  77. package/lib/fulfillment-sla.js +5 -9
  78. package/lib/geolocation.js +2 -6
  79. package/lib/gift-card-ledger.js +6 -10
  80. package/lib/gift-options.js +4 -8
  81. package/lib/gift-registry.js +7 -11
  82. package/lib/giftcards.js +9 -13
  83. package/lib/inventory-alerts.js +4 -8
  84. package/lib/inventory-allocations.js +3 -7
  85. package/lib/inventory-audits.js +5 -9
  86. package/lib/inventory-locations.js +3 -7
  87. package/lib/inventory-receive.js +7 -11
  88. package/lib/inventory-snapshots.js +11 -15
  89. package/lib/inventory-writeoffs.js +6 -10
  90. package/lib/invoice-renderer.js +6 -10
  91. package/lib/knowledge-base.js +14 -18
  92. package/lib/line-gift-wrap.js +8 -15
  93. package/lib/live-chat.js +11 -18
  94. package/lib/locale-router.js +3 -7
  95. package/lib/loyalty-earn-rules.js +4 -8
  96. package/lib/loyalty-redemption.js +5 -9
  97. package/lib/loyalty.js +4 -8
  98. package/lib/mailing-audiences.js +5 -9
  99. package/lib/marketing-budget.js +6 -10
  100. package/lib/metered-usage.js +4 -8
  101. package/lib/newsletter.js +14 -24
  102. package/lib/notifications.js +5 -9
  103. package/lib/operator-activity-feed.js +6 -10
  104. package/lib/operator-approvals.js +4 -8
  105. package/lib/operator-audit-log.js +5 -9
  106. package/lib/operator-help-center.js +13 -17
  107. package/lib/operator-inbox.js +8 -12
  108. package/lib/operator-roles.js +4 -8
  109. package/lib/operator-sessions.js +12 -18
  110. package/lib/order-escalation.js +6 -10
  111. package/lib/order-exchanges.js +4 -8
  112. package/lib/order-export.js +10 -14
  113. package/lib/order-notes.js +14 -20
  114. package/lib/order-ratings.js +5 -9
  115. package/lib/order-tags.js +7 -11
  116. package/lib/order-timeline.js +10 -14
  117. package/lib/order-tracking.js +5 -9
  118. package/lib/order.js +11 -15
  119. package/lib/packing-slips.js +7 -11
  120. package/lib/payment-methods.js +5 -9
  121. package/lib/payment-retries.js +6 -10
  122. package/lib/payment.js +257 -13
  123. package/lib/pick-lists.js +5 -9
  124. package/lib/pixel-events.js +6 -10
  125. package/lib/plan-changes.js +4 -8
  126. package/lib/preorder.js +5 -9
  127. package/lib/price-display.js +7 -11
  128. package/lib/pricing.js +2 -6
  129. package/lib/print-on-demand.js +27 -31
  130. package/lib/print-queue.js +6 -10
  131. package/lib/print-receipts.js +6 -10
  132. package/lib/product-bulk-ops.js +4 -8
  133. package/lib/product-compare.js +7 -11
  134. package/lib/product-import.js +11 -15
  135. package/lib/product-qa.js +10 -17
  136. package/lib/promo-banners.js +13 -17
  137. package/lib/promo-bundles.js +7 -11
  138. package/lib/purchase-orders.js +7 -13
  139. package/lib/push-notifications.js +12 -16
  140. package/lib/pwa-manifest.js +7 -11
  141. package/lib/quantity-discounts.js +8 -12
  142. package/lib/quotes.js +5 -12
  143. package/lib/r2-bridge.js +2 -6
  144. package/lib/recently-viewed.js +6 -14
  145. package/lib/recommendations.js +7 -15
  146. package/lib/referral-leaderboard.js +5 -9
  147. package/lib/referrals.js +8 -12
  148. package/lib/refund-automation.js +5 -10
  149. package/lib/refund-policy.js +4 -9
  150. package/lib/reorder-reminders.js +8 -12
  151. package/lib/reorder-thresholds.js +5 -9
  152. package/lib/return-labels.js +6 -10
  153. package/lib/returns.js +10 -14
  154. package/lib/reviews.js +8 -15
  155. package/lib/robots-config.js +5 -10
  156. package/lib/sales-reports.js +7 -11
  157. package/lib/sales-tax-filings.js +10 -14
  158. package/lib/save-for-later.js +8 -12
  159. package/lib/search-facets.js +15 -22
  160. package/lib/search-ranking.js +4 -8
  161. package/lib/search-suggestions.js +8 -16
  162. package/lib/search-synonyms.js +9 -15
  163. package/lib/seller-signup.js +9 -16
  164. package/lib/shipping-insurance.js +6 -10
  165. package/lib/shipping-labels.js +6 -10
  166. package/lib/shipping-zones.js +2 -9
  167. package/lib/shrinkage-report.js +9 -13
  168. package/lib/sidebar-widgets.js +8 -12
  169. package/lib/site-redirects.js +4 -11
  170. package/lib/sitemap-generator.js +5 -9
  171. package/lib/smart-restocking.js +3 -7
  172. package/lib/sms-dispatcher.js +13 -17
  173. package/lib/split-shipments.js +6 -10
  174. package/lib/stock-alerts.js +10 -19
  175. package/lib/stock-receipts.js +14 -18
  176. package/lib/stock-transfers.js +8 -12
  177. package/lib/store-credit.js +6 -9
  178. package/lib/storefront-dashboards.js +4 -8
  179. package/lib/storefront-forms.js +10 -14
  180. package/lib/storefront-pages.js +5 -9
  181. package/lib/storefront.js +46 -50
  182. package/lib/subscription-analytics.js +14 -22
  183. package/lib/subscription-billing.js +9 -13
  184. package/lib/subscription-controls.js +6 -9
  185. package/lib/subscription-gifts.js +12 -15
  186. package/lib/subscriptions.js +5 -9
  187. package/lib/suggestion-box.js +10 -14
  188. package/lib/support-tickets.js +18 -25
  189. package/lib/tax-cert-renewals.js +7 -10
  190. package/lib/tax-exempt.js +5 -9
  191. package/lib/tax-rates.js +6 -13
  192. package/lib/tax-remittance.js +6 -9
  193. package/lib/tenants.js +6 -13
  194. package/lib/theme-assets.js +5 -10
  195. package/lib/theme.js +3 -7
  196. package/lib/tier-benefits.js +4 -8
  197. package/lib/translations.js +7 -14
  198. package/lib/trust-badges.js +9 -14
  199. package/lib/variants.js +9 -16
  200. package/lib/vendor/MANIFEST.json +2 -2
  201. package/lib/vendor/blamejs/CHANGELOG.md +4 -0
  202. package/lib/vendor/blamejs/README.md +2 -1
  203. package/lib/vendor/blamejs/api-snapshot.json +39 -2
  204. package/lib/vendor/blamejs/index.js +2 -0
  205. package/lib/vendor/blamejs/lib/content-digest.js +189 -0
  206. package/lib/vendor/blamejs/lib/structured-fields.js +362 -0
  207. package/lib/vendor/blamejs/package.json +1 -1
  208. package/lib/vendor/blamejs/release-notes/v0.12.53.json +18 -0
  209. package/lib/vendor/blamejs/release-notes/v0.12.54.json +18 -0
  210. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +11 -1
  211. package/lib/vendor/blamejs/test/layer-0-primitives/content-digest.test.js +87 -0
  212. package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields-codec.test.js +171 -0
  213. package/lib/vendor-invoices.js +8 -15
  214. package/lib/vendors.js +6 -12
  215. package/lib/webhook-receiver.js +13 -24
  216. package/lib/webhook-subscriptions.js +9 -16
  217. package/lib/webhooks.js +17 -20
  218. package/lib/winback-campaigns.js +8 -11
  219. package/lib/wishlist-alerts.js +9 -12
  220. package/lib/wishlist-digest.js +9 -12
  221. package/lib/wishlist-sharing.js +13 -17
  222. package/lib/wishlist.js +7 -14
  223. 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.1.x
10
10
 
11
+ - v0.1.14 (2026-05-25) — **PayPal payment adapter (Orders v2).** `payment.create({ adapter: "paypal", … })` is a new native PayPal adapter alongside the Stripe one — a from-scratch Orders-v2 client over the framework's SSRF-gated HTTP client, with no PayPal SDK dependency. It exchanges an OAuth2 client-credentials token (cached until it nears expiry), creates and captures orders, fetches and refunds them, and verifies inbound webhooks through PayPal's verify-webhook-signature API. This ships the adapter only; wiring it into the checkout flow and a storefront button comes next. Card / Stripe checkout is unchanged. **Added:** *PayPal Orders-v2 adapter* — `payment.create({ adapter: "paypal", clientId, secret, sandbox?, webhookId?, apiBase? })` returns `{ createOrder, captureOrder, getOrder, refund, verifyWebhook }`. `createOrder({ amount_minor, currency, order_id?, return_url?, cancel_url? })` opens a CAPTURE-intent order (amounts converted to PayPal's decimal-string major units, including 0-decimal currencies); `captureOrder(id)` finalizes it; `refund({ capture_id, amount_minor?, currency? })` refunds full or partial; `getOrder(id)` reads status. Every call carries an OAuth2 bearer token exchanged once and cached until ~2 minutes before expiry, and a `PayPal-Request-Id` for idempotency (plus the shared idempotency cache when a `query` handle is wired). `verifyWebhook(headers, rawBody, { webhookId })` confirms an inbound event through PayPal's verify-webhook-signature API and returns `{ ok, event }`. Outbound HTTP goes through `b.httpClient` — no `paypal` npm dependency. Off until the operator supplies credentials; the Stripe adapter and existing checkout are unchanged.
12
+
13
+ - v0.1.13 (2026-05-25) — **Internal: uniform framework access across the library.** An internal consistency refactor with no API or behavior change. Every library module now captures the framework once at the top — straight from the vendored tree (`var b = require("./vendor/blamejs");`) — and uses `b.*` uniformly, replacing a per-module lazy accessor and its scattered call sites. Capturing the framework directly (rather than via the composing entry point) also avoids a circular-load edge case on leaf-first imports. Two source files that embedded a raw NUL byte as a map-key separator now use the `\u0000` escape, so the whole library is plain text. New lint rules lock all of this in place. Public APIs, runtime behavior, and the published surface are unchanged. **Added:** *Lint detectors for accessor uniformity and source hygiene* — Three repository lint rules now prevent drift: one rejects the reintroduction of the per-module lazy framework accessor (capture the framework once at module top); one rejects requiring the composing entry point from a leaf module (require the vendored framework directly — entry-point requires from a leaf create a circular-load hazard); and one rejects raw C0 control bytes in source files (write `\u0000` and friends as escapes so files stay plain text — grep / diff / editors handle them correctly). **Changed:** *Framework handle captured once per module* — Library modules previously reached the vendored framework through a lazy `_b()` accessor invoked at every call site. They now capture it once at module top — `var b = require("./vendor/blamejs");`, the same object the entry point re-exports as `.framework` — and reference `b.*` directly, matching how the edge worker already accesses it. Capturing it directly from the vendored tree (instead of through the composing entry point) keeps leaf-first module imports working — requiring a single module no longer pulls the entry point's whole assembly mid-initialization. No public API or runtime behavior changes.
14
+
11
15
  - v0.1.12 (2026-05-25) — **Card payments now finalize the order — the Stripe webhook is handled end to end.** A confirmed Stripe payment now advances the order from pending to paid. The container now serves the `POST /api/webhooks/stripe` route the edge worker forwards to: it re-verifies the event signature over the exact raw bytes, maps the event to the order's FSM transition, and is idempotent across Stripe's re-deliveries. Previously the edge verified the webhook but nothing consumed it on the container, so a paid PaymentIntent (card, Apple Pay, or Google Pay) left the order stuck in pending — no fulfillment, no paid status. Operators running checkout should upgrade and confirm their Stripe webhook points at `/api/webhooks/stripe`. **Added:** *Raw-body capture for payment webhooks* — A small middleware preserves the exact request bytes for the webhook path before the JSON body-parser runs, so signature verification (which is computed over the raw body) is reliable. It is scoped to the webhook routes and leaves every other request untouched. **Fixed:** *Stripe webhook completes the order* — `POST /api/webhooks/stripe` is now handled on the container: the event signature is re-verified against `STRIPE_WEBHOOK_SECRET` over the raw request body (a tampered or unsigned event is rejected with 400), then `payment_intent.succeeded` / `.canceled` / `charge.refunded` drive the order FSM (`mark_paid` / `cancel` / `refund`). Re-deliveries are idempotent — an event for an order already in the target state is acknowledged with 200 and skipped. A delivery for an unknown PaymentIntent is acknowledged without effect. This closes the gap where a confirmed payment never moved the order out of `pending`.
12
16
 
13
17
  - v0.1.11 (2026-05-25) — **Sign in with Apple.** Customers can now sign in with Apple, alongside passkeys and Google. A “Continue with Apple” button appears on the account login page once the operator wires the Apple credentials; the callback turns the verified Apple identity into a shop session, adopts the guest cart, and claims prior guest orders placed under the same verified email — the same way Google sign-in does. Apple's OAuth client secret is itself an ES256 JWT, which the shop mints from the team's Sign-in-with-Apple key. Sign in with Apple is off until the credentials are set, like every other integration. **Added:** *Sign in with Apple (OIDC)* — `GET /account/login/apple` starts the flow (sealed in-flight state cookie, PKCE, nonce); Apple posts the result back to `POST /account/auth/apple/callback` (response_mode=form_post). The callback verifies the state, exchanges the code, signs the customer in on `(provider=apple, subject)`, adopts the guest cart, and — when Apple reports the email as verified — claims prior guest orders under that email. The display name is captured from Apple's first-authorization `user` field (Apple sends it only once and never in the ID token). The button appears on `/account/login` only when the credentials are configured, and is listed on `/admin/integrations`. · *customers.mintAppleClientSecret* — Mints Apple's required ES256 client-secret JWT from a Services-ID `.p8` key (team id, key id, client id). This is the one signature the protocol forces to be classical ECDSA P-256 rather than the framework's post-quantum default — an external identity provider's wire format, not an application default. The secret is minted at boot with a 150-day life (inside Apple's six-month ceiling) and re-minted on each deploy. **Changed:** *Account login offers Apple when configured* — The login page shows Continue-with-Google and Continue-with-Apple buttons independently, each gated on its own credentials. Set `APPLE_TEAM_ID`, `APPLE_KEY_ID`, `APPLE_CLIENT_ID` (your Services ID), `APPLE_PRIVATE_KEY` (the `.p8` contents), and `SHOP_ORIGIN`, and add `<SHOP_ORIGIN>/account/auth/apple/callback` as a Return URL on the Services ID. Requires an Apple Developer Program membership. See the README “Optional integrations” section.
@@ -63,11 +63,7 @@
63
63
  * @related b.crypto, b.safeJson, b.uuid, shop.addresses, shop.geolocation
64
64
  */
65
65
 
66
- var bShop;
67
- function _b() {
68
- if (!bShop) bShop = require("./index");
69
- return bShop.framework;
70
- }
66
+ var b = require("./vendor/blamejs");
71
67
 
72
68
  // ---- constants ----------------------------------------------------------
73
69
 
@@ -175,7 +171,7 @@ function _normalizedAddress(v) {
175
171
  );
176
172
  }
177
173
  var json;
178
- try { json = _b().safeJson.canonical(v); }
174
+ try { json = b.safeJson.canonical(v); }
179
175
  catch (e) {
180
176
  throw new TypeError(
181
177
  "addressValidation: normalized_address must be JSON-serializable — " + e.message
@@ -210,7 +206,7 @@ function _suggestions(v) {
210
206
  throw new TypeError("addressValidation: suggestions must be an array");
211
207
  }
212
208
  var json;
213
- try { json = _b().safeJson.canonical(v); }
209
+ try { json = b.safeJson.canonical(v); }
214
210
  catch (e) {
215
211
  throw new TypeError(
216
212
  "addressValidation: suggestions must be JSON-serializable — " + e.message
@@ -232,13 +228,13 @@ function _now() { return Date.now(); }
232
228
  function _signatureForInput(input) {
233
229
  _input(input, "input");
234
230
  var canonical;
235
- try { canonical = _b().safeJson.canonical(input); }
231
+ try { canonical = b.safeJson.canonical(input); }
236
232
  catch (e) {
237
233
  throw new TypeError(
238
234
  "addressValidation: input must be JSON-serializable — " + e.message
239
235
  );
240
236
  }
241
- return _b().crypto.namespaceHash(INPUT_NAMESPACE, canonical);
237
+ return b.crypto.namespaceHash(INPUT_NAMESPACE, canonical);
242
238
  }
243
239
 
244
240
  // ---- row -> wire conversions -------------------------------------------
@@ -292,7 +288,7 @@ function create(opts) {
292
288
  opts = opts || {};
293
289
  var query = opts.query;
294
290
  if (!query) {
295
- query = function (sql, params) { return _b().externalDb.query(sql, params); };
291
+ query = function (sql, params) { return b.externalDb.query(sql, params); };
296
292
  }
297
293
 
298
294
  async function _getValidationBySig(sig) {
@@ -354,7 +350,7 @@ function create(opts) {
354
350
  return _rowToValidation(await _getValidationBySig(sig));
355
351
  }
356
352
 
357
- var id = _b().uuid.v7();
353
+ var id = b.uuid.v7();
358
354
  await query(
359
355
  "INSERT INTO address_validations " +
360
356
  "(id, input_signature, normalized_address_json, deliverable, classification, " +
@@ -413,7 +409,7 @@ function create(opts) {
413
409
  return _rowToSuggestion(await _getSuggestionByInput(partial));
414
410
  }
415
411
 
416
- var id = _b().uuid.v7();
412
+ var id = b.uuid.v7();
417
413
  await query(
418
414
  "INSERT INTO address_suggestions_cache " +
419
415
  "(id, partial_input, suggestions_json, expires_at, occurred_at) " +
package/lib/addresses.js CHANGED
@@ -50,11 +50,7 @@
50
50
  * @related customers, checkout
51
51
  */
52
52
 
53
- var bShop;
54
- function _b() {
55
- if (!bShop) bShop = require("./index");
56
- return bShop.framework;
57
- }
53
+ var b = require("./vendor/blamejs");
58
54
 
59
55
  var MAX_LABEL_LEN = 64;
60
56
  var MAX_RECIPIENT_NAME_LEN = 128;
@@ -72,7 +68,7 @@ var CONTROL_BYTE_RE = /[\x00-\x1f\x7f]/;
72
68
  // ---- validators ---------------------------------------------------------
73
69
 
74
70
  function _uuid(s, label) {
75
- try { return _b().guardUuid.sanitize(s, { profile: "strict" }); }
71
+ try { return b.guardUuid.sanitize(s, { profile: "strict" }); }
76
72
  catch (e) { throw new TypeError("addresses: " + label + " — " + (e && e.message || "invalid UUID")); }
77
73
  }
78
74
 
@@ -137,7 +133,7 @@ function create(opts) {
137
133
  opts = opts || {};
138
134
  var query = opts.query;
139
135
  if (!query) {
140
- query = function (sql, params) { return _b().externalDb.query(sql, params); };
136
+ query = function (sql, params) { return b.externalDb.query(sql, params); };
141
137
  }
142
138
 
143
139
  // Clear the named default flag on every non-archived row for this
@@ -180,7 +176,7 @@ function create(opts) {
180
176
  var defShipping = _bool(input.is_default_shipping, "is_default_shipping");
181
177
  var defBilling = _bool(input.is_default_billing, "is_default_billing");
182
178
 
183
- var id = _b().uuid.v7();
179
+ var id = b.uuid.v7();
184
180
  var ts = _now();
185
181
 
186
182
  // Clear sibling defaults FIRST so the promotion lands cleanly.
package/lib/admin.js CHANGED
@@ -32,11 +32,7 @@
32
32
 
33
33
  var pricing = require("./pricing");
34
34
 
35
- var bShop;
36
- function _b() {
37
- if (!bShop) bShop = require("./index");
38
- return bShop.framework;
39
- }
35
+ var b = require("./vendor/blamejs");
40
36
 
41
37
  var AUDIT_NAMESPACE = "shop_admin";
42
38
 
@@ -86,7 +82,7 @@ function _parseLimit(str, label, max, fallback) {
86
82
 
87
83
  function _htmlEscape(s) {
88
84
  if (s == null) return "";
89
- return _b().template.escapeHtml(String(s));
85
+ return b.template.escapeHtml(String(s));
90
86
  }
91
87
 
92
88
  // ---- bearer auth --------------------------------------------------------
@@ -102,7 +98,7 @@ function _readBearer(req) {
102
98
  function _authOk(token, expected) {
103
99
  if (typeof token !== "string" || typeof expected !== "string") return false;
104
100
  if (token.length !== expected.length) return false;
105
- return _b().crypto.timingSafeEqual(token, expected);
101
+ return b.crypto.timingSafeEqual(token, expected);
106
102
  }
107
103
 
108
104
  // ---- admin browser session (sealed cookie) ------------------------------
@@ -118,8 +114,8 @@ var ADMIN_COOKIE_NAME = "shop_admin";
118
114
  var _adminJarMemo = null;
119
115
  function _adminJar() {
120
116
  if (!_adminJarMemo) {
121
- _adminJarMemo = _b().cookies.create({
122
- vault: _b().vault,
117
+ _adminJarMemo = b.cookies.create({
118
+ vault: b.vault,
123
119
  defaults: { httpOnly: true, secure: true, sameSite: "Strict", path: "/admin" },
124
120
  });
125
121
  }
@@ -129,8 +125,8 @@ function _adminJar() {
129
125
  function _setAdminCookie(res) {
130
126
  _adminJar().writeSealed(res, ADMIN_COOKIE_NAME, JSON.stringify({
131
127
  admin: true,
132
- exp: Date.now() + _b().constants.TIME.hours(12),
133
- }), { expires: new Date(Date.now() + _b().constants.TIME.hours(12)) });
128
+ exp: Date.now() + b.constants.TIME.hours(12),
129
+ }), { expires: new Date(Date.now() + b.constants.TIME.hours(12)) });
134
130
  }
135
131
  function _clearAdminCookie(res) {
136
132
  _adminJar().clear(res, ADMIN_COOKIE_NAME);
@@ -153,7 +149,7 @@ function _htmlAuthed(req, expectedToken) {
153
149
  }
154
150
 
155
151
  function _problem(res, status, code, detail) {
156
- return _b().problemDetails.send(res, {
152
+ return b.problemDetails.send(res, {
157
153
  type: "/problems/" + code,
158
154
  title: code.replace(/-/g, " "),
159
155
  status: status,
@@ -193,7 +189,7 @@ function _wrap(handler, opts) {
193
189
  // write path it observes. Equivalent to `try { audit.emit(...)
194
190
  // } catch (_e) {}` but composed via the framework primitive
195
191
  // instead of a local wrapper.
196
- _b().audit.safeEmit({
192
+ b.audit.safeEmit({
197
193
  action: AUDIT_NAMESPACE + "." + opts.audit,
198
194
  outcome: "success",
199
195
  metadata: { id: result.id || null },
@@ -231,7 +227,7 @@ function mount(router, deps) {
231
227
  // into every authed render call as `nav_available`.
232
228
  var navAvailable = { returns: !!returns, reviews: !!reviews };
233
229
 
234
- try { _b().audit.registerNamespace(AUDIT_NAMESPACE); } catch (_e) { /* idempotent */ }
230
+ try { b.audit.registerNamespace(AUDIT_NAMESPACE); } catch (_e) { /* idempotent */ }
235
231
 
236
232
  var W = function (auditAction, h) {
237
233
  return _wrap(h, { expectedToken: expectedToken, audit: auditAction });
@@ -288,7 +284,7 @@ function mount(router, deps) {
288
284
  }
289
285
  throw e;
290
286
  }
291
- _b().audit.safeEmit({ action: AUDIT_NAMESPACE + ".product.create", outcome: "success", metadata: {} });
287
+ b.audit.safeEmit({ action: AUDIT_NAMESPACE + ".product.create", outcome: "success", metadata: {} });
292
288
  _redirect(res, "/admin/products?created=1");
293
289
  },
294
290
  ));
@@ -356,7 +352,7 @@ function mount(router, deps) {
356
352
  // failure must NOT be reported as success — let it surface.
357
353
  try { await op(req.params.id); }
358
354
  catch (e) { if (!(e instanceof TypeError)) throw e; }
359
- _b().audit.safeEmit({ action: AUDIT_NAMESPACE + "." + audit, outcome: "success", metadata: { id: req.params.id } });
355
+ b.audit.safeEmit({ action: AUDIT_NAMESPACE + "." + audit, outcome: "success", metadata: { id: req.params.id } });
360
356
  _redirect(res, "/admin/products");
361
357
  },
362
358
  );
@@ -495,7 +491,7 @@ function mount(router, deps) {
495
491
  // smuggle internal data into the bucket.
496
492
  var fetched;
497
493
  try {
498
- fetched = await _b().httpClient.request({
494
+ fetched = await b.httpClient.request({
499
495
  method: "GET",
500
496
  url: body.source_url,
501
497
  timeoutMs: 20000,
@@ -528,7 +524,7 @@ function mount(router, deps) {
528
524
  // declared content-type so the operator can preview the asset
529
525
  // without a content-disposition round-trip.
530
526
  var ext = _extFromContentType(declared);
531
- var id = _b().uuid.v7();
527
+ var id = b.uuid.v7();
532
528
  var key = "media/" + id + (ext ? "." + ext : "");
533
529
  try {
534
530
  await r2.put(key, buf, body.content_type);
@@ -686,7 +682,7 @@ function mount(router, deps) {
686
682
  }
687
683
  throw e;
688
684
  }
689
- _b().audit.safeEmit({ action: AUDIT_NAMESPACE + ".order.transition", outcome: "success", metadata: { id: id, event: event } });
685
+ b.audit.safeEmit({ action: AUDIT_NAMESPACE + ".order.transition", outcome: "success", metadata: { id: id, event: event } });
690
686
  _redirect(res, "/admin/orders/" + encodeURIComponent(id) + "?moved=1");
691
687
  },
692
688
  ));
@@ -699,7 +695,7 @@ function mount(router, deps) {
699
695
  // "Refund" moves the money first (never a bare state change — that
700
696
  // would mark an order refunded with the customer never paid back).
701
697
  async function _refundOrder(o, body) {
702
- var refundIdempotencyKey = "refund:" + o.id + ":" + (body.idempotency_suffix || _b().uuid.v7());
698
+ var refundIdempotencyKey = "refund:" + o.id + ":" + (body.idempotency_suffix || b.uuid.v7());
703
699
  var refund = await payment.refund({
704
700
  payment_intent: o.payment_intent_id,
705
701
  amount_minor: body.amount_minor || undefined,
@@ -747,7 +743,7 @@ function mount(router, deps) {
747
743
  // transition only runs after a successful refund).
748
744
  return _redirect(res, "/admin/orders/" + encodeURIComponent(id) + "?err=1");
749
745
  }
750
- _b().audit.safeEmit({ action: AUDIT_NAMESPACE + ".order.refund", outcome: "success", metadata: { id: id } });
746
+ b.audit.safeEmit({ action: AUDIT_NAMESPACE + ".order.refund", outcome: "success", metadata: { id: id } });
751
747
  _redirect(res, "/admin/orders/" + encodeURIComponent(id) + "?moved=1");
752
748
  },
753
749
  ));
@@ -816,7 +812,7 @@ function mount(router, deps) {
816
812
  }
817
813
  throw e;
818
814
  }
819
- _b().audit.safeEmit({ action: AUDIT_NAMESPACE + "." + auditEvent, outcome: "success", metadata: { id: id } });
815
+ b.audit.safeEmit({ action: AUDIT_NAMESPACE + "." + auditEvent, outcome: "success", metadata: { id: id } });
820
816
  _redirect(res, "/admin/reviews?moved=1");
821
817
  });
822
818
  }
@@ -957,7 +953,7 @@ function mount(router, deps) {
957
953
  }
958
954
  throw e;
959
955
  }
960
- _b().audit.safeEmit({ action: AUDIT_NAMESPACE + "." + auditEvent, outcome: "success", metadata: { id: id } });
956
+ b.audit.safeEmit({ action: AUDIT_NAMESPACE + "." + auditEvent, outcome: "success", metadata: { id: id } });
961
957
  _redirect(res, "/admin/returns/" + encodeURIComponent(id) + "?moved=1");
962
958
  });
963
959
  }
@@ -1385,11 +1381,11 @@ function mount(router, deps) {
1385
1381
  else if (values.shop_name.length > 80) notice = "Shop name is too long (max 80 characters).";
1386
1382
  else if (values.currency && !/^[A-Z]{3}$/.test(values.currency)) notice = "Currency must be a 3-letter ISO 4217 code (e.g. USD).";
1387
1383
  else if (values.contact_email) {
1388
- var emailReport = _b().guardEmail.validate(values.contact_email, { profile: "strict" });
1384
+ var emailReport = b.guardEmail.validate(values.contact_email, { profile: "strict" });
1389
1385
  if (!emailReport || emailReport.ok === false) notice = "That contact email doesn't look valid.";
1390
1386
  }
1391
1387
  if (!notice && values.support_url) {
1392
- var u = _b().safeUrl.parse(values.support_url);
1388
+ var u = b.safeUrl.parse(values.support_url);
1393
1389
  if (!u || (u.protocol !== "https:" && u.protocol !== "http:")) notice = "Support URL must be a valid http(s) URL.";
1394
1390
  }
1395
1391
  if (notice) {
@@ -1407,7 +1403,7 @@ function mount(router, deps) {
1407
1403
  notice: "Couldn't save — " + ((e && e.message) || "please try again."),
1408
1404
  }));
1409
1405
  }
1410
- _b().audit.safeEmit({ action: AUDIT_NAMESPACE + ".setup.save", outcome: "success", metadata: {} });
1406
+ b.audit.safeEmit({ action: AUDIT_NAMESPACE + ".setup.save", outcome: "success", metadata: {} });
1411
1407
  _redirect(res, "/admin/setup?saved=1");
1412
1408
  });
1413
1409
  }
package/lib/affiliates.js CHANGED
@@ -127,20 +127,14 @@ var ALLOWED_UPDATE_COLUMNS = Object.freeze([
127
127
  "commission_value", "attribution_window_days",
128
128
  ]);
129
129
 
130
- // Lazy framework handle matches the pattern used by every other
131
- // shop primitive; avoids the require cycle that would arise from
132
- // importing `./index` at module-eval time.
133
- var bShop;
134
- function _b() {
135
- if (!bShop) bShop = require("./index");
136
- return bShop.framework;
137
- }
138
- var C = _b().constants;
130
+ // Framework handle (the vendored blamejs); index.js re-exports this as .framework.
131
+ var b = require("./vendor/blamejs");
132
+ var C = b.constants;
139
133
 
140
134
  // ---- validators ---------------------------------------------------------
141
135
 
142
136
  function _uuid(s, label) {
143
- try { return _b().guardUuid.sanitize(s, { profile: "strict" }); }
137
+ try { return b.guardUuid.sanitize(s, { profile: "strict" }); }
144
138
  catch (e) { throw new TypeError("affiliates: " + label + " — " + (e && e.message || "invalid UUID")); }
145
139
  }
146
140
 
@@ -320,7 +314,7 @@ function _normalizeEmail(input) {
320
314
  if (typeof input !== "string" || !input.length) {
321
315
  throw new TypeError("affiliates: email must be a non-empty string");
322
316
  }
323
- var guardEmail = _b().guardEmail;
317
+ var guardEmail = b.guardEmail;
324
318
  var report;
325
319
  try {
326
320
  report = guardEmail.validate(input, { profile: "strict" });
@@ -345,7 +339,7 @@ function _now() { return Date.now(); }
345
339
  // ---- code generation + canonicalization ---------------------------------
346
340
 
347
341
  function _generateCode() {
348
- var buf = _b().crypto.generateBytes(CODE_LEN);
342
+ var buf = b.crypto.generateBytes(CODE_LEN);
349
343
  var out = "";
350
344
  for (var j = 0; j < CODE_LEN; j += 1) {
351
345
  out += CODE_ALPHABET.charAt(buf[j] & 31);
@@ -390,7 +384,7 @@ function create(opts) {
390
384
  opts = opts || {};
391
385
  var query = opts.query;
392
386
  if (!query) {
393
- query = function (sql, params) { return _b().externalDb.query(sql, params); };
387
+ query = function (sql, params) { return b.externalDb.query(sql, params); };
394
388
  }
395
389
 
396
390
  // Pagination cursors are HMAC-tagged via b.pagination so a caller
@@ -413,7 +407,7 @@ function create(opts) {
413
407
  throw new TypeError("affiliates." + label + ": cursor must be an opaque string or null");
414
408
  }
415
409
  try {
416
- var state = _b().pagination.decodeCursor(cursor, cursorSecret);
410
+ var state = b.pagination.decodeCursor(cursor, cursorSecret);
417
411
  if (JSON.stringify(state.orderKey) !== JSON.stringify(LIST_ORDER_KEY)) {
418
412
  throw new TypeError("affiliates." + label + ": cursor orderKey mismatch");
419
413
  }
@@ -427,7 +421,7 @@ function create(opts) {
427
421
  function _encodeNext(rows, limit) {
428
422
  var last = rows[rows.length - 1];
429
423
  if (!last || rows.length < limit) return null;
430
- return _b().pagination.encodeCursor({
424
+ return b.pagination.encodeCursor({
431
425
  orderKey: LIST_ORDER_KEY,
432
426
  vals: [last.occurred_at, last.id],
433
427
  forward: true,
@@ -435,11 +429,11 @@ function create(opts) {
435
429
  }
436
430
 
437
431
  function _hashEmail(canonicalEmail) {
438
- return _b().crypto.namespaceHash(EMAIL_NAMESPACE, canonicalEmail);
432
+ return b.crypto.namespaceHash(EMAIL_NAMESPACE, canonicalEmail);
439
433
  }
440
434
 
441
435
  function _hashSession(sessionId) {
442
- return _b().crypto.namespaceHash(SESSION_NAMESPACE, sessionId);
436
+ return b.crypto.namespaceHash(SESSION_NAMESPACE, sessionId);
443
437
  }
444
438
 
445
439
  async function _getAffiliateRaw(id) {
@@ -519,7 +513,7 @@ function create(opts) {
519
513
  var commissionValue = _commissionValue(input.commission_value, commissionKind);
520
514
  var attributionDays = _attributionWindow(input.attribution_window_days);
521
515
 
522
- var id = _b().uuid.v7();
516
+ var id = b.uuid.v7();
523
517
  var ts = _now();
524
518
  var row = {
525
519
  id: id,
@@ -697,7 +691,7 @@ function create(opts) {
697
691
  };
698
692
  }
699
693
 
700
- var visitId = _b().uuid.v7();
694
+ var visitId = b.uuid.v7();
701
695
  await query(
702
696
  "INSERT INTO affiliate_visits " +
703
697
  "(id, code, affiliate_id, visitor_session_id_hash, referrer, occurred_at) " +
@@ -801,7 +795,7 @@ function create(opts) {
801
795
  aff.commission_kind, Number(aff.commission_value), orderTotal
802
796
  );
803
797
 
804
- var id = _b().uuid.v7();
798
+ var id = b.uuid.v7();
805
799
  await query(
806
800
  "INSERT INTO affiliate_commissions " +
807
801
  "(id, order_id, affiliate_id, order_total_minor, commission_minor, " +
@@ -848,11 +842,11 @@ function create(opts) {
848
842
  idx += 1;
849
843
  }
850
844
  if (cursorVals) {
851
- var a = idx;
852
- var b = idx + 1;
845
+ var pOccurred = idx;
846
+ var pId = idx + 1;
853
847
  where.push(
854
- "(occurred_at < ?" + a + " OR " +
855
- "(occurred_at = ?" + a + " AND id < ?" + b + "))"
848
+ "(occurred_at < ?" + pOccurred + " OR " +
849
+ "(occurred_at = ?" + pOccurred + " AND id < ?" + pId + "))"
856
850
  );
857
851
  params.push(cursorVals[0], cursorVals[1]);
858
852
  idx += 2;
package/lib/analytics.js CHANGED
@@ -87,12 +87,8 @@
87
87
  * discipline owns what goes inside.
88
88
  */
89
89
 
90
- var bShop;
91
- function _b() {
92
- if (!bShop) bShop = require("./index");
93
- return bShop.framework;
94
- }
95
- var C = _b().constants;
90
+ var b = require("./vendor/blamejs");
91
+ var C = b.constants;
96
92
 
97
93
  var ONE_YEAR_MS = C.TIME.days(365);
98
94
  var DEFAULT_WINDOW_MS = C.TIME.days(30);
@@ -231,7 +227,7 @@ function create(opts) {
231
227
  opts = opts || {};
232
228
  var query = opts.query;
233
229
  if (!query) {
234
- query = function (sql, params) { return _b().externalDb.query(sql, params); };
230
+ query = function (sql, params) { return b.externalDb.query(sql, params); };
235
231
  }
236
232
 
237
233
  // Status buckets we always surface, even when zero. Aligned with
@@ -470,7 +466,6 @@ function create(opts) {
470
466
  occurredAt = input.occurred_at;
471
467
  }
472
468
 
473
- var b = _b();
474
469
  var sessionHash = sessionId == null ? null : b.crypto.namespaceHash(SESSION_NAMESPACE, sessionId);
475
470
  var customerHash = customerId == null ? null : b.crypto.namespaceHash(CUSTOMER_NAMESPACE, customerId);
476
471
  // `session_id_hash` is NOT NULL in the schema — fall back to
@@ -593,7 +588,7 @@ function create(opts) {
593
588
  _refuseRawPii("session_id", sessionId);
594
589
  var limit = (opts && opts.limit) == null ? 100 : opts.limit;
595
590
  _limit(limit, "limit", 500);
596
- var hash = _b().crypto.namespaceHash(SESSION_NAMESPACE, sessionId);
591
+ var hash = b.crypto.namespaceHash(SESSION_NAMESPACE, sessionId);
597
592
  var r = await query(
598
593
  "SELECT id, event_type, session_id_hash, customer_id_hash, " +
599
594
  " payload_json, product_id, search_q, page_url, " +
@@ -137,11 +137,7 @@ var ALLOWED_PATCH_COLUMNS = Object.freeze([
137
137
  "dismissible",
138
138
  ]);
139
139
 
140
- var bShop;
141
- function _b() {
142
- if (!bShop) bShop = require("./index");
143
- return bShop.framework;
144
- }
140
+ var b = require("./vendor/blamejs");
145
141
 
146
142
  // ---- monotonic clock ----------------------------------------------------
147
143
  //
@@ -275,7 +271,7 @@ function _linkUrl(s) {
275
271
  return s;
276
272
  }
277
273
  try {
278
- _b().safeUrl.parse(s, { allowedProtocols: ["https:"] });
274
+ b.safeUrl.parse(s, { allowedProtocols: ["https:"] });
279
275
  } catch (e) {
280
276
  throw new TypeError("announcementBar: link_url — " + (e && e.message || "must be https:// or a /-rooted absolute path"));
281
277
  }
@@ -323,7 +319,7 @@ function create(opts) {
323
319
  opts = opts || {};
324
320
  var query = opts.query;
325
321
  if (!query) {
326
- query = function (sql, params) { return _b().externalDb.query(sql, params); };
322
+ query = function (sql, params) { return b.externalDb.query(sql, params); };
327
323
  }
328
324
  // customerSegments is optional — announcements with audience =
329
325
  // "segment" require it, but a deployment without segment-targeted
@@ -564,7 +560,7 @@ function create(opts) {
564
560
  var sessionHash = null;
565
561
  if (input.session_id != null) {
566
562
  var sid = _sessionId(input.session_id);
567
- sessionHash = _b().crypto.namespaceHash(SESSION_HASH_NAMESPACE, sid);
563
+ sessionHash = b.crypto.namespaceHash(SESSION_HASH_NAMESPACE, sid);
568
564
  }
569
565
 
570
566
  // Pull every candidate row in the active window, ordered by
@@ -655,14 +651,14 @@ function create(opts) {
655
651
  throw new TypeError("announcementBar.recordDismissal: slug " + JSON.stringify(slug) + " not found");
656
652
  }
657
653
 
658
- var hash = _b().crypto.namespaceHash(SESSION_HASH_NAMESPACE, sessionId);
654
+ var hash = b.crypto.namespaceHash(SESSION_HASH_NAMESPACE, sessionId);
659
655
 
660
656
  // Dedup is enforced by the UNIQUE(announcement_slug,
661
657
  // session_id_hash) index; a second dismissal from the same
662
658
  // session is a no-op (the existing row keeps its occurred_at).
663
659
  // INSERT OR IGNORE keeps the call idempotent without a separate
664
660
  // SELECT-then-INSERT round-trip.
665
- var id = _b().uuid.v7();
661
+ var id = b.uuid.v7();
666
662
  var r = await query(
667
663
  "INSERT OR IGNORE INTO announcement_dismissals " +
668
664
  "(id, announcement_slug, session_id_hash, occurred_at) " +
@@ -695,7 +691,7 @@ function create(opts) {
695
691
  throw new TypeError("announcementBar.renderHtml: locale must be a BCP-47-shape string (e.g. 'en-US')");
696
692
  }
697
693
  }
698
- var escapeHtml = _b().template.escapeHtml;
694
+ var escapeHtml = b.template.escapeHtml;
699
695
 
700
696
  var theme = escapeHtml(announcement.theme || "info");
701
697
  var slug = escapeHtml(announcement.slug);
package/lib/api-keys.js CHANGED
@@ -76,7 +76,10 @@ var TOKEN_BYTE_LEN = 32;
76
76
  var TOKEN_PLAINTEXT_LEN = 43;
77
77
  var TOKEN_PLAINTEXT_RE = /^[A-Za-z0-9_-]{43}$/;
78
78
 
79
- var ROTATION_GRACE_MS = _b().constants.TIME.days(1);
79
+ // Framework handle (the vendored blamejs); index.js re-exports this as .framework.
80
+ var b = require("./vendor/blamejs");
81
+
82
+ var ROTATION_GRACE_MS = b.constants.TIME.days(1);
80
83
 
81
84
  var OWNER_TYPES = ["operator", "app", "affiliate", "tenant"];
82
85
  var STATUSES = ["active", "rotated", "revoked", "expired"];
@@ -112,19 +115,10 @@ var ALLOWED_UPDATE_COLUMNS = Object.freeze([
112
115
  "name", "scopes", "rate_limit_per_minute",
113
116
  ]);
114
117
 
115
- // Lazy framework handle — matches the pattern used by every other
116
- // shop primitive; avoids the require cycle that would arise from
117
- // importing `./index` at module-eval time.
118
- var bShop;
119
- function _b() {
120
- if (!bShop) bShop = require("./index");
121
- return bShop.framework;
122
- }
123
-
124
118
  // ---- validators ---------------------------------------------------------
125
119
 
126
120
  function _uuid(s, label) {
127
- try { return _b().guardUuid.sanitize(s, { profile: "strict" }); }
121
+ try { return b.guardUuid.sanitize(s, { profile: "strict" }); }
128
122
  catch (e) { throw new TypeError("apiKeys: " + label + " — " + (e && e.message || "invalid UUID")); }
129
123
  }
130
124
 
@@ -257,8 +251,8 @@ function _now() { return Date.now(); }
257
251
  // built-in `base64url` encoding runs in place of a polynomial-ReDoS-
258
252
  // shaped `.replace(/=+$/, "")` strip (CodeQL js/polynomial-redos).
259
253
  function _generateToken() {
260
- var buf = _b().crypto.generateBytes(TOKEN_BYTE_LEN);
261
- return _b().crypto.toBase64Url(buf);
254
+ var buf = b.crypto.generateBytes(TOKEN_BYTE_LEN);
255
+ return b.crypto.toBase64Url(buf);
262
256
  }
263
257
 
264
258
  function _canonicalToken(input) {
@@ -272,7 +266,7 @@ function _canonicalToken(input) {
272
266
  }
273
267
 
274
268
  function _hashToken(canonical) {
275
- return _b().crypto.namespaceHash(TOKEN_NAMESPACE, canonical);
269
+ return b.crypto.namespaceHash(TOKEN_NAMESPACE, canonical);
276
270
  }
277
271
 
278
272
  // ---- factory ------------------------------------------------------------
@@ -281,7 +275,7 @@ function create(opts) {
281
275
  opts = opts || {};
282
276
  var query = opts.query;
283
277
  if (!query) {
284
- query = function (sql, params) { return _b().externalDb.query(sql, params); };
278
+ query = function (sql, params) { return b.externalDb.query(sql, params); };
285
279
  }
286
280
 
287
281
  async function _getRaw(id) {
@@ -398,7 +392,7 @@ function create(opts) {
398
392
  var rateLimit = _rateLimit(input.rate_limit_per_minute);
399
393
  var expiresAt = _expiresAt(input.expires_at);
400
394
 
401
- var id = _b().uuid.v7();
395
+ var id = b.uuid.v7();
402
396
  var plaintext = _generateToken();
403
397
  var hash = _hashToken(plaintext);
404
398
  var ts = _now();
@@ -468,9 +462,9 @@ function create(opts) {
468
462
  var row = r.rows[0];
469
463
 
470
464
  // Constant-time equality on whichever column matched.
471
- var matchedLive = _b().crypto.timingSafeEqual(row.token_hash, hash);
465
+ var matchedLive = b.crypto.timingSafeEqual(row.token_hash, hash);
472
466
  var matchedPrevious = row.token_hash_previous != null
473
- && _b().crypto.timingSafeEqual(row.token_hash_previous, hash);
467
+ && b.crypto.timingSafeEqual(row.token_hash_previous, hash);
474
468
  if (!matchedLive && !matchedPrevious) return null;
475
469
 
476
470
  // expires_at takes precedence over everything else. A key whose
@@ -561,7 +555,7 @@ function create(opts) {
561
555
  // row can claim the UNIQUE column without colliding. We use a
562
556
  // placeholder hash (the row id under a rotate-marker namespace)
563
557
  // so the UNIQUE constraint stays honoured.
564
- var placeholderHash = _b().crypto.namespaceHash(
558
+ var placeholderHash = b.crypto.namespaceHash(
565
559
  "api-key-rotated-placeholder", current.id + ":" + ts
566
560
  );
567
561
  await query(
@@ -572,7 +566,7 @@ function create(opts) {
572
566
 
573
567
  // Issue the replacement row. Scopes / rate-limit / expiry /
574
568
  // owner all carry forward verbatim — rotation is plaintext-only.
575
- var newId = _b().uuid.v7();
569
+ var newId = b.uuid.v7();
576
570
  var plaintext = _generateToken();
577
571
  var newHash = _hashToken(plaintext);
578
572
  var row = {
@@ -704,7 +698,7 @@ function create(opts) {
704
698
  throw miss;
705
699
  }
706
700
 
707
- var rowId = _b().uuid.v7();
701
+ var rowId = b.uuid.v7();
708
702
  await query(
709
703
  "INSERT INTO api_key_usage (id, key_id, endpoint, occurred_at) " +
710
704
  "VALUES (?1, ?2, ?3, ?4)",