@asteby/storefront-react 0.18.0 → 0.20.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/README.md +60 -0
- package/dist/account-server.cjs +405 -7
- package/dist/account-server.cjs.map +1 -1
- package/dist/account-server.d.cts +41 -1
- package/dist/account-server.d.ts +41 -1
- package/dist/account-server.js +73 -3
- package/dist/account-server.js.map +1 -1
- package/dist/account.cjs +1507 -4
- package/dist/account.cjs.map +1 -1
- package/dist/account.css +203 -0
- package/dist/account.d.cts +526 -6
- package/dist/account.d.ts +526 -6
- package/dist/account.js +1145 -2
- package/dist/account.js.map +1 -1
- package/dist/checkout.js +2 -2
- package/dist/chunk-PPQEUTXJ.js +260 -0
- package/dist/chunk-PPQEUTXJ.js.map +1 -0
- package/dist/chunk-TXEYBDFG.js +182 -0
- package/dist/chunk-TXEYBDFG.js.map +1 -0
- package/dist/fiscal.d.cts +34 -34
- package/dist/fiscal.d.ts +34 -34
- package/dist/fiscal.js +4 -258
- package/dist/fiscal.js.map +1 -1
- package/dist/payments.cjs +22 -3
- package/dist/payments.cjs.map +1 -1
- package/dist/payments.css +15 -14
- package/dist/payments.d.cts +4 -1
- package/dist/payments.d.ts +4 -1
- package/dist/payments.js +24 -5
- package/dist/payments.js.map +1 -1
- package/dist/voucher-document-SFWJCLTN.js +124 -0
- package/dist/voucher-document-SFWJCLTN.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/account/server.ts"],"names":["repairPath","isStorefrontError"],"mappings":"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","file":"account-server.cjs","sourcesContent":["/**\n * Server side of the account screen (`@asteby/storefront-react/account/server`): `loadAuthCapabilities` for the loader\n * and `createAuthAction` for the action. No React, no router: Web `Request`/`Response` only, so any framework mounts it.\n *\n * The browser never talks to OPS. The action signs the buyer in with the store's `sk_` client and keeps the session\n * token in the store's own cookie, which is passed in (`customerCookie`), so name, flags and signing stay the store's.\n */\nimport { isStorefrontError, repairPath, type CustomerCapabilities, type CustomerSession, type StorefrontClient } from '@asteby/storefront'\nimport type { AuthActionData, AuthErrorCode, AuthIntent } from './types.js'\n\nexport type { AuthActionData, AuthErrorCode, AuthIntent, AuthStep } from './types.js'\n\n/** What is assumed when the store cannot be asked: password sign-in works, nothing else is offered. */\nexport const SAFE_AUTH_CAPABILITIES: Readonly<CustomerCapabilities> = Object.freeze({\n password: true,\n email_verification: false,\n otp_channels: Object.freeze([]) as unknown as CustomerCapabilities['otp_channels'],\n})\n\nconst FAILURE_TTL_MS = 5_000\nconst LOG_EVERY_MS = 60_000\nlet lastLogAt = -Infinity\n\n/** Server log (never the buyer's data): says what is missing and where it is repaired. At most once a minute. */\nfunction logMisconfigured(scopes: readonly string[]): void {\n const t = Date.now()\n if (t - lastLogAt < LOG_EVERY_MS) return\n lastLogAt = t\n console.error(\n `[@asteby/storefront-react] La credencial de la tienda no tiene permisos${scopes.length ? ` (${scopes.join(', ')})` : ''}; ` +\n `las cuentas de comprador no funcionan hasta repararlo en ${repairPath()}.`,\n )\n}\nconst cache = new WeakMap<object, { at: number; ok: boolean; value: CustomerCapabilities }>()\n\nexport type LoadAuthCapabilitiesOptions = {\n /** How long a good answer is reused per client (default 60 s). `0` disables the cache. */\n ttlMs?: number\n signal?: AbortSignal\n /** Clock, for tests. */\n now?: () => number\n}\n\n/**\n * Asks the store which ways of signing in it offers, with a short cache per client. It NEVER throws: when OPS does not\n * answer (older server, outage, token without scope) it returns `SAFE_AUTH_CAPABILITIES` and retries after a few\n * seconds, so the account screen always renders. Use it as the loader: `loader = () => loadAuthCapabilities(storefront)`.\n */\nexport async function loadAuthCapabilities(sf: StorefrontClient, options: LoadAuthCapabilitiesOptions = {}): Promise<CustomerCapabilities> {\n const now = options.now ?? Date.now\n const ttl = options.ttlMs ?? 60_000\n const hit = cache.get(sf)\n if (hit && now() - hit.at < (hit.ok ? ttl : FAILURE_TTL_MS)) return hit.value\n try {\n const got = await sf.customer.capabilities(options.signal ? { signal: options.signal } : undefined)\n const missing = Array.isArray(got?.missing_scopes) ? got.missing_scopes.filter((x): x is string => typeof x === 'string') : []\n const value: CustomerCapabilities = {\n // `password: false` (including for a missing scope) is respected: the form never offers what the token cannot do.\n password: got?.password !== false,\n email_verification: got?.email_verification === true,\n otp_channels: Array.isArray(got?.otp_channels) ? got.otp_channels : [],\n ...(typeof got?.unavailable_reason === 'string' ? { unavailable_reason: got.unavailable_reason } : {}),\n ...(missing.length ? { missing_scopes: missing } : {}),\n }\n if (value.unavailable_reason === 'missing_scope') logMisconfigured(missing)\n cache.set(sf, { at: now(), ok: true, value })\n return value\n } catch (err) {\n if (isStorefrontError(err) && err.code === 'insufficient_scope') {\n // The token cannot even read capabilities: do not offer password sign-in it could not complete.\n const value: CustomerCapabilities = {\n password: false,\n email_verification: false,\n otp_channels: [],\n unavailable_reason: 'missing_scope',\n missing_scopes: err.requiredScopes,\n }\n logMisconfigured(err.requiredScopes)\n cache.set(sf, { at: now(), ok: false, value })\n return value\n }\n cache.set(sf, { at: now(), ok: false, value: SAFE_AUTH_CAPABILITIES })\n return SAFE_AUTH_CAPABILITIES\n }\n}\n\n/** The part of a cookie the action needs. React Router's `createCookie(...)` and Remix's fit as they are. */\nexport type AuthCookie = {\n serialize(value: string, options?: { expires?: Date; maxAge?: number }): string | Promise<string>\n}\n\n/** Allows only a path inside the site (`/account`, `/orders?x=1`); anything else is `fallback`. Blocks `//host` and `/\\host`. */\nexport function safeNextPath(raw: string | null | undefined, fallback = '/account'): string {\n if (typeof raw !== 'string') return fallback\n const v = raw.trim()\n if (!v.startsWith('/') || v.startsWith('//') || v.startsWith('/\\\\') || /[\\u0000-\\u001f\\\\]/.test(v)) return fallback\n return v\n}\n\nexport type CreateAuthActionOptions = {\n storefront: StorefrontClient\n /** The store's cookie for the buyer session token (`createCookie('sf_customer', ...)`). */\n customerCookie: AuthCookie\n /** Validates the `next` field before redirecting (default `safeNextPath`). Return a same-site path. */\n safeNext?: (raw: string | null) => string\n /** Where to go after signing in when there is no `next` (default `/account`). Only used by the default `safeNext`. */\n defaultNext?: string\n /** Shopper IP for the per-shopper rate limit (see `clientIp` of the client). */\n clientIp?: (request: Request) => string | null | undefined\n /** Capabilities source, for tests or a shared cache (default `loadAuthCapabilities`). */\n capabilities?: (sf: StorefrontClient) => Promise<CustomerCapabilities>\n}\n\nexport type AuthActionArgs = { request: Request }\n\nconst fail = (code: AuthErrorCode, extra: Partial<AuthActionData> = {}, field?: string): AuthActionData => ({\n ok: false,\n ...extra,\n error: { code, ...(field ? { field } : {}) },\n})\n\n/** Maps what the SDK threw to the error the form shows. `ctx` tells what a 401 means on this step. */\nfunction toFailure(err: unknown, ctx: 'credentials' | 'code' | 'other', extra: Partial<AuthActionData>): AuthActionData {\n if (!isStorefrontError(err)) return fail('unavailable', extra)\n if (err.code === 'insufficient_scope') {\n logMisconfigured(err.requiredScopes)\n return fail('store_misconfigured', extra)\n }\n switch (err.status) {\n case 401:\n return fail(ctx === 'credentials' ? 'invalid_credentials' : ctx === 'code' ? 'invalid_code' : 'unavailable', extra, ctx === 'code' ? 'code' : undefined)\n case 409:\n return fail('email_taken', extra, 'email')\n case 429:\n return fail('rate_limited', extra)\n case 400:\n case 422:\n return fail('validation', extra, err.field)\n case 403:\n case 404:\n return fail('unsupported', extra)\n default:\n return fail('unavailable', extra)\n }\n}\n\n/**\n * The account action: one `POST` form with an `intent` field.\n *\n * | intent | fields | result |\n * | ------------- | ---------------------------------------- | -------------------------------------------------------- |\n * | `login` | email, password | signs in -> redirect |\n * | `register` | email, password, first_name?, last_name? | `step: 'verify'` or, without verification, redirect |\n * | `verify` | email, code | account ready -> redirect |\n * | `otp-request` | email | `step: 'otp'` (code sent) |\n * | `otp-login` | email, code | signs in -> redirect |\n * | `forgot` | email | `step: 'reset'` (always, so it never says who has an account) |\n * | `reset` | email, code, password | new password and signed in -> redirect |\n *\n * Success is a `303` to `next` (validated by `safeNext`) with `Set-Cookie` holding the session token; anything else is\n * an `AuthActionData` to render with `<AccountAuth data={...}>`. Passwords and codes are never echoed back.\n */\nexport function createAuthAction(options: CreateAuthActionOptions) {\n const { storefront: sf, customerCookie } = options\n const safeNext = options.safeNext ?? ((raw: string | null) => safeNextPath(raw, options.defaultNext ?? '/account'))\n const loadCaps = options.capabilities ?? ((client: StorefrontClient) => loadAuthCapabilities(client))\n\n async function signedIn(session: CustomerSession, next: string): Promise<Response> {\n const expires = new Date(session.expires_at)\n const cookie = await customerCookie.serialize(session.token, Number.isNaN(expires.getTime()) ? undefined : { expires })\n return new Response(null, { status: 303, headers: { Location: next, 'Set-Cookie': cookie } })\n }\n\n return async function authAction({ request }: AuthActionArgs): Promise<Response | AuthActionData> {\n const form = await request.formData().catch(() => null)\n if (!form) return fail('validation')\n const text = (name: string) => {\n const v = form.get(name)\n return typeof v === 'string' ? v : ''\n }\n const intent = text('intent') as AuthIntent\n const email = text('email').trim()\n const password = text('password')\n const code = text('code').replace(/\\s+/g, '')\n const next = safeNext(text('next') || null)\n const ip = options.clientIp?.(request)\n const w = ip ? { clientIp: ip } : undefined\n const carry: Partial<AuthActionData> = { email }\n if (!email) return fail('validation', carry, 'email')\n\n const caps = await loadCaps(sf)\n const passwordOn = caps.password\n // Off because the store's token lacks a scope (not a merchant choice): say so instead of \"not available\".\n const misconfigured = caps.unavailable_reason === 'missing_scope'\n const off = (): AuthActionData => fail(misconfigured ? 'store_misconfigured' : 'unsupported', carry)\n const otpOn = caps.otp_channels.includes('email')\n\n try {\n switch (intent) {\n case 'login': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n case 'register': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n const res = await sf.customer.register(\n { email, password, ...(text('first_name').trim() ? { first_name: text('first_name').trim() } : {}), ...(text('last_name').trim() ? { last_name: text('last_name').trim() } : {}) },\n w,\n )\n return res.status === 'created' ? await signedIn(res.session, next) : { ok: true, step: 'verify', email }\n }\n case 'verify': {\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.verifyRegistration({ email, code }, w), next)\n }\n case 'otp-request': {\n if (!otpOn) return off()\n await sf.customer.requestOtp({ email }, w)\n return { ok: true, step: 'otp', email }\n }\n case 'otp-login': {\n if (!otpOn) return off()\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.createSession({ email, code }, w), next)\n }\n case 'forgot': {\n if (!passwordOn || !otpOn) return off()\n try {\n await sf.customer.requestOtp({ email }, w)\n } catch (err) {\n // Only throttling and a bad email are told; anything else looks the same as success (no account enumeration).\n if (isStorefrontError(err) && (err.status === 429 || err.status === 400)) throw err\n }\n return { ok: true, step: 'reset', email }\n }\n case 'reset': {\n if (!passwordOn) return off()\n if (!code) return fail('validation', carry, 'code')\n if (!password) return fail('validation', carry, 'password')\n await sf.customer.resetPassword({ email, code, password }, w)\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n default:\n return fail('validation', carry)\n }\n } catch (err) {\n const step = intent === 'verify' ? 'verify' : intent === 'otp-login' ? 'otp' : intent === 'reset' || intent === 'forgot' ? 'reset' : undefined\n const ctx = intent === 'login' ? 'credentials' : step ? 'code' : 'other'\n return toFailure(err, ctx, step && intent !== 'forgot' ? { ...carry, step } : carry)\n }\n }\n}\n\nexport type AuthAction = ReturnType<typeof createAuthAction>\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/account/voucher.ts","../src/account/voucher-document.ts","../src/account/server.ts"],"names":["repairPath","isStorefrontError","text","storefront","invoiceFileBytes","safeInvoiceFilename","renderVoucherDocument"],"mappings":"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AAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MACvI,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAAA;AAAA,MAAe,aAA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","file":"account-server.cjs","sourcesContent":["/**\n * Pure pieces of the cash voucher (OXXO, SPEI, deposit): the normalized `VoucherView` of a `PendingPayment` and the\n * Code 128 barcode (the one cashiers' readers scan). No React, no DOM: the same code draws the barcode in the page\n * (`<Barcode>`) and in the printable document (`voucher-document.ts`, loaded only when the buyer prints).\n */\nimport type { Money, PendingPayment } from '@asteby/storefront'\n\nexport type VoucherView = {\n /** `oxxo`, `spei`, ... as the gateway publishes it. */\n method: string | null\n reference: string | null\n barcode: string | null\n clabe: string | null\n expires_at: string | null\n amount: Money | null\n instructions: string | null\n}\n\nconst MAX = 256\n\nfunction text(v: unknown): string | null {\n if (typeof v === 'number' && Number.isFinite(v)) return String(v)\n if (typeof v !== 'string') return null\n const s = v.trim().slice(0, MAX)\n return s || null\n}\n\nfunction moneyOf(v: unknown): Money | null {\n if (!v || typeof v !== 'object') return null\n const m = v as Record<string, unknown>\n const amount = text(m.amount)\n const cur = text(m.currency_code)\n return amount && cur && Number.isFinite(Number(amount)) ? { amount, currency_code: cur.toUpperCase() } : null\n}\n\n/** The voucher of a pending payment; `null` when it has neither reference, barcode nor CLABE (nothing to pay with). */\nexport function voucherOf(p: Pick<PendingPayment, 'payment' | 'total' | 'expires_at'> | null | undefined): VoucherView | null {\n const pay = p?.payment\n if (!pay || typeof pay !== 'object') return null\n const v: VoucherView = {\n method: text(pay.method ?? pay.provider),\n reference: text(pay.reference),\n barcode: text(pay.barcode),\n clabe: text(pay.clabe),\n expires_at: text(pay.expires_at) ?? text(p?.expires_at),\n amount: moneyOf(pay.amount) ?? moneyOf(p?.total),\n instructions: text(pay.instructions),\n }\n return v.reference || v.barcode || v.clabe ? v : null\n}\n\n/** The value the barcode encodes: the gateway's `barcode`, else the reference of an OXXO voucher. */\nexport function barcodeValue(v: Pick<VoucherView, 'barcode' | 'method' | 'reference'>): string | null {\n return v.barcode ?? (v.method?.toLowerCase() === 'oxxo' ? v.reference : null)\n}\n\n// 11-module patterns of symbols 0..105 and the 13-module stop (ISO/IEC 15417).\nconst BARS = [\n '11011001100', '11001101100', '11001100110', '10010011000', '10010001100', '10001001100', '10011001000', '10011000100', '10001100100', '11001001000',\n '11001000100', '11000100100', '10110011100', '10011011100', '10011001110', '10111001100', '10011101100', '10011100110', '11001110010', '11001011100',\n '11001001110', '11011100100', '11001110100', '11101101110', '11101001100', '11100101100', '11100100110', '11101100100', '11100110100', '11100110010',\n '11011011000', '11011000110', '11000110110', '10100011000', '10001011000', '10001000110', '10110001000', '10001101000', '10001100010', '11010001000',\n '11000101000', '11000100010', '10110111000', '10110001110', '10001101110', '10111011000', '10111000110', '10001110110', '11101110110', '11010001110',\n '11000101110', '11011101000', '11011100010', '11011101110', '11101011000', '11101000110', '11100010110', '11101101000', '11101100010', '11100011010',\n '11101111010', '11001000010', '11110001010', '10100110000', '10100001100', '10010110000', '10010000110', '10000101100', '10000100110', '10110010000',\n '10110000100', '10011010000', '10011000010', '10000110100', '10000110010', '11000010010', '11001010000', '11110111010', '11000010100', '10001111010',\n '10100111100', '10010111100', '10010011110', '10111100100', '10011110100', '10011110010', '11110100100', '11110010100', '11110010010', '11011011110',\n '11011110110', '11110110110', '10101111000', '10100011110', '10001011110', '10111101000', '10111100010', '11110101000', '11110100010', '10111011110',\n '10111101110', '11101011110', '11110101110', '11010000100', '11010010000', '11010011100',\n]\nconst STOP = '1100011101011'\n\n/**\n * Modules (`1` bar, `0` space) of the Code 128 of `value`: set C (digit pairs) when it is all digits of even length,\n * set B (printable ASCII) otherwise. `null` when it cannot be encoded.\n */\nexport function code128Modules(value: string): string | null {\n if (!value || value.length > 80) return null\n let codes: number[]\n if (/^\\d+$/.test(value) && value.length % 2 === 0) {\n codes = [105]\n for (let i = 0; i < value.length; i += 2) codes.push(Number(value.slice(i, i + 2)))\n } else {\n codes = [104]\n for (const ch of value) {\n const c = ch.charCodeAt(0)\n if (c < 32 || c > 126) return null\n codes.push(c - 32)\n }\n }\n let sum = codes[0]!\n for (let i = 1; i < codes.length; i++) sum += codes[i]! * i\n codes.push(sum % 103)\n return codes.map((c) => BARS[c]).join('') + STOP\n}\n\nexport type BarcodeGeometry = { width: number; height: number; rects: { x: number; w: number }[] }\n\n/** Bars of the barcode as rectangles (quiet zone of 10 modules each side included in `width`). `null` if not encodable. */\nexport function barcodeGeometry(value: string, opts: { module?: number; height?: number } = {}): BarcodeGeometry | null {\n const bits = code128Modules(value)\n if (!bits) return null\n const mod = opts.module ?? 2\n const quiet = 10\n const rects: { x: number; w: number }[] = []\n for (let i = 0; i < bits.length; ) {\n if (bits[i] === '0') {\n i++\n continue\n }\n let j = i\n while (j < bits.length && bits[j] === '1') j++\n rects.push({ x: (quiet + i) * mod, w: (j - i) * mod })\n i = j\n }\n return { width: (bits.length + quiet * 2) * mod, height: opts.height ?? 70, rects }\n}\n","/**\n * Printable voucher (A4 HTML) that does not depend on any payment gateway: built only from the voucher data OPS keeps.\n * Loaded on demand (the buyer taps print/download) or by `pendingVoucherResponse` on the server; plain text, no React.\n * Everything external passes through `esc` before it enters the HTML.\n */\nimport type { Money } from '@asteby/storefront'\nimport { barcodeGeometry, barcodeValue, type VoucherView } from './voucher.js'\n\nexport function esc(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[c] as string)\n}\n\ntype DocText = {\n title: string\n total: string\n reference: string\n clabe: string\n expires: string\n expiresNote: string\n order: string\n barcode: string\n print: string\n footer: string\n stepsCash: string[]\n stepsSpei: string[]\n methods: Record<string, string>\n cash: string\n}\n\nconst ES: DocText = {\n title: 'Ficha de pago',\n total: 'Total a pagar',\n reference: 'Referencia',\n clabe: 'CLABE',\n expires: 'Vence',\n expiresNote: 'Pasada esa fecha la ficha deja de ser válida.',\n order: 'Pedido',\n barcode: 'Código de barras',\n print: 'Imprimir ficha',\n footer: 'Tu pedido se genera cuando se confirma el pago. Esta ficha es de un solo uso; no la compartas.',\n stepsCash: [\n 'Acude a la tienda OXXO (o el comercio indicado) y di que vas a hacer un pago de servicio en efectivo.',\n 'Muestra el código de barras o dicta la referencia y paga el monto exacto.',\n 'Conserva tu comprobante: confirmaremos tu pago automáticamente.',\n ],\n stepsSpei: ['Entra a la banca en línea o app de tu banco.', 'Haz una transferencia SPEI a la CLABE indicada por el monto exacto.', 'Conserva tu comprobante: confirmaremos tu pago automáticamente.'],\n methods: { oxxo: 'OXXO', spei: 'Transferencia SPEI', bank_transfer: 'Transferencia bancaria', bank_deposit: 'Depósito bancario', cash: 'Pago en efectivo' },\n cash: 'Pago en efectivo',\n}\n\nconst EN: DocText = {\n title: 'Payment voucher',\n total: 'Amount to pay',\n reference: 'Reference',\n clabe: 'CLABE',\n expires: 'Expires',\n expiresNote: 'After that date the voucher is no longer valid.',\n order: 'Order',\n barcode: 'Barcode',\n print: 'Print voucher',\n footer: 'Your order is created when the payment is confirmed. This voucher is single-use; do not share it.',\n stepsCash: [\n 'Go to an OXXO store (or the store indicated) and say you want to make a cash service payment.',\n 'Show the barcode or read out the reference and pay the exact amount.',\n 'Keep your receipt: we will confirm your payment automatically.',\n ],\n stepsSpei: ['Open your bank online or app.', 'Make a SPEI transfer to the CLABE below for the exact amount.', 'Keep your receipt: we will confirm your payment automatically.'],\n methods: { oxxo: 'OXXO', spei: 'SPEI transfer', bank_transfer: 'Bank transfer', bank_deposit: 'Bank deposit', cash: 'Cash payment' },\n cash: 'Cash payment',\n}\n\nexport type VoucherDocumentOptions = {\n shopName?: string\n /** Order number, if there is one yet. */\n number?: string | null\n locale?: string\n /** IANA zone the expiry is printed in (default: the runtime's). */\n timeZone?: string\n /** Print button on screen (hidden when printing). */\n printButton?: boolean\n /** Opens the print dialog on load. */\n autoPrint?: boolean\n /** `<script>` nonce when the one serving the voucher sends a CSP with `script-src 'nonce-…'`. */\n nonce?: string\n}\n\nconst CSS = `\n@page { size: A4; margin: 18mm; }\n* { box-sizing: border-box; }\nbody { margin: 0; font: 14px/1.5 system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif; color: #111; background: #fff; }\nmain { max-width: 174mm; margin: 0 auto; padding: 24px 16px; }\nh1 { font-size: 22px; margin: 0; }\n.muted { color: #555; }\n.head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; border-bottom: 3px solid #111; padding-bottom: 12px; }\n.amount { font-size: 28px; font-weight: 700; text-align: right; }\n.box { border: 1px solid #111; padding: 14px 16px; margin-top: 18px; }\n.label { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: #555; }\n.value { font: 700 22px/1.3 ui-monospace, \"SF Mono\", Menlo, Consolas, monospace; word-break: break-all; letter-spacing: .04em; }\n.bar { margin-top: 18px; text-align: center; }\n.bar svg { max-width: 100%; height: auto; }\n.steps { margin: 18px 0 0; padding-left: 20px; }\n.note { margin-top: 18px; font-size: 12px; }\n.pre { white-space: pre-line; }\n.actions { margin-top: 24px; display: flex; gap: 12px; }\n.actions button { font: inherit; padding: 10px 18px; border: 1px solid #111; background: #111; color: #fff; cursor: pointer; }\n@media print { .actions { display: none; } main { padding: 0; } }\n`\n\nfunction formatMoney(m: Money | null, locale: string): string {\n if (!m) return ''\n try {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: m.currency_code }).format(Number(m.amount))\n } catch {\n return `${m.amount} ${m.currency_code}`\n }\n}\n\nfunction formatDate(iso: string | null, locale: string, timeZone?: string): string {\n if (!iso) return ''\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return ''\n try {\n return d.toLocaleString(locale, { dateStyle: 'long', timeStyle: 'short', ...(timeZone ? { timeZone } : {}) })\n } catch {\n return d.toISOString()\n }\n}\n\nfunction barcodeSvg(value: string, label: string): string | null {\n const g = barcodeGeometry(value)\n if (!g) return null\n const rects = g.rects.map((r) => `<rect x=\"${r.x}\" y=\"0\" width=\"${r.w}\" height=\"${g.height}\"/>`).join('')\n return `<svg viewBox=\"0 0 ${g.width} ${g.height}\" width=\"${g.width}\" height=\"${g.height}\" role=\"img\" aria-label=\"${esc(label)} ${esc(value)}\" shape-rendering=\"crispEdges\" fill=\"#000\">${rects}</svg>`\n}\n\n/** Complete HTML document of the voucher. Missing data is simply not drawn. */\nexport function renderVoucherDocument(v: VoucherView, opts: VoucherDocumentOptions = {}): string {\n const locale = opts.locale ?? 'es-MX'\n const t = locale.toLowerCase().startsWith('en') ? EN : ES\n const shop = opts.shopName || ''\n // Own keys only: a gateway method named `constructor` or `__proto__` must print as itself, not as Object internals.\n const method = v.method ? (Object.prototype.hasOwnProperty.call(t.methods, v.method.toLowerCase()) ? t.methods[v.method.toLowerCase()]! : v.method) : t.cash\n const isSpei = !!v.clabe && !v.reference\n const code = barcodeValue(v)\n const svg = code ? barcodeSvg(code, t.barcode) : null\n const expires = formatDate(v.expires_at, locale, opts.timeZone)\n const field = (label: string, value: string | null) => (value ? `<div class=\"box\"><div class=\"label\">${esc(label)}</div><div class=\"value\">${esc(value)}</div></div>` : '')\n const steps = isSpei ? t.stepsSpei : t.stepsCash\n const subtitle = [shop, method, opts.number ? `${t.order} ${opts.number}` : ''].filter(Boolean).map(esc).join(' · ')\n return `<!doctype html>\n<html lang=\"${esc(locale)}\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"robots\" content=\"noindex\"><title>${esc(t.title)}${shop ? ` - ${esc(shop)}` : ''}</title><style>${CSS}</style></head>\n<body><main>\n<div class=\"head\"><div><h1>${esc(t.title)}</h1><div class=\"muted\">${subtitle}</div></div>\n${v.amount ? `<div><div class=\"label\" style=\"text-align:right\">${esc(t.total)}</div><div class=\"amount\">${esc(formatMoney(v.amount, locale))}</div></div>` : ''}</div>\n${field(t.reference, v.reference)}${field(t.clabe, v.clabe)}\n${svg ? `<div class=\"bar\">${svg}<div class=\"muted\" style=\"font-family:ui-monospace,monospace\">${esc(code as string)}</div></div>` : ''}\n${expires ? `<p><strong>${esc(t.expires)}:</strong> ${esc(expires)}. ${esc(t.expiresNote)}</p>` : ''}\n<ol class=\"steps\">${steps.map((s) => `<li>${esc(s)}</li>`).join('')}</ol>\n${v.instructions ? `<p class=\"note pre muted\">${esc(v.instructions)}</p>` : ''}\n<p class=\"note muted\">${esc(t.footer)}</p>\n${opts.printButton ? `<div class=\"actions\"><button type=\"button\" id=\"print\">${esc(t.print)}</button></div>` : ''}\n</main>\n${opts.printButton || opts.autoPrint ? `<script${opts.nonce ? ` nonce=\"${esc(opts.nonce)}\"` : ''}>(function(){var b=document.getElementById(\"print\");if(b)b.addEventListener(\"click\",function(){window.print()});${opts.autoPrint ? 'window.addEventListener(\"load\",function(){setTimeout(function(){window.print()},300)});' : ''}})();</script>` : ''}\n</body></html>`\n}\n","/**\n * Server side of the account screen (`@asteby/storefront-react/account/server`): `loadAuthCapabilities` for the loader\n * and `createAuthAction` for the action. No React, no router: Web `Request`/`Response` only, so any framework mounts it.\n *\n * The browser never talks to OPS. The action signs the buyer in with the store's `sk_` client and keeps the session\n * token in the store's own cookie, which is passed in (`customerCookie`), so name, flags and signing stay the store's.\n */\nimport { invoiceFileBytes, isStorefrontError, repairPath, safeInvoiceFilename, type CustomerCapabilities, type CustomerSession, type StorefrontClient } from '@asteby/storefront'\nimport { voucherOf } from './voucher.js'\nimport type { AuthActionData, AuthErrorCode, AuthIntent } from './types.js'\n\nexport type { AuthActionData, AuthErrorCode, AuthIntent, AuthStep } from './types.js'\n\n/** What is assumed when the store cannot be asked: password sign-in works, nothing else is offered. */\nexport const SAFE_AUTH_CAPABILITIES: Readonly<CustomerCapabilities> = Object.freeze({\n password: true,\n email_verification: false,\n otp_channels: Object.freeze([]) as unknown as CustomerCapabilities['otp_channels'],\n})\n\nconst FAILURE_TTL_MS = 5_000\nconst LOG_EVERY_MS = 60_000\nlet lastLogAt = -Infinity\n\n/** Server log (never the buyer's data): says what is missing and where it is repaired. At most once a minute. */\nfunction logMisconfigured(scopes: readonly string[]): void {\n const t = Date.now()\n if (t - lastLogAt < LOG_EVERY_MS) return\n lastLogAt = t\n console.error(\n `[@asteby/storefront-react] La credencial de la tienda no tiene permisos${scopes.length ? ` (${scopes.join(', ')})` : ''}; ` +\n `las cuentas de comprador no funcionan hasta repararlo en ${repairPath()}.`,\n )\n}\nconst cache = new WeakMap<object, { at: number; ok: boolean; value: CustomerCapabilities }>()\n\nexport type LoadAuthCapabilitiesOptions = {\n /** How long a good answer is reused per client (default 60 s). `0` disables the cache. */\n ttlMs?: number\n signal?: AbortSignal\n /** Clock, for tests. */\n now?: () => number\n}\n\n/**\n * Asks the store which ways of signing in it offers, with a short cache per client. It NEVER throws: when OPS does not\n * answer (older server, outage, token without scope) it returns `SAFE_AUTH_CAPABILITIES` and retries after a few\n * seconds, so the account screen always renders. Use it as the loader: `loader = () => loadAuthCapabilities(storefront)`.\n */\nexport async function loadAuthCapabilities(sf: StorefrontClient, options: LoadAuthCapabilitiesOptions = {}): Promise<CustomerCapabilities> {\n const now = options.now ?? Date.now\n const ttl = options.ttlMs ?? 60_000\n const hit = cache.get(sf)\n if (hit && now() - hit.at < (hit.ok ? ttl : FAILURE_TTL_MS)) return hit.value\n try {\n const got = await sf.customer.capabilities(options.signal ? { signal: options.signal } : undefined)\n const missing = Array.isArray(got?.missing_scopes) ? got.missing_scopes.filter((x): x is string => typeof x === 'string') : []\n const value: CustomerCapabilities = {\n // `password: false` (including for a missing scope) is respected: the form never offers what the token cannot do.\n password: got?.password !== false,\n email_verification: got?.email_verification === true,\n otp_channels: Array.isArray(got?.otp_channels) ? got.otp_channels : [],\n ...(typeof got?.unavailable_reason === 'string' ? { unavailable_reason: got.unavailable_reason } : {}),\n ...(missing.length ? { missing_scopes: missing } : {}),\n }\n if (value.unavailable_reason === 'missing_scope') logMisconfigured(missing)\n cache.set(sf, { at: now(), ok: true, value })\n return value\n } catch (err) {\n if (isStorefrontError(err) && err.code === 'insufficient_scope') {\n // The token cannot even read capabilities: do not offer password sign-in it could not complete.\n const value: CustomerCapabilities = {\n password: false,\n email_verification: false,\n otp_channels: [],\n unavailable_reason: 'missing_scope',\n missing_scopes: err.requiredScopes,\n }\n logMisconfigured(err.requiredScopes)\n cache.set(sf, { at: now(), ok: false, value })\n return value\n }\n cache.set(sf, { at: now(), ok: false, value: SAFE_AUTH_CAPABILITIES })\n return SAFE_AUTH_CAPABILITIES\n }\n}\n\n/** The part of a cookie the action needs. React Router's `createCookie(...)` and Remix's fit as they are. */\nexport type AuthCookie = {\n serialize(value: string, options?: { expires?: Date; maxAge?: number }): string | Promise<string>\n}\n\n/** Allows only a path inside the site (`/account`, `/orders?x=1`); anything else is `fallback`. Blocks `//host` and `/\\host`. */\nexport function safeNextPath(raw: string | null | undefined, fallback = '/account'): string {\n if (typeof raw !== 'string') return fallback\n const v = raw.trim()\n if (!v.startsWith('/') || v.startsWith('//') || v.startsWith('/\\\\') || /[\\u0000-\\u001f\\\\]/.test(v)) return fallback\n return v\n}\n\nexport type CreateAuthActionOptions = {\n storefront: StorefrontClient\n /** The store's cookie for the buyer session token (`createCookie('sf_customer', ...)`). */\n customerCookie: AuthCookie\n /** Validates the `next` field before redirecting (default `safeNextPath`). Return a same-site path. */\n safeNext?: (raw: string | null) => string\n /** Where to go after signing in when there is no `next` (default `/account`). Only used by the default `safeNext`. */\n defaultNext?: string\n /** Shopper IP for the per-shopper rate limit (see `clientIp` of the client). */\n clientIp?: (request: Request) => string | null | undefined\n /** Capabilities source, for tests or a shared cache (default `loadAuthCapabilities`). */\n capabilities?: (sf: StorefrontClient) => Promise<CustomerCapabilities>\n}\n\nexport type AuthActionArgs = { request: Request }\n\nconst fail = (code: AuthErrorCode, extra: Partial<AuthActionData> = {}, field?: string): AuthActionData => ({\n ok: false,\n ...extra,\n error: { code, ...(field ? { field } : {}) },\n})\n\n/** Maps what the SDK threw to the error the form shows. `ctx` tells what a 401 means on this step. */\nfunction toFailure(err: unknown, ctx: 'credentials' | 'code' | 'other', extra: Partial<AuthActionData>): AuthActionData {\n if (!isStorefrontError(err)) return fail('unavailable', extra)\n if (err.code === 'insufficient_scope') {\n logMisconfigured(err.requiredScopes)\n return fail('store_misconfigured', extra)\n }\n switch (err.status) {\n case 401:\n return fail(ctx === 'credentials' ? 'invalid_credentials' : ctx === 'code' ? 'invalid_code' : 'unavailable', extra, ctx === 'code' ? 'code' : undefined)\n case 409:\n return fail('email_taken', extra, 'email')\n case 429:\n return fail('rate_limited', extra)\n case 400:\n case 422:\n return fail('validation', extra, err.field)\n case 403:\n case 404:\n return fail('unsupported', extra)\n default:\n return fail('unavailable', extra)\n }\n}\n\n/**\n * The account action: one `POST` form with an `intent` field.\n *\n * | intent | fields | result |\n * | ------------- | ---------------------------------------- | -------------------------------------------------------- |\n * | `login` | email, password | signs in -> redirect |\n * | `register` | email, password, first_name?, last_name? | `step: 'verify'` or, without verification, redirect |\n * | `verify` | email, code | account ready -> redirect |\n * | `otp-request` | email | `step: 'otp'` (code sent) |\n * | `otp-login` | email, code | signs in -> redirect |\n * | `forgot` | email | `step: 'reset'` (always, so it never says who has an account) |\n * | `reset` | email, code, password | new password and signed in -> redirect |\n *\n * Success is a `303` to `next` (validated by `safeNext`) with `Set-Cookie` holding the session token; anything else is\n * an `AuthActionData` to render with `<AccountAuth data={...}>`. Passwords and codes are never echoed back.\n */\nexport function createAuthAction(options: CreateAuthActionOptions) {\n const { storefront: sf, customerCookie } = options\n const safeNext = options.safeNext ?? ((raw: string | null) => safeNextPath(raw, options.defaultNext ?? '/account'))\n const loadCaps = options.capabilities ?? ((client: StorefrontClient) => loadAuthCapabilities(client))\n\n async function signedIn(session: CustomerSession, next: string): Promise<Response> {\n const expires = new Date(session.expires_at)\n const cookie = await customerCookie.serialize(session.token, Number.isNaN(expires.getTime()) ? undefined : { expires })\n return new Response(null, { status: 303, headers: { Location: next, 'Set-Cookie': cookie } })\n }\n\n return async function authAction({ request }: AuthActionArgs): Promise<Response | AuthActionData> {\n const form = await request.formData().catch(() => null)\n if (!form) return fail('validation')\n const text = (name: string) => {\n const v = form.get(name)\n return typeof v === 'string' ? v : ''\n }\n const intent = text('intent') as AuthIntent\n const email = text('email').trim()\n const password = text('password')\n const code = text('code').replace(/\\s+/g, '')\n const next = safeNext(text('next') || null)\n const ip = options.clientIp?.(request)\n const w = ip ? { clientIp: ip } : undefined\n const carry: Partial<AuthActionData> = { email }\n if (!email) return fail('validation', carry, 'email')\n\n const caps = await loadCaps(sf)\n const passwordOn = caps.password\n // Off because the store's token lacks a scope (not a merchant choice): say so instead of \"not available\".\n const misconfigured = caps.unavailable_reason === 'missing_scope'\n const off = (): AuthActionData => fail(misconfigured ? 'store_misconfigured' : 'unsupported', carry)\n const otpOn = caps.otp_channels.includes('email')\n\n try {\n switch (intent) {\n case 'login': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n case 'register': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n const res = await sf.customer.register(\n { email, password, ...(text('first_name').trim() ? { first_name: text('first_name').trim() } : {}), ...(text('last_name').trim() ? { last_name: text('last_name').trim() } : {}) },\n w,\n )\n return res.status === 'created' ? await signedIn(res.session, next) : { ok: true, step: 'verify', email }\n }\n case 'verify': {\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.verifyRegistration({ email, code }, w), next)\n }\n case 'otp-request': {\n if (!otpOn) return off()\n await sf.customer.requestOtp({ email }, w)\n return { ok: true, step: 'otp', email }\n }\n case 'otp-login': {\n if (!otpOn) return off()\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.createSession({ email, code }, w), next)\n }\n case 'forgot': {\n if (!passwordOn || !otpOn) return off()\n try {\n await sf.customer.requestOtp({ email }, w)\n } catch (err) {\n // Only throttling and a bad email are told; anything else looks the same as success (no account enumeration).\n if (isStorefrontError(err) && (err.status === 429 || err.status === 400)) throw err\n }\n return { ok: true, step: 'reset', email }\n }\n case 'reset': {\n if (!passwordOn) return off()\n if (!code) return fail('validation', carry, 'code')\n if (!password) return fail('validation', carry, 'password')\n await sf.customer.resetPassword({ email, code, password }, w)\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n default:\n return fail('validation', carry)\n }\n } catch (err) {\n const step = intent === 'verify' ? 'verify' : intent === 'otp-login' ? 'otp' : intent === 'reset' || intent === 'forgot' ? 'reset' : undefined\n const ctx = intent === 'login' ? 'credentials' : step ? 'code' : 'other'\n return toFailure(err, ctx, step && intent !== 'forgot' ? { ...carry, step } : carry)\n }\n }\n}\n\nexport type AuthAction = ReturnType<typeof createAuthAction>\n\n// ---------------------------------------------------------------------------\n// Resource routes of the order screens: the invoice file and the printable voucher\n// ---------------------------------------------------------------------------\n\n/** Headers every answer of a buyer route carries, error or not: never cached, never sniffed, never rendered as a page. */\nconst LOCKED_HEADERS = {\n 'Cache-Control': 'private, no-store',\n 'X-Content-Type-Options': 'nosniff',\n 'Referrer-Policy': 'no-referrer',\n 'X-Robots-Tag': 'noindex',\n} as const\nconst TEXT_HEADERS = { ...LOCKED_HEADERS, 'Content-Type': 'text/plain; charset=utf-8', 'Content-Security-Policy': \"default-src 'none'; sandbox\" } as const\nconst textResponse = (status: number, body: string, extra: Record<string, string> = {}) => new Response(body, { status, headers: { ...TEXT_HEADERS, ...extra } })\n\n/** Largest invoice file served (a CFDI PDF is well under 1 MB): anything bigger is refused before it is decoded. */\nexport const MAX_INVOICE_FILE_BYTES = 10 * 1024 * 1024\n\n/** Statuses a buyer-facing route answers with; anything unexpected is a plain 502 (never the upstream message). */\nfunction failureResponse(err: unknown): Response {\n if (isStorefrontError(err)) {\n if (err.status === 401) return textResponse(401, 'Sesion vencida')\n if (err.status === 404) return textResponse(404, 'No encontrado')\n if (err.status === 429) {\n const wait = typeof err.retryAfter === 'number' && Number.isFinite(err.retryAfter) && err.retryAfter > 0 ? Math.min(3600, Math.ceil(err.retryAfter)) : null\n return textResponse(429, 'Demasiados intentos', wait ? { 'Retry-After': String(wait) } : {})\n }\n }\n return textResponse(502, 'No pudimos obtener el archivo')\n}\n\nconst FILE_TYPES: Record<string, string> = { pdf: 'application/pdf', xml: 'application/xml' }\n\nexport type InvoiceFileResponseOptions = {\n /** Client WITH the buyer's session (`storefront.withCustomerToken(token)`). */\n storefront: StorefrontClient\n orderId: string\n invoiceId: string\n /** From the URL (`pdf` | `xml`); anything else is a 404. */\n kind: string | undefined\n signal?: AbortSignal\n /** Largest file served, in bytes (default `MAX_INVOICE_FILE_BYTES`, 10 MB); a bigger one is a generic 502. */\n maxBytes?: number\n}\n\n/**\n * Serves one file of an invoice or credit note to the signed-in buyer: the route handler of the store\n * (`account.order.$id.invoice.$doc.$kind.ts`) is `return invoiceFileResponse({ storefront, orderId, invoiceId, kind })`.\n * The buyer's token and any PAC URL stay on the server; the browser gets bytes with `Content-Disposition: attachment`,\n * `Cache-Control: private, no-store`, `nosniff` and a sandboxing CSP. The content type is taken from `kind`, never\n * from what the API says, so a file cannot make the browser render HTML under your origin. 401/404/429 pass through;\n * anything else is a generic 502 with no upstream detail.\n */\nexport async function invoiceFileResponse({ storefront, orderId, invoiceId, kind, signal, maxBytes = MAX_INVOICE_FILE_BYTES }: InvoiceFileResponseOptions): Promise<Response> {\n if (kind !== 'pdf' && kind !== 'xml') return textResponse(404, 'No encontrado')\n if (!orderId || !invoiceId) return textResponse(404, 'No encontrado')\n try {\n const file = await storefront.customer.invoiceFile(orderId, invoiceId, kind, signal ? { signal } : undefined)\n if (!file) return textResponse(404, 'No encontrado')\n // Checked on the encoded text (4 chars per 3 bytes, whitespace aside) so a huge answer is never decoded.\n if (file.content_base64.length > Math.ceil(maxBytes / 3) * 4 * 1.1 + 64) return textResponse(502, 'No pudimos obtener el archivo')\n const bytes = invoiceFileBytes(file)\n if (bytes.byteLength > maxBytes) return textResponse(502, 'No pudimos obtener el archivo')\n const name = safeInvoiceFilename(file.filename, kind === 'pdf' ? 'factura.pdf' : 'factura.xml')\n const filename = name.toLowerCase().endsWith(`.${kind}`) ? name : `${name}.${kind}`\n return new Response(bytes as BodyInit, {\n status: 200,\n headers: {\n 'Content-Type': FILE_TYPES[kind]!,\n 'Content-Length': String(bytes.byteLength),\n 'Content-Disposition': `attachment; filename=\"${filename}\"`,\n ...LOCKED_HEADERS,\n 'Content-Security-Policy': \"default-src 'none'; sandbox\",\n },\n })\n } catch (err) {\n return failureResponse(err)\n }\n}\n\nexport type PendingVoucherResponseOptions = {\n /** Client WITH the buyer's session. */\n storefront: StorefrontClient\n /** Checkout id (`PendingPayment.id`). */\n id: string\n /** `?descargar=1`: deliver it as a file instead of showing it. */\n download?: boolean\n shopName?: string\n locale?: string\n timeZone?: string\n signal?: AbortSignal\n}\n\n/**\n * The printable A4 voucher of a pending payment of the signed-in buyer. Served only when `id` is in HIS list (the list\n * is scoped by buyer in OPS): any other id is a 404. The document is self-contained, so its CSP allows nothing\n * external, only its own print script (with a per-response nonce) and inline styles.\n */\nexport async function pendingVoucherResponse({ storefront, id, download = false, shopName, locale, timeZone, signal }: PendingVoucherResponseOptions): Promise<Response> {\n try {\n const page = await storefront.customer.pendingPayments({ first: 100 }, signal ? { signal } : undefined)\n const item = page.nodes.find((p) => p.id === id)\n const voucher = item ? voucherOf(item) : null\n if (!item || !voucher) return textResponse(404, 'Ficha no encontrada')\n const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(16))))\n const { renderVoucherDocument } = await import('./voucher-document.js')\n const html = renderVoucherDocument(voucher, { ...(shopName ? { shopName } : {}), ...(locale ? { locale } : {}), ...(timeZone ? { timeZone } : {}), printButton: !download, nonce })\n const safeId = id.replace(/[^A-Za-z0-9-]/g, '').slice(0, 8) || 'ficha'\n return new Response(html, {\n status: 200,\n headers: {\n 'Content-Type': 'text/html; charset=utf-8',\n ...LOCKED_HEADERS,\n // The download carries no script, so its policy allows none.\n 'Content-Security-Policy': `default-src 'none'; style-src 'unsafe-inline'; img-src data:; script-src ${download ? \"'none'\" : `'nonce-${nonce}'`}; base-uri 'none'; form-action 'none'; frame-ancestors 'self'`,\n ...(download ? { 'Content-Disposition': `attachment; filename=\"ficha-de-pago-${safeId}.html\"` } : {}),\n },\n })\n } catch (err) {\n return failureResponse(err)\n }\n}\n"]}
|
|
@@ -68,5 +68,45 @@ type AuthActionArgs = {
|
|
|
68
68
|
*/
|
|
69
69
|
declare function createAuthAction(options: CreateAuthActionOptions): ({ request }: AuthActionArgs) => Promise<Response | AuthActionData>;
|
|
70
70
|
type AuthAction = ReturnType<typeof createAuthAction>;
|
|
71
|
+
/** Largest invoice file served (a CFDI PDF is well under 1 MB): anything bigger is refused before it is decoded. */
|
|
72
|
+
declare const MAX_INVOICE_FILE_BYTES: number;
|
|
73
|
+
type InvoiceFileResponseOptions = {
|
|
74
|
+
/** Client WITH the buyer's session (`storefront.withCustomerToken(token)`). */
|
|
75
|
+
storefront: StorefrontClient;
|
|
76
|
+
orderId: string;
|
|
77
|
+
invoiceId: string;
|
|
78
|
+
/** From the URL (`pdf` | `xml`); anything else is a 404. */
|
|
79
|
+
kind: string | undefined;
|
|
80
|
+
signal?: AbortSignal;
|
|
81
|
+
/** Largest file served, in bytes (default `MAX_INVOICE_FILE_BYTES`, 10 MB); a bigger one is a generic 502. */
|
|
82
|
+
maxBytes?: number;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Serves one file of an invoice or credit note to the signed-in buyer: the route handler of the store
|
|
86
|
+
* (`account.order.$id.invoice.$doc.$kind.ts`) is `return invoiceFileResponse({ storefront, orderId, invoiceId, kind })`.
|
|
87
|
+
* The buyer's token and any PAC URL stay on the server; the browser gets bytes with `Content-Disposition: attachment`,
|
|
88
|
+
* `Cache-Control: private, no-store`, `nosniff` and a sandboxing CSP. The content type is taken from `kind`, never
|
|
89
|
+
* from what the API says, so a file cannot make the browser render HTML under your origin. 401/404/429 pass through;
|
|
90
|
+
* anything else is a generic 502 with no upstream detail.
|
|
91
|
+
*/
|
|
92
|
+
declare function invoiceFileResponse({ storefront, orderId, invoiceId, kind, signal, maxBytes }: InvoiceFileResponseOptions): Promise<Response>;
|
|
93
|
+
type PendingVoucherResponseOptions = {
|
|
94
|
+
/** Client WITH the buyer's session. */
|
|
95
|
+
storefront: StorefrontClient;
|
|
96
|
+
/** Checkout id (`PendingPayment.id`). */
|
|
97
|
+
id: string;
|
|
98
|
+
/** `?descargar=1`: deliver it as a file instead of showing it. */
|
|
99
|
+
download?: boolean;
|
|
100
|
+
shopName?: string;
|
|
101
|
+
locale?: string;
|
|
102
|
+
timeZone?: string;
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The printable A4 voucher of a pending payment of the signed-in buyer. Served only when `id` is in HIS list (the list
|
|
107
|
+
* is scoped by buyer in OPS): any other id is a 404. The document is self-contained, so its CSP allows nothing
|
|
108
|
+
* external, only its own print script (with a per-response nonce) and inline styles.
|
|
109
|
+
*/
|
|
110
|
+
declare function pendingVoucherResponse({ storefront, id, download, shopName, locale, timeZone, signal }: PendingVoucherResponseOptions): Promise<Response>;
|
|
71
111
|
|
|
72
|
-
export { type AuthAction, type AuthActionArgs, AuthActionData, type AuthCookie, type CreateAuthActionOptions, type LoadAuthCapabilitiesOptions, SAFE_AUTH_CAPABILITIES, createAuthAction, loadAuthCapabilities, safeNextPath };
|
|
112
|
+
export { type AuthAction, type AuthActionArgs, AuthActionData, type AuthCookie, type CreateAuthActionOptions, type InvoiceFileResponseOptions, type LoadAuthCapabilitiesOptions, MAX_INVOICE_FILE_BYTES, type PendingVoucherResponseOptions, SAFE_AUTH_CAPABILITIES, createAuthAction, invoiceFileResponse, loadAuthCapabilities, pendingVoucherResponse, safeNextPath };
|
package/dist/account-server.d.ts
CHANGED
|
@@ -68,5 +68,45 @@ type AuthActionArgs = {
|
|
|
68
68
|
*/
|
|
69
69
|
declare function createAuthAction(options: CreateAuthActionOptions): ({ request }: AuthActionArgs) => Promise<Response | AuthActionData>;
|
|
70
70
|
type AuthAction = ReturnType<typeof createAuthAction>;
|
|
71
|
+
/** Largest invoice file served (a CFDI PDF is well under 1 MB): anything bigger is refused before it is decoded. */
|
|
72
|
+
declare const MAX_INVOICE_FILE_BYTES: number;
|
|
73
|
+
type InvoiceFileResponseOptions = {
|
|
74
|
+
/** Client WITH the buyer's session (`storefront.withCustomerToken(token)`). */
|
|
75
|
+
storefront: StorefrontClient;
|
|
76
|
+
orderId: string;
|
|
77
|
+
invoiceId: string;
|
|
78
|
+
/** From the URL (`pdf` | `xml`); anything else is a 404. */
|
|
79
|
+
kind: string | undefined;
|
|
80
|
+
signal?: AbortSignal;
|
|
81
|
+
/** Largest file served, in bytes (default `MAX_INVOICE_FILE_BYTES`, 10 MB); a bigger one is a generic 502. */
|
|
82
|
+
maxBytes?: number;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Serves one file of an invoice or credit note to the signed-in buyer: the route handler of the store
|
|
86
|
+
* (`account.order.$id.invoice.$doc.$kind.ts`) is `return invoiceFileResponse({ storefront, orderId, invoiceId, kind })`.
|
|
87
|
+
* The buyer's token and any PAC URL stay on the server; the browser gets bytes with `Content-Disposition: attachment`,
|
|
88
|
+
* `Cache-Control: private, no-store`, `nosniff` and a sandboxing CSP. The content type is taken from `kind`, never
|
|
89
|
+
* from what the API says, so a file cannot make the browser render HTML under your origin. 401/404/429 pass through;
|
|
90
|
+
* anything else is a generic 502 with no upstream detail.
|
|
91
|
+
*/
|
|
92
|
+
declare function invoiceFileResponse({ storefront, orderId, invoiceId, kind, signal, maxBytes }: InvoiceFileResponseOptions): Promise<Response>;
|
|
93
|
+
type PendingVoucherResponseOptions = {
|
|
94
|
+
/** Client WITH the buyer's session. */
|
|
95
|
+
storefront: StorefrontClient;
|
|
96
|
+
/** Checkout id (`PendingPayment.id`). */
|
|
97
|
+
id: string;
|
|
98
|
+
/** `?descargar=1`: deliver it as a file instead of showing it. */
|
|
99
|
+
download?: boolean;
|
|
100
|
+
shopName?: string;
|
|
101
|
+
locale?: string;
|
|
102
|
+
timeZone?: string;
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The printable A4 voucher of a pending payment of the signed-in buyer. Served only when `id` is in HIS list (the list
|
|
107
|
+
* is scoped by buyer in OPS): any other id is a 404. The document is self-contained, so its CSP allows nothing
|
|
108
|
+
* external, only its own print script (with a per-response nonce) and inline styles.
|
|
109
|
+
*/
|
|
110
|
+
declare function pendingVoucherResponse({ storefront, id, download, shopName, locale, timeZone, signal }: PendingVoucherResponseOptions): Promise<Response>;
|
|
71
111
|
|
|
72
|
-
export { type AuthAction, type AuthActionArgs, AuthActionData, type AuthCookie, type CreateAuthActionOptions, type LoadAuthCapabilitiesOptions, SAFE_AUTH_CAPABILITIES, createAuthAction, loadAuthCapabilities, safeNextPath };
|
|
112
|
+
export { type AuthAction, type AuthActionArgs, AuthActionData, type AuthCookie, type CreateAuthActionOptions, type InvoiceFileResponseOptions, type LoadAuthCapabilitiesOptions, MAX_INVOICE_FILE_BYTES, type PendingVoucherResponseOptions, SAFE_AUTH_CAPABILITIES, createAuthAction, invoiceFileResponse, loadAuthCapabilities, pendingVoucherResponse, safeNextPath };
|
package/dist/account-server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { voucherOf } from './chunk-TXEYBDFG.js';
|
|
2
|
+
import { isStorefrontError, invoiceFileBytes, safeInvoiceFilename, repairPath } from '@asteby/storefront';
|
|
2
3
|
|
|
3
|
-
// src/account/server.ts
|
|
4
4
|
var SAFE_AUTH_CAPABILITIES = Object.freeze({
|
|
5
5
|
password: true,
|
|
6
6
|
email_verification: false,
|
|
@@ -174,7 +174,77 @@ function createAuthAction(options) {
|
|
|
174
174
|
}
|
|
175
175
|
};
|
|
176
176
|
}
|
|
177
|
+
var LOCKED_HEADERS = {
|
|
178
|
+
"Cache-Control": "private, no-store",
|
|
179
|
+
"X-Content-Type-Options": "nosniff",
|
|
180
|
+
"Referrer-Policy": "no-referrer",
|
|
181
|
+
"X-Robots-Tag": "noindex"
|
|
182
|
+
};
|
|
183
|
+
var TEXT_HEADERS = { ...LOCKED_HEADERS, "Content-Type": "text/plain; charset=utf-8", "Content-Security-Policy": "default-src 'none'; sandbox" };
|
|
184
|
+
var textResponse = (status, body, extra = {}) => new Response(body, { status, headers: { ...TEXT_HEADERS, ...extra } });
|
|
185
|
+
var MAX_INVOICE_FILE_BYTES = 10 * 1024 * 1024;
|
|
186
|
+
function failureResponse(err) {
|
|
187
|
+
if (isStorefrontError(err)) {
|
|
188
|
+
if (err.status === 401) return textResponse(401, "Sesion vencida");
|
|
189
|
+
if (err.status === 404) return textResponse(404, "No encontrado");
|
|
190
|
+
if (err.status === 429) {
|
|
191
|
+
const wait = typeof err.retryAfter === "number" && Number.isFinite(err.retryAfter) && err.retryAfter > 0 ? Math.min(3600, Math.ceil(err.retryAfter)) : null;
|
|
192
|
+
return textResponse(429, "Demasiados intentos", wait ? { "Retry-After": String(wait) } : {});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return textResponse(502, "No pudimos obtener el archivo");
|
|
196
|
+
}
|
|
197
|
+
var FILE_TYPES = { pdf: "application/pdf", xml: "application/xml" };
|
|
198
|
+
async function invoiceFileResponse({ storefront, orderId, invoiceId, kind, signal, maxBytes = MAX_INVOICE_FILE_BYTES }) {
|
|
199
|
+
if (kind !== "pdf" && kind !== "xml") return textResponse(404, "No encontrado");
|
|
200
|
+
if (!orderId || !invoiceId) return textResponse(404, "No encontrado");
|
|
201
|
+
try {
|
|
202
|
+
const file = await storefront.customer.invoiceFile(orderId, invoiceId, kind, signal ? { signal } : void 0);
|
|
203
|
+
if (!file) return textResponse(404, "No encontrado");
|
|
204
|
+
if (file.content_base64.length > Math.ceil(maxBytes / 3) * 4 * 1.1 + 64) return textResponse(502, "No pudimos obtener el archivo");
|
|
205
|
+
const bytes = invoiceFileBytes(file);
|
|
206
|
+
if (bytes.byteLength > maxBytes) return textResponse(502, "No pudimos obtener el archivo");
|
|
207
|
+
const name = safeInvoiceFilename(file.filename, kind === "pdf" ? "factura.pdf" : "factura.xml");
|
|
208
|
+
const filename = name.toLowerCase().endsWith(`.${kind}`) ? name : `${name}.${kind}`;
|
|
209
|
+
return new Response(bytes, {
|
|
210
|
+
status: 200,
|
|
211
|
+
headers: {
|
|
212
|
+
"Content-Type": FILE_TYPES[kind],
|
|
213
|
+
"Content-Length": String(bytes.byteLength),
|
|
214
|
+
"Content-Disposition": `attachment; filename="${filename}"`,
|
|
215
|
+
...LOCKED_HEADERS,
|
|
216
|
+
"Content-Security-Policy": "default-src 'none'; sandbox"
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
} catch (err) {
|
|
220
|
+
return failureResponse(err);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async function pendingVoucherResponse({ storefront, id, download = false, shopName, locale, timeZone, signal }) {
|
|
224
|
+
try {
|
|
225
|
+
const page = await storefront.customer.pendingPayments({ first: 100 }, signal ? { signal } : void 0);
|
|
226
|
+
const item = page.nodes.find((p) => p.id === id);
|
|
227
|
+
const voucher = item ? voucherOf(item) : null;
|
|
228
|
+
if (!item || !voucher) return textResponse(404, "Ficha no encontrada");
|
|
229
|
+
const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(16))));
|
|
230
|
+
const { renderVoucherDocument } = await import('./voucher-document-SFWJCLTN.js');
|
|
231
|
+
const html = renderVoucherDocument(voucher, { ...shopName ? { shopName } : {}, ...locale ? { locale } : {}, ...timeZone ? { timeZone } : {}, printButton: !download, nonce });
|
|
232
|
+
const safeId = id.replace(/[^A-Za-z0-9-]/g, "").slice(0, 8) || "ficha";
|
|
233
|
+
return new Response(html, {
|
|
234
|
+
status: 200,
|
|
235
|
+
headers: {
|
|
236
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
237
|
+
...LOCKED_HEADERS,
|
|
238
|
+
// The download carries no script, so its policy allows none.
|
|
239
|
+
"Content-Security-Policy": `default-src 'none'; style-src 'unsafe-inline'; img-src data:; script-src ${download ? "'none'" : `'nonce-${nonce}'`}; base-uri 'none'; form-action 'none'; frame-ancestors 'self'`,
|
|
240
|
+
...download ? { "Content-Disposition": `attachment; filename="ficha-de-pago-${safeId}.html"` } : {}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
} catch (err) {
|
|
244
|
+
return failureResponse(err);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
177
247
|
|
|
178
|
-
export { SAFE_AUTH_CAPABILITIES, createAuthAction, loadAuthCapabilities, safeNextPath };
|
|
248
|
+
export { MAX_INVOICE_FILE_BYTES, SAFE_AUTH_CAPABILITIES, createAuthAction, invoiceFileResponse, loadAuthCapabilities, pendingVoucherResponse, safeNextPath };
|
|
179
249
|
//# sourceMappingURL=account-server.js.map
|
|
180
250
|
//# sourceMappingURL=account-server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/account/server.ts"],"names":[],"mappings":"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","file":"account-server.js","sourcesContent":["/**\n * Server side of the account screen (`@asteby/storefront-react/account/server`): `loadAuthCapabilities` for the loader\n * and `createAuthAction` for the action. No React, no router: Web `Request`/`Response` only, so any framework mounts it.\n *\n * The browser never talks to OPS. The action signs the buyer in with the store's `sk_` client and keeps the session\n * token in the store's own cookie, which is passed in (`customerCookie`), so name, flags and signing stay the store's.\n */\nimport { isStorefrontError, repairPath, type CustomerCapabilities, type CustomerSession, type StorefrontClient } from '@asteby/storefront'\nimport type { AuthActionData, AuthErrorCode, AuthIntent } from './types.js'\n\nexport type { AuthActionData, AuthErrorCode, AuthIntent, AuthStep } from './types.js'\n\n/** What is assumed when the store cannot be asked: password sign-in works, nothing else is offered. */\nexport const SAFE_AUTH_CAPABILITIES: Readonly<CustomerCapabilities> = Object.freeze({\n password: true,\n email_verification: false,\n otp_channels: Object.freeze([]) as unknown as CustomerCapabilities['otp_channels'],\n})\n\nconst FAILURE_TTL_MS = 5_000\nconst LOG_EVERY_MS = 60_000\nlet lastLogAt = -Infinity\n\n/** Server log (never the buyer's data): says what is missing and where it is repaired. At most once a minute. */\nfunction logMisconfigured(scopes: readonly string[]): void {\n const t = Date.now()\n if (t - lastLogAt < LOG_EVERY_MS) return\n lastLogAt = t\n console.error(\n `[@asteby/storefront-react] La credencial de la tienda no tiene permisos${scopes.length ? ` (${scopes.join(', ')})` : ''}; ` +\n `las cuentas de comprador no funcionan hasta repararlo en ${repairPath()}.`,\n )\n}\nconst cache = new WeakMap<object, { at: number; ok: boolean; value: CustomerCapabilities }>()\n\nexport type LoadAuthCapabilitiesOptions = {\n /** How long a good answer is reused per client (default 60 s). `0` disables the cache. */\n ttlMs?: number\n signal?: AbortSignal\n /** Clock, for tests. */\n now?: () => number\n}\n\n/**\n * Asks the store which ways of signing in it offers, with a short cache per client. It NEVER throws: when OPS does not\n * answer (older server, outage, token without scope) it returns `SAFE_AUTH_CAPABILITIES` and retries after a few\n * seconds, so the account screen always renders. Use it as the loader: `loader = () => loadAuthCapabilities(storefront)`.\n */\nexport async function loadAuthCapabilities(sf: StorefrontClient, options: LoadAuthCapabilitiesOptions = {}): Promise<CustomerCapabilities> {\n const now = options.now ?? Date.now\n const ttl = options.ttlMs ?? 60_000\n const hit = cache.get(sf)\n if (hit && now() - hit.at < (hit.ok ? ttl : FAILURE_TTL_MS)) return hit.value\n try {\n const got = await sf.customer.capabilities(options.signal ? { signal: options.signal } : undefined)\n const missing = Array.isArray(got?.missing_scopes) ? got.missing_scopes.filter((x): x is string => typeof x === 'string') : []\n const value: CustomerCapabilities = {\n // `password: false` (including for a missing scope) is respected: the form never offers what the token cannot do.\n password: got?.password !== false,\n email_verification: got?.email_verification === true,\n otp_channels: Array.isArray(got?.otp_channels) ? got.otp_channels : [],\n ...(typeof got?.unavailable_reason === 'string' ? { unavailable_reason: got.unavailable_reason } : {}),\n ...(missing.length ? { missing_scopes: missing } : {}),\n }\n if (value.unavailable_reason === 'missing_scope') logMisconfigured(missing)\n cache.set(sf, { at: now(), ok: true, value })\n return value\n } catch (err) {\n if (isStorefrontError(err) && err.code === 'insufficient_scope') {\n // The token cannot even read capabilities: do not offer password sign-in it could not complete.\n const value: CustomerCapabilities = {\n password: false,\n email_verification: false,\n otp_channels: [],\n unavailable_reason: 'missing_scope',\n missing_scopes: err.requiredScopes,\n }\n logMisconfigured(err.requiredScopes)\n cache.set(sf, { at: now(), ok: false, value })\n return value\n }\n cache.set(sf, { at: now(), ok: false, value: SAFE_AUTH_CAPABILITIES })\n return SAFE_AUTH_CAPABILITIES\n }\n}\n\n/** The part of a cookie the action needs. React Router's `createCookie(...)` and Remix's fit as they are. */\nexport type AuthCookie = {\n serialize(value: string, options?: { expires?: Date; maxAge?: number }): string | Promise<string>\n}\n\n/** Allows only a path inside the site (`/account`, `/orders?x=1`); anything else is `fallback`. Blocks `//host` and `/\\host`. */\nexport function safeNextPath(raw: string | null | undefined, fallback = '/account'): string {\n if (typeof raw !== 'string') return fallback\n const v = raw.trim()\n if (!v.startsWith('/') || v.startsWith('//') || v.startsWith('/\\\\') || /[\\u0000-\\u001f\\\\]/.test(v)) return fallback\n return v\n}\n\nexport type CreateAuthActionOptions = {\n storefront: StorefrontClient\n /** The store's cookie for the buyer session token (`createCookie('sf_customer', ...)`). */\n customerCookie: AuthCookie\n /** Validates the `next` field before redirecting (default `safeNextPath`). Return a same-site path. */\n safeNext?: (raw: string | null) => string\n /** Where to go after signing in when there is no `next` (default `/account`). Only used by the default `safeNext`. */\n defaultNext?: string\n /** Shopper IP for the per-shopper rate limit (see `clientIp` of the client). */\n clientIp?: (request: Request) => string | null | undefined\n /** Capabilities source, for tests or a shared cache (default `loadAuthCapabilities`). */\n capabilities?: (sf: StorefrontClient) => Promise<CustomerCapabilities>\n}\n\nexport type AuthActionArgs = { request: Request }\n\nconst fail = (code: AuthErrorCode, extra: Partial<AuthActionData> = {}, field?: string): AuthActionData => ({\n ok: false,\n ...extra,\n error: { code, ...(field ? { field } : {}) },\n})\n\n/** Maps what the SDK threw to the error the form shows. `ctx` tells what a 401 means on this step. */\nfunction toFailure(err: unknown, ctx: 'credentials' | 'code' | 'other', extra: Partial<AuthActionData>): AuthActionData {\n if (!isStorefrontError(err)) return fail('unavailable', extra)\n if (err.code === 'insufficient_scope') {\n logMisconfigured(err.requiredScopes)\n return fail('store_misconfigured', extra)\n }\n switch (err.status) {\n case 401:\n return fail(ctx === 'credentials' ? 'invalid_credentials' : ctx === 'code' ? 'invalid_code' : 'unavailable', extra, ctx === 'code' ? 'code' : undefined)\n case 409:\n return fail('email_taken', extra, 'email')\n case 429:\n return fail('rate_limited', extra)\n case 400:\n case 422:\n return fail('validation', extra, err.field)\n case 403:\n case 404:\n return fail('unsupported', extra)\n default:\n return fail('unavailable', extra)\n }\n}\n\n/**\n * The account action: one `POST` form with an `intent` field.\n *\n * | intent | fields | result |\n * | ------------- | ---------------------------------------- | -------------------------------------------------------- |\n * | `login` | email, password | signs in -> redirect |\n * | `register` | email, password, first_name?, last_name? | `step: 'verify'` or, without verification, redirect |\n * | `verify` | email, code | account ready -> redirect |\n * | `otp-request` | email | `step: 'otp'` (code sent) |\n * | `otp-login` | email, code | signs in -> redirect |\n * | `forgot` | email | `step: 'reset'` (always, so it never says who has an account) |\n * | `reset` | email, code, password | new password and signed in -> redirect |\n *\n * Success is a `303` to `next` (validated by `safeNext`) with `Set-Cookie` holding the session token; anything else is\n * an `AuthActionData` to render with `<AccountAuth data={...}>`. Passwords and codes are never echoed back.\n */\nexport function createAuthAction(options: CreateAuthActionOptions) {\n const { storefront: sf, customerCookie } = options\n const safeNext = options.safeNext ?? ((raw: string | null) => safeNextPath(raw, options.defaultNext ?? '/account'))\n const loadCaps = options.capabilities ?? ((client: StorefrontClient) => loadAuthCapabilities(client))\n\n async function signedIn(session: CustomerSession, next: string): Promise<Response> {\n const expires = new Date(session.expires_at)\n const cookie = await customerCookie.serialize(session.token, Number.isNaN(expires.getTime()) ? undefined : { expires })\n return new Response(null, { status: 303, headers: { Location: next, 'Set-Cookie': cookie } })\n }\n\n return async function authAction({ request }: AuthActionArgs): Promise<Response | AuthActionData> {\n const form = await request.formData().catch(() => null)\n if (!form) return fail('validation')\n const text = (name: string) => {\n const v = form.get(name)\n return typeof v === 'string' ? v : ''\n }\n const intent = text('intent') as AuthIntent\n const email = text('email').trim()\n const password = text('password')\n const code = text('code').replace(/\\s+/g, '')\n const next = safeNext(text('next') || null)\n const ip = options.clientIp?.(request)\n const w = ip ? { clientIp: ip } : undefined\n const carry: Partial<AuthActionData> = { email }\n if (!email) return fail('validation', carry, 'email')\n\n const caps = await loadCaps(sf)\n const passwordOn = caps.password\n // Off because the store's token lacks a scope (not a merchant choice): say so instead of \"not available\".\n const misconfigured = caps.unavailable_reason === 'missing_scope'\n const off = (): AuthActionData => fail(misconfigured ? 'store_misconfigured' : 'unsupported', carry)\n const otpOn = caps.otp_channels.includes('email')\n\n try {\n switch (intent) {\n case 'login': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n case 'register': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n const res = await sf.customer.register(\n { email, password, ...(text('first_name').trim() ? { first_name: text('first_name').trim() } : {}), ...(text('last_name').trim() ? { last_name: text('last_name').trim() } : {}) },\n w,\n )\n return res.status === 'created' ? await signedIn(res.session, next) : { ok: true, step: 'verify', email }\n }\n case 'verify': {\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.verifyRegistration({ email, code }, w), next)\n }\n case 'otp-request': {\n if (!otpOn) return off()\n await sf.customer.requestOtp({ email }, w)\n return { ok: true, step: 'otp', email }\n }\n case 'otp-login': {\n if (!otpOn) return off()\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.createSession({ email, code }, w), next)\n }\n case 'forgot': {\n if (!passwordOn || !otpOn) return off()\n try {\n await sf.customer.requestOtp({ email }, w)\n } catch (err) {\n // Only throttling and a bad email are told; anything else looks the same as success (no account enumeration).\n if (isStorefrontError(err) && (err.status === 429 || err.status === 400)) throw err\n }\n return { ok: true, step: 'reset', email }\n }\n case 'reset': {\n if (!passwordOn) return off()\n if (!code) return fail('validation', carry, 'code')\n if (!password) return fail('validation', carry, 'password')\n await sf.customer.resetPassword({ email, code, password }, w)\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n default:\n return fail('validation', carry)\n }\n } catch (err) {\n const step = intent === 'verify' ? 'verify' : intent === 'otp-login' ? 'otp' : intent === 'reset' || intent === 'forgot' ? 'reset' : undefined\n const ctx = intent === 'login' ? 'credentials' : step ? 'code' : 'other'\n return toFailure(err, ctx, step && intent !== 'forgot' ? { ...carry, step } : carry)\n }\n }\n}\n\nexport type AuthAction = ReturnType<typeof createAuthAction>\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/account/server.ts"],"names":[],"mappings":"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","file":"account-server.js","sourcesContent":["/**\n * Server side of the account screen (`@asteby/storefront-react/account/server`): `loadAuthCapabilities` for the loader\n * and `createAuthAction` for the action. No React, no router: Web `Request`/`Response` only, so any framework mounts it.\n *\n * The browser never talks to OPS. The action signs the buyer in with the store's `sk_` client and keeps the session\n * token in the store's own cookie, which is passed in (`customerCookie`), so name, flags and signing stay the store's.\n */\nimport { invoiceFileBytes, isStorefrontError, repairPath, safeInvoiceFilename, type CustomerCapabilities, type CustomerSession, type StorefrontClient } from '@asteby/storefront'\nimport { voucherOf } from './voucher.js'\nimport type { AuthActionData, AuthErrorCode, AuthIntent } from './types.js'\n\nexport type { AuthActionData, AuthErrorCode, AuthIntent, AuthStep } from './types.js'\n\n/** What is assumed when the store cannot be asked: password sign-in works, nothing else is offered. */\nexport const SAFE_AUTH_CAPABILITIES: Readonly<CustomerCapabilities> = Object.freeze({\n password: true,\n email_verification: false,\n otp_channels: Object.freeze([]) as unknown as CustomerCapabilities['otp_channels'],\n})\n\nconst FAILURE_TTL_MS = 5_000\nconst LOG_EVERY_MS = 60_000\nlet lastLogAt = -Infinity\n\n/** Server log (never the buyer's data): says what is missing and where it is repaired. At most once a minute. */\nfunction logMisconfigured(scopes: readonly string[]): void {\n const t = Date.now()\n if (t - lastLogAt < LOG_EVERY_MS) return\n lastLogAt = t\n console.error(\n `[@asteby/storefront-react] La credencial de la tienda no tiene permisos${scopes.length ? ` (${scopes.join(', ')})` : ''}; ` +\n `las cuentas de comprador no funcionan hasta repararlo en ${repairPath()}.`,\n )\n}\nconst cache = new WeakMap<object, { at: number; ok: boolean; value: CustomerCapabilities }>()\n\nexport type LoadAuthCapabilitiesOptions = {\n /** How long a good answer is reused per client (default 60 s). `0` disables the cache. */\n ttlMs?: number\n signal?: AbortSignal\n /** Clock, for tests. */\n now?: () => number\n}\n\n/**\n * Asks the store which ways of signing in it offers, with a short cache per client. It NEVER throws: when OPS does not\n * answer (older server, outage, token without scope) it returns `SAFE_AUTH_CAPABILITIES` and retries after a few\n * seconds, so the account screen always renders. Use it as the loader: `loader = () => loadAuthCapabilities(storefront)`.\n */\nexport async function loadAuthCapabilities(sf: StorefrontClient, options: LoadAuthCapabilitiesOptions = {}): Promise<CustomerCapabilities> {\n const now = options.now ?? Date.now\n const ttl = options.ttlMs ?? 60_000\n const hit = cache.get(sf)\n if (hit && now() - hit.at < (hit.ok ? ttl : FAILURE_TTL_MS)) return hit.value\n try {\n const got = await sf.customer.capabilities(options.signal ? { signal: options.signal } : undefined)\n const missing = Array.isArray(got?.missing_scopes) ? got.missing_scopes.filter((x): x is string => typeof x === 'string') : []\n const value: CustomerCapabilities = {\n // `password: false` (including for a missing scope) is respected: the form never offers what the token cannot do.\n password: got?.password !== false,\n email_verification: got?.email_verification === true,\n otp_channels: Array.isArray(got?.otp_channels) ? got.otp_channels : [],\n ...(typeof got?.unavailable_reason === 'string' ? { unavailable_reason: got.unavailable_reason } : {}),\n ...(missing.length ? { missing_scopes: missing } : {}),\n }\n if (value.unavailable_reason === 'missing_scope') logMisconfigured(missing)\n cache.set(sf, { at: now(), ok: true, value })\n return value\n } catch (err) {\n if (isStorefrontError(err) && err.code === 'insufficient_scope') {\n // The token cannot even read capabilities: do not offer password sign-in it could not complete.\n const value: CustomerCapabilities = {\n password: false,\n email_verification: false,\n otp_channels: [],\n unavailable_reason: 'missing_scope',\n missing_scopes: err.requiredScopes,\n }\n logMisconfigured(err.requiredScopes)\n cache.set(sf, { at: now(), ok: false, value })\n return value\n }\n cache.set(sf, { at: now(), ok: false, value: SAFE_AUTH_CAPABILITIES })\n return SAFE_AUTH_CAPABILITIES\n }\n}\n\n/** The part of a cookie the action needs. React Router's `createCookie(...)` and Remix's fit as they are. */\nexport type AuthCookie = {\n serialize(value: string, options?: { expires?: Date; maxAge?: number }): string | Promise<string>\n}\n\n/** Allows only a path inside the site (`/account`, `/orders?x=1`); anything else is `fallback`. Blocks `//host` and `/\\host`. */\nexport function safeNextPath(raw: string | null | undefined, fallback = '/account'): string {\n if (typeof raw !== 'string') return fallback\n const v = raw.trim()\n if (!v.startsWith('/') || v.startsWith('//') || v.startsWith('/\\\\') || /[\\u0000-\\u001f\\\\]/.test(v)) return fallback\n return v\n}\n\nexport type CreateAuthActionOptions = {\n storefront: StorefrontClient\n /** The store's cookie for the buyer session token (`createCookie('sf_customer', ...)`). */\n customerCookie: AuthCookie\n /** Validates the `next` field before redirecting (default `safeNextPath`). Return a same-site path. */\n safeNext?: (raw: string | null) => string\n /** Where to go after signing in when there is no `next` (default `/account`). Only used by the default `safeNext`. */\n defaultNext?: string\n /** Shopper IP for the per-shopper rate limit (see `clientIp` of the client). */\n clientIp?: (request: Request) => string | null | undefined\n /** Capabilities source, for tests or a shared cache (default `loadAuthCapabilities`). */\n capabilities?: (sf: StorefrontClient) => Promise<CustomerCapabilities>\n}\n\nexport type AuthActionArgs = { request: Request }\n\nconst fail = (code: AuthErrorCode, extra: Partial<AuthActionData> = {}, field?: string): AuthActionData => ({\n ok: false,\n ...extra,\n error: { code, ...(field ? { field } : {}) },\n})\n\n/** Maps what the SDK threw to the error the form shows. `ctx` tells what a 401 means on this step. */\nfunction toFailure(err: unknown, ctx: 'credentials' | 'code' | 'other', extra: Partial<AuthActionData>): AuthActionData {\n if (!isStorefrontError(err)) return fail('unavailable', extra)\n if (err.code === 'insufficient_scope') {\n logMisconfigured(err.requiredScopes)\n return fail('store_misconfigured', extra)\n }\n switch (err.status) {\n case 401:\n return fail(ctx === 'credentials' ? 'invalid_credentials' : ctx === 'code' ? 'invalid_code' : 'unavailable', extra, ctx === 'code' ? 'code' : undefined)\n case 409:\n return fail('email_taken', extra, 'email')\n case 429:\n return fail('rate_limited', extra)\n case 400:\n case 422:\n return fail('validation', extra, err.field)\n case 403:\n case 404:\n return fail('unsupported', extra)\n default:\n return fail('unavailable', extra)\n }\n}\n\n/**\n * The account action: one `POST` form with an `intent` field.\n *\n * | intent | fields | result |\n * | ------------- | ---------------------------------------- | -------------------------------------------------------- |\n * | `login` | email, password | signs in -> redirect |\n * | `register` | email, password, first_name?, last_name? | `step: 'verify'` or, without verification, redirect |\n * | `verify` | email, code | account ready -> redirect |\n * | `otp-request` | email | `step: 'otp'` (code sent) |\n * | `otp-login` | email, code | signs in -> redirect |\n * | `forgot` | email | `step: 'reset'` (always, so it never says who has an account) |\n * | `reset` | email, code, password | new password and signed in -> redirect |\n *\n * Success is a `303` to `next` (validated by `safeNext`) with `Set-Cookie` holding the session token; anything else is\n * an `AuthActionData` to render with `<AccountAuth data={...}>`. Passwords and codes are never echoed back.\n */\nexport function createAuthAction(options: CreateAuthActionOptions) {\n const { storefront: sf, customerCookie } = options\n const safeNext = options.safeNext ?? ((raw: string | null) => safeNextPath(raw, options.defaultNext ?? '/account'))\n const loadCaps = options.capabilities ?? ((client: StorefrontClient) => loadAuthCapabilities(client))\n\n async function signedIn(session: CustomerSession, next: string): Promise<Response> {\n const expires = new Date(session.expires_at)\n const cookie = await customerCookie.serialize(session.token, Number.isNaN(expires.getTime()) ? undefined : { expires })\n return new Response(null, { status: 303, headers: { Location: next, 'Set-Cookie': cookie } })\n }\n\n return async function authAction({ request }: AuthActionArgs): Promise<Response | AuthActionData> {\n const form = await request.formData().catch(() => null)\n if (!form) return fail('validation')\n const text = (name: string) => {\n const v = form.get(name)\n return typeof v === 'string' ? v : ''\n }\n const intent = text('intent') as AuthIntent\n const email = text('email').trim()\n const password = text('password')\n const code = text('code').replace(/\\s+/g, '')\n const next = safeNext(text('next') || null)\n const ip = options.clientIp?.(request)\n const w = ip ? { clientIp: ip } : undefined\n const carry: Partial<AuthActionData> = { email }\n if (!email) return fail('validation', carry, 'email')\n\n const caps = await loadCaps(sf)\n const passwordOn = caps.password\n // Off because the store's token lacks a scope (not a merchant choice): say so instead of \"not available\".\n const misconfigured = caps.unavailable_reason === 'missing_scope'\n const off = (): AuthActionData => fail(misconfigured ? 'store_misconfigured' : 'unsupported', carry)\n const otpOn = caps.otp_channels.includes('email')\n\n try {\n switch (intent) {\n case 'login': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n case 'register': {\n if (!passwordOn) return off()\n if (!password) return fail('validation', carry, 'password')\n const res = await sf.customer.register(\n { email, password, ...(text('first_name').trim() ? { first_name: text('first_name').trim() } : {}), ...(text('last_name').trim() ? { last_name: text('last_name').trim() } : {}) },\n w,\n )\n return res.status === 'created' ? await signedIn(res.session, next) : { ok: true, step: 'verify', email }\n }\n case 'verify': {\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.verifyRegistration({ email, code }, w), next)\n }\n case 'otp-request': {\n if (!otpOn) return off()\n await sf.customer.requestOtp({ email }, w)\n return { ok: true, step: 'otp', email }\n }\n case 'otp-login': {\n if (!otpOn) return off()\n if (!code) return fail('validation', carry, 'code')\n return await signedIn(await sf.customer.createSession({ email, code }, w), next)\n }\n case 'forgot': {\n if (!passwordOn || !otpOn) return off()\n try {\n await sf.customer.requestOtp({ email }, w)\n } catch (err) {\n // Only throttling and a bad email are told; anything else looks the same as success (no account enumeration).\n if (isStorefrontError(err) && (err.status === 429 || err.status === 400)) throw err\n }\n return { ok: true, step: 'reset', email }\n }\n case 'reset': {\n if (!passwordOn) return off()\n if (!code) return fail('validation', carry, 'code')\n if (!password) return fail('validation', carry, 'password')\n await sf.customer.resetPassword({ email, code, password }, w)\n return await signedIn(await sf.customer.loginWithPassword({ email, password }, w), next)\n }\n default:\n return fail('validation', carry)\n }\n } catch (err) {\n const step = intent === 'verify' ? 'verify' : intent === 'otp-login' ? 'otp' : intent === 'reset' || intent === 'forgot' ? 'reset' : undefined\n const ctx = intent === 'login' ? 'credentials' : step ? 'code' : 'other'\n return toFailure(err, ctx, step && intent !== 'forgot' ? { ...carry, step } : carry)\n }\n }\n}\n\nexport type AuthAction = ReturnType<typeof createAuthAction>\n\n// ---------------------------------------------------------------------------\n// Resource routes of the order screens: the invoice file and the printable voucher\n// ---------------------------------------------------------------------------\n\n/** Headers every answer of a buyer route carries, error or not: never cached, never sniffed, never rendered as a page. */\nconst LOCKED_HEADERS = {\n 'Cache-Control': 'private, no-store',\n 'X-Content-Type-Options': 'nosniff',\n 'Referrer-Policy': 'no-referrer',\n 'X-Robots-Tag': 'noindex',\n} as const\nconst TEXT_HEADERS = { ...LOCKED_HEADERS, 'Content-Type': 'text/plain; charset=utf-8', 'Content-Security-Policy': \"default-src 'none'; sandbox\" } as const\nconst textResponse = (status: number, body: string, extra: Record<string, string> = {}) => new Response(body, { status, headers: { ...TEXT_HEADERS, ...extra } })\n\n/** Largest invoice file served (a CFDI PDF is well under 1 MB): anything bigger is refused before it is decoded. */\nexport const MAX_INVOICE_FILE_BYTES = 10 * 1024 * 1024\n\n/** Statuses a buyer-facing route answers with; anything unexpected is a plain 502 (never the upstream message). */\nfunction failureResponse(err: unknown): Response {\n if (isStorefrontError(err)) {\n if (err.status === 401) return textResponse(401, 'Sesion vencida')\n if (err.status === 404) return textResponse(404, 'No encontrado')\n if (err.status === 429) {\n const wait = typeof err.retryAfter === 'number' && Number.isFinite(err.retryAfter) && err.retryAfter > 0 ? Math.min(3600, Math.ceil(err.retryAfter)) : null\n return textResponse(429, 'Demasiados intentos', wait ? { 'Retry-After': String(wait) } : {})\n }\n }\n return textResponse(502, 'No pudimos obtener el archivo')\n}\n\nconst FILE_TYPES: Record<string, string> = { pdf: 'application/pdf', xml: 'application/xml' }\n\nexport type InvoiceFileResponseOptions = {\n /** Client WITH the buyer's session (`storefront.withCustomerToken(token)`). */\n storefront: StorefrontClient\n orderId: string\n invoiceId: string\n /** From the URL (`pdf` | `xml`); anything else is a 404. */\n kind: string | undefined\n signal?: AbortSignal\n /** Largest file served, in bytes (default `MAX_INVOICE_FILE_BYTES`, 10 MB); a bigger one is a generic 502. */\n maxBytes?: number\n}\n\n/**\n * Serves one file of an invoice or credit note to the signed-in buyer: the route handler of the store\n * (`account.order.$id.invoice.$doc.$kind.ts`) is `return invoiceFileResponse({ storefront, orderId, invoiceId, kind })`.\n * The buyer's token and any PAC URL stay on the server; the browser gets bytes with `Content-Disposition: attachment`,\n * `Cache-Control: private, no-store`, `nosniff` and a sandboxing CSP. The content type is taken from `kind`, never\n * from what the API says, so a file cannot make the browser render HTML under your origin. 401/404/429 pass through;\n * anything else is a generic 502 with no upstream detail.\n */\nexport async function invoiceFileResponse({ storefront, orderId, invoiceId, kind, signal, maxBytes = MAX_INVOICE_FILE_BYTES }: InvoiceFileResponseOptions): Promise<Response> {\n if (kind !== 'pdf' && kind !== 'xml') return textResponse(404, 'No encontrado')\n if (!orderId || !invoiceId) return textResponse(404, 'No encontrado')\n try {\n const file = await storefront.customer.invoiceFile(orderId, invoiceId, kind, signal ? { signal } : undefined)\n if (!file) return textResponse(404, 'No encontrado')\n // Checked on the encoded text (4 chars per 3 bytes, whitespace aside) so a huge answer is never decoded.\n if (file.content_base64.length > Math.ceil(maxBytes / 3) * 4 * 1.1 + 64) return textResponse(502, 'No pudimos obtener el archivo')\n const bytes = invoiceFileBytes(file)\n if (bytes.byteLength > maxBytes) return textResponse(502, 'No pudimos obtener el archivo')\n const name = safeInvoiceFilename(file.filename, kind === 'pdf' ? 'factura.pdf' : 'factura.xml')\n const filename = name.toLowerCase().endsWith(`.${kind}`) ? name : `${name}.${kind}`\n return new Response(bytes as BodyInit, {\n status: 200,\n headers: {\n 'Content-Type': FILE_TYPES[kind]!,\n 'Content-Length': String(bytes.byteLength),\n 'Content-Disposition': `attachment; filename=\"${filename}\"`,\n ...LOCKED_HEADERS,\n 'Content-Security-Policy': \"default-src 'none'; sandbox\",\n },\n })\n } catch (err) {\n return failureResponse(err)\n }\n}\n\nexport type PendingVoucherResponseOptions = {\n /** Client WITH the buyer's session. */\n storefront: StorefrontClient\n /** Checkout id (`PendingPayment.id`). */\n id: string\n /** `?descargar=1`: deliver it as a file instead of showing it. */\n download?: boolean\n shopName?: string\n locale?: string\n timeZone?: string\n signal?: AbortSignal\n}\n\n/**\n * The printable A4 voucher of a pending payment of the signed-in buyer. Served only when `id` is in HIS list (the list\n * is scoped by buyer in OPS): any other id is a 404. The document is self-contained, so its CSP allows nothing\n * external, only its own print script (with a per-response nonce) and inline styles.\n */\nexport async function pendingVoucherResponse({ storefront, id, download = false, shopName, locale, timeZone, signal }: PendingVoucherResponseOptions): Promise<Response> {\n try {\n const page = await storefront.customer.pendingPayments({ first: 100 }, signal ? { signal } : undefined)\n const item = page.nodes.find((p) => p.id === id)\n const voucher = item ? voucherOf(item) : null\n if (!item || !voucher) return textResponse(404, 'Ficha no encontrada')\n const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(16))))\n const { renderVoucherDocument } = await import('./voucher-document.js')\n const html = renderVoucherDocument(voucher, { ...(shopName ? { shopName } : {}), ...(locale ? { locale } : {}), ...(timeZone ? { timeZone } : {}), printButton: !download, nonce })\n const safeId = id.replace(/[^A-Za-z0-9-]/g, '').slice(0, 8) || 'ficha'\n return new Response(html, {\n status: 200,\n headers: {\n 'Content-Type': 'text/html; charset=utf-8',\n ...LOCKED_HEADERS,\n // The download carries no script, so its policy allows none.\n 'Content-Security-Policy': `default-src 'none'; style-src 'unsafe-inline'; img-src data:; script-src ${download ? \"'none'\" : `'nonce-${nonce}'`}; base-uri 'none'; form-action 'none'; frame-ancestors 'self'`,\n ...(download ? { 'Content-Disposition': `attachment; filename=\"ficha-de-pago-${safeId}.html\"` } : {}),\n },\n })\n } catch (err) {\n return failureResponse(err)\n }\n}\n"]}
|