tempest-react-sdk 0.80.0 → 0.82.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 +40 -10
- package/bin/create-tempest-app.e2e.test.mjs +31 -0
- package/bin/create-tempest-app.mjs +11 -1
- package/bin/lib/component/generate.test.mjs +13 -1
- package/bin/lib/doctor/doctor.e2e.test.mjs +29 -0
- package/bin/lib/doctor/vitest.mjs +120 -0
- package/bin/lib/doctor/vitest.test.mjs +139 -0
- package/bin/lib/fs/contain.mjs +7 -0
- package/bin/lib/openapi/escape.mjs +68 -4
- package/bin/lib/openapi/generate.hostile.test.mjs +150 -1
- package/bin/lib/openapi/generate.mjs +78 -13
- package/bin/lib/openapi/generate.test.mjs +13 -1
- package/bin/lib/openapi/pattern-risk.mjs +134 -0
- package/bin/lib/openapi/pattern-risk.test.mjs +45 -0
- package/bin/tempest-gen.test.mjs +100 -0
- package/bin/tempest.mjs +24 -8
- package/dist/access/use-can.cjs +1 -1
- package/dist/access/use-can.cjs.map +1 -1
- package/dist/access/use-can.js +25 -28
- package/dist/access/use-can.js.map +1 -1
- package/dist/auth/create-tempest-auth.cjs +1 -1
- package/dist/auth/create-tempest-auth.cjs.map +1 -1
- package/dist/auth/create-tempest-auth.js +234 -122
- package/dist/auth/create-tempest-auth.js.map +1 -1
- package/dist/auth/session-identity.cjs +2 -0
- package/dist/auth/session-identity.cjs.map +1 -0
- package/dist/auth/session-identity.js +12 -0
- package/dist/auth/session-identity.js.map +1 -0
- package/dist/br/boleto.cjs +1 -1
- package/dist/br/boleto.cjs.map +1 -1
- package/dist/br/boleto.js +2 -1
- package/dist/br/boleto.js.map +1 -1
- package/dist/br.d.ts +22 -3
- package/dist/components/AuthForm/AuthFieldControl.cjs +2 -0
- package/dist/components/AuthForm/AuthFieldControl.cjs.map +1 -0
- package/dist/components/AuthForm/AuthFieldControl.js +85 -0
- package/dist/components/AuthForm/AuthFieldControl.js.map +1 -0
- package/dist/components/AuthForm/AuthForm.cjs +2 -0
- package/dist/components/AuthForm/AuthForm.cjs.map +1 -0
- package/dist/components/AuthForm/AuthForm.js +83 -0
- package/dist/components/AuthForm/AuthForm.js.map +1 -0
- package/dist/components/AuthForm/AuthForm.module.cjs +3 -0
- package/dist/components/AuthForm/AuthForm.module.cjs.map +1 -0
- package/dist/components/AuthForm/AuthForm.module.js +14 -0
- package/dist/components/AuthForm/AuthForm.module.js.map +1 -0
- package/dist/components/AuthForm/AuthLinks.cjs +2 -0
- package/dist/components/AuthForm/AuthLinks.cjs.map +1 -0
- package/dist/components/AuthForm/AuthLinks.js +32 -0
- package/dist/components/AuthForm/AuthLinks.js.map +1 -0
- package/dist/components/AuthForm/ForgotPasswordForm.cjs +2 -0
- package/dist/components/AuthForm/ForgotPasswordForm.cjs.map +1 -0
- package/dist/components/AuthForm/ForgotPasswordForm.js +32 -0
- package/dist/components/AuthForm/ForgotPasswordForm.js.map +1 -0
- package/dist/components/AuthForm/LoginForm.cjs +2 -0
- package/dist/components/AuthForm/LoginForm.cjs.map +1 -0
- package/dist/components/AuthForm/LoginForm.js +39 -0
- package/dist/components/AuthForm/LoginForm.js.map +1 -0
- package/dist/components/AuthForm/ResetPasswordForm.cjs +2 -0
- package/dist/components/AuthForm/ResetPasswordForm.cjs.map +1 -0
- package/dist/components/AuthForm/ResetPasswordForm.js +39 -0
- package/dist/components/AuthForm/ResetPasswordForm.js.map +1 -0
- package/dist/components/AuthForm/SignUpForm.cjs +2 -0
- package/dist/components/AuthForm/SignUpForm.cjs.map +1 -0
- package/dist/components/AuthForm/SignUpForm.js +32 -0
- package/dist/components/AuthForm/SignUpForm.js.map +1 -0
- package/dist/components/AuthForm/auth-defaults.cjs +2 -0
- package/dist/components/AuthForm/auth-defaults.cjs.map +1 -0
- package/dist/components/AuthForm/auth-defaults.js +54 -0
- package/dist/components/AuthForm/auth-defaults.js.map +1 -0
- package/dist/components/AuthForm/auth-schemas.cjs +2 -0
- package/dist/components/AuthForm/auth-schemas.cjs.map +1 -0
- package/dist/components/AuthForm/auth-schemas.js +26 -0
- package/dist/components/AuthForm/auth-schemas.js.map +1 -0
- package/dist/components/AuthPage/AuthPage.cjs +2 -0
- package/dist/components/AuthPage/AuthPage.cjs.map +1 -0
- package/dist/components/AuthPage/AuthPage.js +97 -0
- package/dist/components/AuthPage/AuthPage.js.map +1 -0
- package/dist/components/AuthPage/AuthPage.module.cjs +3 -0
- package/dist/components/AuthPage/AuthPage.module.cjs.map +1 -0
- package/dist/components/AuthPage/AuthPage.module.js +24 -0
- package/dist/components/AuthPage/AuthPage.module.js.map +1 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.cjs +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.js +22 -21
- package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/components/Button/Button.cjs +1 -1
- package/dist/components/Button/Button.cjs.map +1 -1
- package/dist/components/Button/Button.js +41 -40
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Chat/ChatAttachments.cjs +1 -1
- package/dist/components/Chat/ChatAttachments.cjs.map +1 -1
- package/dist/components/Chat/ChatAttachments.js +38 -38
- package/dist/components/FilterBar/filter-apply.cjs +1 -1
- package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
- package/dist/components/FilterBar/filter-apply.js +7 -7
- package/dist/components/Form/Form.cjs +1 -1
- package/dist/components/Form/Form.cjs.map +1 -1
- package/dist/components/Form/Form.js +30 -32
- package/dist/components/Form/Form.js.map +1 -1
- package/dist/components/Layout/Layout.cjs +1 -1
- package/dist/components/Layout/Layout.cjs.map +1 -1
- package/dist/components/Layout/Layout.js +25 -24
- package/dist/components/Layout/Layout.js.map +1 -1
- package/dist/components/Layout/gap.cjs +2 -0
- package/dist/components/Layout/gap.cjs.map +1 -0
- package/dist/components/Layout/gap.js +15 -0
- package/dist/components/Layout/gap.js.map +1 -0
- package/dist/components/NavigationMenu/NavigationMenu.cjs +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.js +71 -70
- package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
- package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
- package/dist/components/Sidebar/Sidebar.js.map +1 -1
- package/dist/components/Sidebar/SidebarEntry.cjs +1 -1
- package/dist/components/Sidebar/SidebarEntry.cjs.map +1 -1
- package/dist/components/Sidebar/SidebarEntry.js +30 -29
- package/dist/components/Sidebar/SidebarEntry.js.map +1 -1
- package/dist/data/create-data-provider.cjs +1 -1
- package/dist/data/create-data-provider.cjs.map +1 -1
- package/dist/data/create-data-provider.js +1 -2
- package/dist/data/create-data-provider.js.map +1 -1
- package/dist/forms/index.js +7 -7
- package/dist/forms/masked-inputs.cjs +1 -1
- package/dist/forms/masked-inputs.cjs.map +1 -1
- package/dist/forms/masked-inputs.js +15 -15
- package/dist/forms/validate-form.cjs +1 -1
- package/dist/forms/validate-form.cjs.map +1 -1
- package/dist/forms/validate-form.js +6 -1
- package/dist/forms/validate-form.js.map +1 -1
- package/dist/forms/zod-resolver.cjs +1 -1
- package/dist/forms/zod-resolver.cjs.map +1 -1
- package/dist/forms/zod-resolver.js +8 -3
- package/dist/forms/zod-resolver.js.map +1 -1
- package/dist/http/api-client.cjs +1 -1
- package/dist/http/api-client.cjs.map +1 -1
- package/dist/http/api-client.js +137 -116
- package/dist/http/api-client.js.map +1 -1
- package/dist/http/credential-scope.cjs +1 -1
- package/dist/http/credential-scope.cjs.map +1 -1
- package/dist/http/credential-scope.js +33 -9
- package/dist/http/credential-scope.js.map +1 -1
- package/dist/http/presigned-post.cjs.map +1 -1
- package/dist/http/presigned-post.js.map +1 -1
- package/dist/http/resumable-upload.cjs +1 -1
- package/dist/http/resumable-upload.cjs.map +1 -1
- package/dist/http/resumable-upload.js +140 -134
- package/dist/http/resumable-upload.js.map +1 -1
- package/dist/http/upload-with-progress.cjs +1 -1
- package/dist/http/upload-with-progress.cjs.map +1 -1
- package/dist/http/upload-with-progress.js +17 -17
- package/dist/http/upload-with-progress.js.map +1 -1
- package/dist/http/use-describe-api-error.cjs +1 -1
- package/dist/http/use-describe-api-error.cjs.map +1 -1
- package/dist/http/use-describe-api-error.js +9 -9
- package/dist/oauth/GoogleSignIn.cjs +1 -1
- package/dist/oauth/GoogleSignIn.cjs.map +1 -1
- package/dist/oauth/GoogleSignIn.js +5 -4
- package/dist/oauth/GoogleSignIn.js.map +1 -1
- package/dist/offline/create-offline-sync.cjs +1 -1
- package/dist/offline/create-offline-sync.cjs.map +1 -1
- package/dist/offline/create-offline-sync.js +108 -68
- package/dist/offline/create-offline-sync.js.map +1 -1
- package/dist/query/offline-persistence.cjs +1 -1
- package/dist/query/offline-persistence.cjs.map +1 -1
- package/dist/query/offline-persistence.js +54 -44
- package/dist/query/offline-persistence.js.map +1 -1
- package/dist/sse/create-event-stream.cjs +1 -1
- package/dist/sse/create-event-stream.cjs.map +1 -1
- package/dist/sse/create-event-stream.js +48 -41
- package/dist/sse/create-event-stream.js.map +1 -1
- package/dist/sse/ticket-event-stream.cjs +1 -1
- package/dist/sse/ticket-event-stream.cjs.map +1 -1
- package/dist/sse/ticket-event-stream.js +48 -19
- package/dist/sse/ticket-event-stream.js.map +1 -1
- package/dist/sse/use-event-stream.cjs +1 -1
- package/dist/sse/use-event-stream.cjs.map +1 -1
- package/dist/sse/use-event-stream.js +19 -14
- package/dist/sse/use-event-stream.js.map +1 -1
- package/dist/styles/AuthForm.css +2 -0
- package/dist/styles/AuthPage.css +2 -0
- package/dist/styles/component/AuthForm.css +9 -0
- package/dist/styles/component/AuthPage.css +29 -0
- package/dist/styles/forms.css +36 -0
- package/dist/styles/manifest.json +63 -0
- package/dist/styles.css +1 -1
- package/dist/sw/background-sync.cjs +1 -1
- package/dist/sw/background-sync.cjs.map +1 -1
- package/dist/sw/background-sync.js +132 -112
- package/dist/sw/background-sync.js.map +1 -1
- package/dist/sw/cache.cjs +1 -1
- package/dist/sw/cache.cjs.map +1 -1
- package/dist/sw/cache.js +36 -30
- package/dist/sw/cache.js.map +1 -1
- package/dist/sw/create-push-handler.cjs +1 -1
- package/dist/sw/create-push-handler.cjs.map +1 -1
- package/dist/sw/create-push-handler.js +20 -10
- package/dist/sw/create-push-handler.js.map +1 -1
- package/dist/sw.d.ts +93 -28
- package/dist/tabular/compact.cjs +1 -1
- package/dist/tabular/compact.cjs.map +1 -1
- package/dist/tabular/compact.js +35 -16
- package/dist/tabular/compact.js.map +1 -1
- package/dist/tabular/manifest.cjs +1 -1
- package/dist/tabular/manifest.cjs.map +1 -1
- package/dist/tabular/manifest.js +33 -15
- package/dist/tabular/manifest.js.map +1 -1
- package/dist/tabular.d.ts +11 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +1057 -83
- package/dist/tempest-react-sdk.js +373 -365
- package/dist/theme/initial-theme.cjs +4 -4
- package/dist/theme/initial-theme.cjs.map +1 -1
- package/dist/theme/initial-theme.js +8 -5
- package/dist/theme/initial-theme.js.map +1 -1
- package/dist/utils/compressed-storage.cjs +1 -1
- package/dist/utils/compressed-storage.cjs.map +1 -1
- package/dist/utils/compressed-storage.js +13 -7
- package/dist/utils/compressed-storage.js.map +1 -1
- package/dist/utils/format.cjs +1 -1
- package/dist/utils/format.cjs.map +1 -1
- package/dist/utils/format.js +25 -25
- package/dist/utils/numbers.cjs +1 -1
- package/dist/utils/numbers.cjs.map +1 -1
- package/dist/utils/numbers.js +7 -7
- package/dist/utils/objects.cjs +1 -1
- package/dist/utils/objects.cjs.map +1 -1
- package/dist/utils/objects.js +13 -7
- package/dist/utils/objects.js.map +1 -1
- package/dist/utils/safe-url.cjs +1 -1
- package/dist/utils/safe-url.cjs.map +1 -1
- package/dist/utils/safe-url.js +4 -1
- package/dist/utils/safe-url.js.map +1 -1
- package/dist/webrtc/peer-mesh.cjs +1 -1
- package/dist/webrtc/peer-mesh.cjs.map +1 -1
- package/dist/webrtc/peer-mesh.js +7 -1
- package/dist/webrtc/peer-mesh.js.map +1 -1
- package/dist/ws/create-web-socket.cjs +1 -1
- package/dist/ws/create-web-socket.cjs.map +1 -1
- package/dist/ws/create-web-socket.js +77 -61
- package/dist/ws/create-web-socket.js.map +1 -1
- package/dist/ws/use-web-socket.cjs +1 -1
- package/dist/ws/use-web-socket.cjs.map +1 -1
- package/dist/ws/use-web-socket.js +4 -3
- package/dist/ws/use-web-socket.js.map +1 -1
- package/package.json +1 -1
- package/template-pwa/src/pwa.tsx +42 -0
- package/template-pwa/src/sw.ts +15 -10
package/dist/br/boleto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boleto.js","names":["BoletoError","message","LEGACY_EPOCH_UTC","CURRENT_EPOCH_UTC","MS_PER_DAY","FATOR_MIN","FATOR_MAX","MOD10_WEIGHTS","MOD11_WEIGHT_FIRST","SEGMENTO_LABELS","SEGMENTO_CNPJ","digits","value","mod10Dac","sum","index","fromRight","product","remainder","mod11Sum","mod11DacCobranca","mod11DacArrecadacao","boletoKind","raw","dayAfter","utc","epochUtcMs","days","boletoDueDate","fator","options","epoch","legacy","current","at","reference","fatorVencimento","base","target","date","campoLivreDate","head","campoLivre","year","month","day","bancoLinha","barcode","field1","field2","field3","arrecadacaoLinha","dac","mod11Selector","line","start","block","readBanco","due","moeda","readArrecadacao","segmento","identificacaoValor","empresaIsCnpj","valorRaw","isMoney","assertBarcodeDv","body","assertIdentificacaoValor","parseCodigoBarras","parseLinhaDigitavel","bancoBarcode","arrecadacaoBarcode","dv","blocks","expected","linhaDigitavelToCodigoBarras","codigoBarrasToLinhaDigitavel","validateBoleto","formatLinhaDigitavel"],"sources":["../../src/br/boleto.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the FEBRABAN spec in one file: the 47-digit linha\n * digitável, the 44-digit barcode, the two layouts (bank slips and arrecadação),\n * modulo-10 and modulo-11 check digits, the base date the due date counts from, and\n * the value scaling. Every piece cross-checks another — the conversion between the\n * two forms is what proves the check digits — so splitting it hides the one property\n * the file exists to guarantee.\n */\n/**\n * A boleto string could not be read, or failed a check digit.\n *\n * Its own class so a scanner screen can tell \"this is not a boleto\" apart from a\n * bug, and so the message can be shown to the operator as-is.\n */\nexport class BoletoError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BoletoError\";\n }\n}\n\n/**\n * The two incompatible layouts that share the 44-digit barcode.\n *\n * `\"banco\"` is the cobrança boleto every bank issues; `\"arrecadacao\"` is the\n * concessionária/tributo slip, which starts with `8` and lays out its 44 digits\n * completely differently — same length, different meaning for every field.\n */\nexport type BoletoKind = \"banco\" | \"arrecadacao\";\n\n/** Which base date the fator de vencimento counts from. See {@link boletoDueDate}. */\nexport type BoletoEpoch = \"auto\" | \"legacy\" | \"current\";\n\n/** Options shared by every parser here. */\nexport interface BoletoOptions {\n /** Fator de vencimento epoch. Default `\"auto\"`. */\n epoch?: BoletoEpoch;\n /** Date `\"auto\"` measures proximity against. Default `new Date()`. */\n reference?: Date;\n}\n\n/** A cobrança boleto — the kind a bank issues against an invoice. */\nexport interface BoletoBanco {\n kind: \"banco\";\n /** 44 digits. */\n codigoBarras: string;\n /** 47 digits. */\n linhaDigitavel: string;\n /** 3-digit bank code in the clearing house, e.g. `\"341\"`. */\n banco: string;\n /** 1 digit. `\"9\"` is BRL; nothing else is in use. */\n moeda: string;\n /** `\"Real\"` for `\"9\"`, `null` for anything else. */\n moedaLabel: string | null;\n /** The general check digit, position 5 of the barcode. */\n dv: string;\n /** Raw 4-digit field. `0` means the boleto carries no due date. */\n fatorVencimento: number;\n /** Due date, or `null` when the fator is `0`. */\n vencimento: Date | null;\n /** Which epoch {@link vencimento} was resolved under. `null` when there is none. */\n vencimentoEpoch: Exclude<BoletoEpoch, \"auto\"> | null;\n /** Reais. `0` when the issuer left the amount for the payer to fill in. */\n valor: number;\n /** 25 digits the issuing bank defines. Not interpretable without its manual. */\n campoLivre: string;\n}\n\n/** An arrecadação/convênio slip — utilities, taxes, traffic fines. */\nexport interface BoletoArrecadacao {\n kind: \"arrecadacao\";\n /** 44 digits, always starting with `8`. */\n codigoBarras: string;\n /** 48 digits, in four blocks of twelve. */\n linhaDigitavel: string;\n /** Position 2. See {@link segmentoLabel}. */\n segmento: number;\n /** Human label, or `null` for a value the layout does not define. */\n segmentoLabel: string | null;\n /** Position 3: `6`/`8` mean real money, `7`/`9` mean a reference quantity. */\n identificacaoValor: number;\n /** Which modulo position 3 selects for the general check digit. */\n dvModulo: 10 | 11;\n /** The general check digit, position 4. */\n dv: string;\n /** Reais, or `null` when position 3 says the field is a reference, not money. */\n valor: number | null;\n /** The raw 11-digit value field, useful when {@link valor} is `null`. */\n valorRaw: string;\n /**\n * Positions 16-19 — the 4-digit code FEBRABAN assigns the company — or, on\n * segmento 6, positions 16-23, which are the first eight CNPJ digits.\n */\n empresa: string;\n /** `true` when {@link empresa} is a CNPJ prefix rather than a FEBRABAN code. */\n empresaIsCnpj: boolean;\n /** 25 digits, or 21 when the CNPJ took four of them. Issuer-defined. */\n campoLivre: string;\n /**\n * Due date read from the first eight digits of the campo livre.\n *\n * The layout says a due date, **if present**, must sit there as `AAAAMMDD` —\n * but the field is optional and nothing marks its presence, so a campo livre\n * that merely looks like a date lands here too. Treat it as a hint for a UI,\n * never as the date a payment settles against.\n */\n vencimentoCampoLivre: Date | null;\n}\n\n/** What the two parsers return. Narrow on `kind`. */\nexport type Boleto = BoletoBanco | BoletoArrecadacao;\n\n/** Base date of the fator de vencimento as FEBRABAN defined it in 1997. */\nconst LEGACY_EPOCH_UTC = Date.UTC(1997, 9, 7);\n\n/**\n * Base date the fator de vencimento restarted from.\n *\n * FEBRABAN communication FB-009/2023: the 4-digit field hit its ceiling of 9999\n * on 2025-02-21 (1997-10-07 + 9999 days), so from 2025-02-22 the counter restarts\n * at 1000 against a new base of 2022-05-29 (2022-05-29 + 1000 days = 2025-02-22).\n */\nconst CURRENT_EPOCH_UTC = Date.UTC(2022, 4, 29);\n\nconst MS_PER_DAY = 86_400_000;\n\n/** First fator FEBRABAN ever put in circulation, in either epoch. */\nconst FATOR_MIN = 1000;\n\n/** Last fator the 4-digit field can hold. */\nconst FATOR_MAX = 9999;\n\nconst MOD10_WEIGHTS = [2, 1] as const;\nconst MOD11_WEIGHT_FIRST = 2;\nconst MOD11_WEIGHT_LAST = 9;\n\nconst SEGMENTO_LABELS: Record<number, string> = {\n 1: \"Prefeituras\",\n 2: \"Saneamento\",\n 3: \"Energia elétrica e gás\",\n 4: \"Telecomunicações\",\n 5: \"Órgãos governamentais\",\n 6: \"Carnes e assemelhados ou empresas identificadas por CNPJ\",\n 7: \"Multas de trânsito\",\n 9: \"Uso exclusivo do banco\",\n};\n\n/** Segmento whose company identifier is a CNPJ prefix instead of a FEBRABAN code. */\nconst SEGMENTO_CNPJ = 6;\n\n/** Digits of a value that may carry the usual dots, spaces and dashes. */\nfunction digits(value: string): string {\n return value.replace(/\\D/g, \"\");\n}\n\n/**\n * DAC módulo 10, FEBRABAN flavour.\n *\n * Multipliers cycle `2, 1, 2, 1, …` from right to left; the **digits** of each\n * product are summed individually (so `6 × 2 = 12` contributes `1 + 2`); the DAC\n * is `10 - (sum mod 10)`, and `0` when that remainder is `0`.\n *\n * Ported from \"Layout Padrão de Arrecadação/Recebimento com Utilização do Código\n * de Barras\", FEBRABAN version 07 (effective 2023-03-01), section 07 — whose own\n * worked example gives `01230067896 → 3`.\n *\n * @param value - Digits only.\n * @returns The check digit, 0-9.\n * @throws {BoletoError} When `value` is empty or holds a non-digit.\n */\nexport function mod10Dac(value: string): number {\n if (!/^\\d+$/.test(value))\n throw new BoletoError(`mod10Dac needs digits, got ${JSON.stringify(value)}.`);\n let sum = 0;\n for (let index = 0; index < value.length; index += 1) {\n const fromRight = value.length - 1 - index;\n const product = Number(value[index]) * MOD10_WEIGHTS[fromRight % MOD10_WEIGHTS.length]!;\n sum += product > 9 ? product - 9 : product;\n }\n const remainder = sum % 10;\n return remainder === 0 ? 0 : 10 - remainder;\n}\n\n/** Sum of `digit × weight` with weights cycling 2…9 from the right. */\nfunction mod11Sum(value: string): number {\n const span = MOD11_WEIGHT_LAST - MOD11_WEIGHT_FIRST + 1;\n let sum = 0;\n for (let index = 0; index < value.length; index += 1) {\n const fromRight = value.length - 1 - index;\n sum += Number(value[index]) * (MOD11_WEIGHT_FIRST + (fromRight % span));\n }\n return sum;\n}\n\n/**\n * DAC módulo 11 for a **cobrança** barcode — position 5 of a bank boleto.\n *\n * Weights cycle `2…9` from right to left, the products are summed whole, and the\n * DAC is `11 - (sum mod 11)`. A remainder of `0`, `1` or `10` would put `11`, `10`\n * or `1` in a one-digit field, and FEBRABAN resolves all three to **`1`**.\n *\n * That last rule is where cobrança and arrecadação disagree — see\n * {@link mod11DacArrecadacao}, which resolves the same remainders to `0`. Using\n * one flavour on the other layout produces a check digit that is wrong exactly\n * 3 times in 11, which is why they are separate functions here.\n *\n * @param value - The 43 digits of the barcode with position 5 removed.\n * @returns The check digit, 1-9.\n * @throws {BoletoError} When `value` is empty or holds a non-digit.\n */\nexport function mod11DacCobranca(value: string): number {\n if (!/^\\d+$/.test(value)) {\n throw new BoletoError(`mod11DacCobranca needs digits, got ${JSON.stringify(value)}.`);\n }\n const remainder = mod11Sum(value) % 11;\n return remainder === 0 || remainder === 1 || remainder === 10 ? 1 : 11 - remainder;\n}\n\n/**\n * DAC módulo 11 for an **arrecadação** barcode — position 4 of a `8…` slip.\n *\n * Same weights and same subtraction as {@link mod11DacCobranca}, but a remainder\n * of `0` or `1` resolves to **`0`**.\n *\n * Ported from the FEBRABAN version 07 layout, section 10, and pinned by that\n * document's own worked example: the 43-digit sequence\n * `8220000215048200974123220154098290108605940` sums to 705, `705 mod 11 = 1`,\n * and the barcode the spec prints carries `0` in position 4.\n *\n * @param value - The 43 digits of the barcode with position 4 removed.\n * @returns The check digit, 0 or 2-9.\n * @throws {BoletoError} When `value` is empty or holds a non-digit.\n */\nexport function mod11DacArrecadacao(value: string): number {\n if (!/^\\d+$/.test(value)) {\n throw new BoletoError(`mod11DacArrecadacao needs digits, got ${JSON.stringify(value)}.`);\n }\n const remainder = mod11Sum(value) % 11;\n return remainder === 0 || remainder === 1 ? 0 : 11 - remainder;\n}\n\n/**\n * Which layout a string is in, without throwing.\n *\n * @param value - A barcode or typed line, masked or not.\n * @returns The layout, or `null` when the length is not 44, 47 or 48.\n */\nexport function boletoKind(value: string): BoletoKind | null {\n const raw = digits(value);\n if (raw.length === 47) return \"banco\";\n if (raw.length === 48) return \"arrecadacao\";\n if (raw.length === 44) return raw.startsWith(\"8\") ? \"arrecadacao\" : \"banco\";\n return null;\n}\n\n/** Local midnight of the calendar day `days` after a UTC epoch. */\nfunction dayAfter(epochUtcMs: number, days: number): Date {\n const utc = new Date(epochUtcMs + days * MS_PER_DAY);\n return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());\n}\n\n/**\n * Resolve a fator de vencimento to a calendar date.\n *\n * The field is four digits of days since a base date, and it has had **two** base\n * dates: 1997-10-07 until the counter saturated at 9999 on 2025-02-21, then\n * 2022-05-29 from 2025-02-22, when FEBRABAN restarted it at 1000.\n *\n * !!! danger \"The two epochs are genuinely ambiguous\"\n * Every fator from 1000 to 9999 has a reading under each base — 1997-10-07\n * gives a date in `2000-07-03 … 2025-02-21`, 2022-05-29 gives one in\n * `2025-02-22 … 2049-10-14`. Nothing in the barcode says which. `\"auto\"`\n * picks whichever lands nearer `reference`, which is right for the case that\n * matters (a slip being paid now) and wrong for an archive sweep. Pass\n * `\"legacy\"` or `\"current\"` when you know.\n *\n * @param fator - The raw 4-digit field as a number. `0` means \"no due date\".\n * @param options - Epoch selection. Default `\"auto\"` against `new Date()`.\n * @returns Local midnight of the due date, or `null` when `fator` is `0`.\n *\n * @example\n * boletoDueDate(1000, { epoch: \"legacy\" }); // 2000-07-03\n * boletoDueDate(1000, { epoch: \"current\" }); // 2025-02-22\n */\nexport function boletoDueDate(\n fator: number,\n options: BoletoOptions = {},\n): { date: Date; epoch: Exclude<BoletoEpoch, \"auto\"> } | null {\n if (fator === 0) return null;\n const { epoch = \"auto\", reference = new Date() } = options;\n\n if (epoch === \"legacy\") return { date: dayAfter(LEGACY_EPOCH_UTC, fator), epoch: \"legacy\" };\n if (epoch === \"current\") return { date: dayAfter(CURRENT_EPOCH_UTC, fator), epoch: \"current\" };\n\n const legacy = dayAfter(LEGACY_EPOCH_UTC, fator);\n if (fator < FATOR_MIN) return { date: legacy, epoch: \"legacy\" };\n const current = dayAfter(CURRENT_EPOCH_UTC, fator);\n const at = reference.getTime();\n return Math.abs(current.getTime() - at) <= Math.abs(legacy.getTime() - at)\n ? { date: current, epoch: \"current\" }\n : { date: legacy, epoch: \"legacy\" };\n}\n\n/**\n * Invert {@link boletoDueDate}: the fator that encodes a due date.\n *\n * @param date - The due date. Only its local calendar day is used.\n * @param epoch - Base date to count from. Default `\"current\"`, the epoch in force\n * since 2025-02-22 and therefore the one a boleto issued today must use.\n * @returns The 4-digit fator.\n * @throws {BoletoError} When the date falls outside the 1000-9999 window of that\n * epoch, because no fator can represent it.\n *\n * @example\n * fatorVencimento(new Date(2025, 1, 22)); // 1000\n */\nexport function fatorVencimento(\n date: Date,\n epoch: Exclude<BoletoEpoch, \"auto\"> = \"current\",\n): number {\n const base = epoch === \"legacy\" ? LEGACY_EPOCH_UTC : CURRENT_EPOCH_UTC;\n const target = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());\n const fator = Math.round((target - base) / MS_PER_DAY);\n if (fator < FATOR_MIN || fator > FATOR_MAX) {\n throw new BoletoError(\n `${date.toISOString().slice(0, 10)} is fator ${fator} under the \"${epoch}\" epoch, ` +\n `outside the ${FATOR_MIN}-${FATOR_MAX} the field holds.`,\n );\n }\n return fator;\n}\n\n/**\n * `AAAAMMDD` at the head of an arrecadação campo livre, when it reads as a date.\n *\n * The caller only ever passes a slice of a validated barcode, so the head is\n * always eight digits; what is not guaranteed is that those digits are a date, and\n * `20260231` has to come back `null` rather than roll into March.\n */\nfunction campoLivreDate(campoLivre: string): Date | null {\n const head = campoLivre.slice(0, 8);\n const year = Number(head.slice(0, 4));\n const month = Number(head.slice(4, 6));\n const day = Number(head.slice(6, 8));\n if (year < 1997 || year > 2099 || month < 1 || month > 12 || day < 1 || day > 31) return null;\n const date = new Date(year, month - 1, day);\n return date.getMonth() === month - 1 && date.getDate() === day ? date : null;\n}\n\n/** Assemble the 47-digit typed line from a validated 44-digit bank barcode. */\nfunction bancoLinha(barcode: string): string {\n const campoLivre = barcode.slice(19);\n const field1 = barcode.slice(0, 4) + campoLivre.slice(0, 5);\n const field2 = campoLivre.slice(5, 15);\n const field3 = campoLivre.slice(15, 25);\n return (\n field1 +\n mod10Dac(field1) +\n field2 +\n mod10Dac(field2) +\n field3 +\n mod10Dac(field3) +\n barcode.slice(4, 5) +\n barcode.slice(5, 19)\n );\n}\n\n/** Assemble the 48-digit typed line from a validated 44-digit arrecadação barcode. */\nfunction arrecadacaoLinha(barcode: string): string {\n const dac = mod11Selector(barcode) === 11 ? mod11DacArrecadacao : mod10Dac;\n let line = \"\";\n for (let start = 0; start < 44; start += 11) {\n const block = barcode.slice(start, start + 11);\n line += block + dac(block);\n }\n return line;\n}\n\n/** Which modulo position 3 of an arrecadação barcode selects. */\nfunction mod11Selector(barcode: string): 10 | 11 {\n return barcode[2] === \"8\" || barcode[2] === \"9\" ? 11 : 10;\n}\n\n/** Read a 44-digit bank barcode, whose general DV has already been checked. */\nfunction readBanco(barcode: string, options: BoletoOptions): BoletoBanco {\n const fator = Number(barcode.slice(5, 9));\n const due = boletoDueDate(fator, options);\n const moeda = barcode.slice(3, 4);\n return {\n kind: \"banco\",\n codigoBarras: barcode,\n linhaDigitavel: bancoLinha(barcode),\n banco: barcode.slice(0, 3),\n moeda,\n moedaLabel: moeda === \"9\" ? \"Real\" : null,\n dv: barcode.slice(4, 5),\n fatorVencimento: fator,\n vencimento: due?.date ?? null,\n vencimentoEpoch: due?.epoch ?? null,\n valor: Number(barcode.slice(9, 19)) / 100,\n campoLivre: barcode.slice(19),\n };\n}\n\n/** Read a 44-digit arrecadação barcode, whose general DV has already been checked. */\nfunction readArrecadacao(barcode: string): BoletoArrecadacao {\n const segmento = Number(barcode[1]);\n const identificacaoValor = Number(barcode[2]);\n const empresaIsCnpj = segmento === SEGMENTO_CNPJ;\n const campoLivre = empresaIsCnpj ? barcode.slice(23) : barcode.slice(19);\n const valorRaw = barcode.slice(4, 15);\n const isMoney = identificacaoValor === 6 || identificacaoValor === 8;\n return {\n kind: \"arrecadacao\",\n codigoBarras: barcode,\n linhaDigitavel: arrecadacaoLinha(barcode),\n segmento,\n segmentoLabel: SEGMENTO_LABELS[segmento] ?? null,\n identificacaoValor,\n dvModulo: mod11Selector(barcode),\n dv: barcode.slice(3, 4),\n valor: isMoney ? Number(valorRaw) / 100 : null,\n valorRaw,\n empresa: empresaIsCnpj ? barcode.slice(15, 23) : barcode.slice(15, 19),\n empresaIsCnpj,\n campoLivre,\n vencimentoCampoLivre: campoLivreDate(campoLivre),\n };\n}\n\n/** Recompute and compare the general check digit of a 44-digit barcode. */\nfunction assertBarcodeDv(barcode: string): void {\n if (barcode.startsWith(\"8\")) {\n const body = barcode.slice(0, 3) + barcode.slice(4);\n const dac = mod11Selector(barcode) === 11 ? mod11DacArrecadacao(body) : mod10Dac(body);\n if (String(dac) !== barcode[3]) {\n throw new BoletoError(\n `Arrecadação check digit is ${barcode[3]}, recomputed ${dac} (módulo ${mod11Selector(barcode)}).`,\n );\n }\n return;\n }\n const dac = mod11DacCobranca(barcode.slice(0, 4) + barcode.slice(5));\n if (String(dac) !== barcode[4]) {\n throw new BoletoError(`Barcode check digit is ${barcode[4]}, recomputed ${dac}.`);\n }\n}\n\n/** Reject an arrecadação barcode whose position 3 is not one of 6, 7, 8, 9. */\nfunction assertIdentificacaoValor(barcode: string): void {\n if (!\"6789\".includes(barcode[2]!)) {\n throw new BoletoError(\n `Position 3 of an arrecadação barcode must be 6, 7, 8 or 9 (identificação do valor), got ${barcode[2]}.`,\n );\n }\n}\n\n/**\n * Read a 44-digit barcode — either layout — into its fields.\n *\n * The first digit picks the layout: `8` is an arrecadação/convênio slip, anything\n * else is a cobrança boleto. They are **not** variants of one format; every field\n * moves. Narrow the result on `kind` before touching it.\n *\n * @param value - 44 digits. Spaces and punctuation are ignored.\n * @param options - Fator de vencimento epoch. See {@link boletoDueDate}.\n * @returns The parsed boleto, with the matching typed line filled in.\n * @throws {BoletoError} On a length other than 44, on a general check digit that\n * does not recompute, or on an arrecadação slip whose position 3 is out of spec.\n *\n * @example\n * const boleto = parseCodigoBarras(scanned);\n * if (boleto.kind === \"banco\") console.log(boleto.valor, boleto.vencimento);\n */\nexport function parseCodigoBarras(value: string, options: BoletoOptions = {}): Boleto {\n const barcode = digits(value);\n if (barcode.length !== 44) {\n throw new BoletoError(\n `A barcode has 44 digits, got ${barcode.length}. ` +\n \"A 47- or 48-digit string is a typed line — use parseLinhaDigitavel.\",\n );\n }\n if (barcode.startsWith(\"8\")) {\n assertIdentificacaoValor(barcode);\n assertBarcodeDv(barcode);\n return readArrecadacao(barcode);\n }\n assertBarcodeDv(barcode);\n return readBanco(barcode, options);\n}\n\n/**\n * Read a typed line — 47 digits for a bank boleto, 48 for an arrecadação slip.\n *\n * Both layouts interleave check digits with the data, so the function rebuilds the\n * 44-digit barcode as it goes and every DV is verified: the three (bank) or four\n * (arrecadação) block digits, plus the general one.\n *\n * @param value - 47 or 48 digits. The usual `.`, ` ` and `-` are ignored.\n * @param options - Fator de vencimento epoch. See {@link boletoDueDate}.\n * @returns The parsed boleto, with the barcode filled in.\n * @throws {BoletoError} On a length other than 47 or 48, or on any check digit\n * that does not recompute.\n *\n * @example\n * const boleto = parseLinhaDigitavel(\"34191.09008 64592.181109 00000.463074 1 84410000002000\");\n */\nexport function parseLinhaDigitavel(value: string, options: BoletoOptions = {}): Boleto {\n const line = digits(value);\n if (line.length === 47) return parseCodigoBarras(bancoBarcode(line), options);\n if (line.length === 48) return parseCodigoBarras(arrecadacaoBarcode(line), options);\n throw new BoletoError(\n `A typed line has 47 digits (bank) or 48 (arrecadação), got ${line.length}. ` +\n \"A 44-digit string is a barcode — use parseCodigoBarras.\",\n );\n}\n\n/** Verify the three field DVs of a 47-digit line and rebuild the barcode. */\nfunction bancoBarcode(line: string): string {\n const fields: [string, string][] = [\n [line.slice(0, 9), line.slice(9, 10)],\n [line.slice(10, 20), line.slice(20, 21)],\n [line.slice(21, 31), line.slice(31, 32)],\n ];\n fields.forEach(([body, dv], index) => {\n const dac = mod10Dac(body);\n if (String(dac) !== dv) {\n throw new BoletoError(\n `Field ${index + 1} check digit is ${dv}, recomputed ${dac} (módulo 10).`,\n );\n }\n });\n return (\n line.slice(0, 4) +\n line.slice(32, 33) +\n line.slice(33, 47) +\n line.slice(4, 9) +\n line.slice(10, 20) +\n line.slice(21, 31)\n );\n}\n\n/** Verify the four block DVs of a 48-digit line and rebuild the barcode. */\nfunction arrecadacaoBarcode(line: string): string {\n const blocks = [0, 12, 24, 36].map((start) => ({\n body: line.slice(start, start + 11),\n dv: line.slice(start + 11, start + 12),\n }));\n const barcode = blocks.map((block) => block.body).join(\"\");\n if (!barcode.startsWith(\"8\")) {\n throw new BoletoError(\n `A 48-digit typed line is an arrecadação slip and must start with 8, got ${barcode[0]}.`,\n );\n }\n assertIdentificacaoValor(barcode);\n const dac = mod11Selector(barcode) === 11 ? mod11DacArrecadacao : mod10Dac;\n blocks.forEach((block, index) => {\n const expected = dac(block.body);\n if (String(expected) !== block.dv) {\n throw new BoletoError(\n `Block ${index + 1} check digit is ${block.dv}, recomputed ${expected} ` +\n `(módulo ${mod11Selector(barcode)}).`,\n );\n }\n });\n return barcode;\n}\n\n/**\n * Convert a typed line to its 44-digit barcode.\n *\n * @param value - 47 or 48 digits.\n * @returns The 44-digit barcode.\n * @throws {BoletoError} On a bad length or a check digit that does not recompute.\n */\nexport function linhaDigitavelToCodigoBarras(value: string): string {\n return parseLinhaDigitavel(value).codigoBarras;\n}\n\n/**\n * Convert a 44-digit barcode to its typed line — 47 digits, or 48 for `8…`.\n *\n * @param value - 44 digits.\n * @returns The typed line, check digits included.\n * @throws {BoletoError} On a bad length or a general check digit that does not\n * recompute.\n */\nexport function codigoBarrasToLinhaDigitavel(value: string): string {\n return parseCodigoBarras(value).linhaDigitavel;\n}\n\n/**\n * Whether a boleto string is internally consistent.\n *\n * Checks every digit the layout can check — the block DVs of a typed line and the\n * general DV in both representations. It says nothing about whether the boleto\n * exists, is registered, or is still payable: only a bank can answer that. What it\n * *does* catch is the common failure, a mistyped or truncated line.\n *\n * @param value - A barcode (44) or typed line (47/48), masked or not.\n * @returns `true` when everything recomputes.\n *\n * @example\n * if (!validateBoleto(input)) setError(\"Confira a linha digitável.\");\n */\nexport function validateBoleto(value: string): boolean {\n try {\n const raw = digits(value);\n if (raw.length === 44) parseCodigoBarras(raw);\n else parseLinhaDigitavel(raw);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Group a typed line the way it is printed, so a human can read it back.\n *\n * 47 digits become `AAABC.CCCCD EEEEE.EEEEEF GGGGG.GGGGGH I JJJJKKKKKKKKKK`;\n * 48 digits become four blocks of twelve. Anything else is returned untouched —\n * this is a display helper, not a validator.\n *\n * @param value - A typed line, masked or not.\n * @returns The grouped string.\n *\n * @example\n * formatLinhaDigitavel(\"34191090086459218110900000463074184410000002000\");\n * // \"34191.09008 64592.181109 00000.463074 1 84410000002000\"\n */\nexport function formatLinhaDigitavel(value: string): string {\n const line = digits(value);\n if (line.length === 47) {\n return [\n `${line.slice(0, 5)}.${line.slice(5, 10)}`,\n `${line.slice(10, 15)}.${line.slice(15, 21)}`,\n `${line.slice(21, 26)}.${line.slice(26, 32)}`,\n line.slice(32, 33),\n line.slice(33),\n ].join(\" \");\n }\n if (line.length === 48) {\n return [0, 12, 24, 36].map((start) => line.slice(start, start + 12)).join(\" \");\n }\n return value;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"boleto.js","names":["BoletoError","message","LEGACY_EPOCH_UTC","CURRENT_EPOCH_UTC","MS_PER_DAY","FATOR_MIN","FATOR_MAX","MOD10_WEIGHTS","MOD11_WEIGHT_FIRST","SEGMENTO_LABELS","SEGMENTO_CNPJ","digits","value","mod10Dac","sum","index","fromRight","product","remainder","mod11Sum","mod11DacCobranca","mod11DacArrecadacao","boletoKind","raw","dayAfter","utc","epochUtcMs","days","boletoDueDate","fator","options","epoch","legacy","current","at","reference","fatorVencimento","base","target","date","campoLivreDate","head","campoLivre","year","month","day","bancoLinha","barcode","field1","field2","field3","arrecadacaoLinha","dac","mod11Selector","line","start","block","readBanco","due","moeda","readArrecadacao","segmento","identificacaoValor","empresaIsCnpj","valorRaw","isMoney","assertBarcodeDv","body","assertIdentificacaoValor","parseCodigoBarras","parseLinhaDigitavel","bancoBarcode","arrecadacaoBarcode","dv","blocks","expected","linhaDigitavelToCodigoBarras","codigoBarrasToLinhaDigitavel","validateBoleto","formatLinhaDigitavel"],"sources":["../../src/br/boleto.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the FEBRABAN spec in one file: the 47-digit linha\n * digitável, the 44-digit barcode, the two layouts (bank slips and arrecadação),\n * modulo-10 and modulo-11 check digits, the base date the due date counts from, and\n * the value scaling. Every piece cross-checks another — the conversion between the\n * two forms is what proves the check digits — so splitting it hides the one property\n * the file exists to guarantee.\n */\n/**\n * A boleto string could not be read, or failed a check digit.\n *\n * Its own class so a scanner screen can tell \"this is not a boleto\" apart from a\n * bug, and so the message can be shown to the operator as-is.\n */\nexport class BoletoError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BoletoError\";\n }\n}\n\n/**\n * The two incompatible layouts that share the 44-digit barcode.\n *\n * `\"banco\"` is the cobrança boleto every bank issues; `\"arrecadacao\"` is the\n * concessionária/tributo slip, which starts with `8` and lays out its 44 digits\n * completely differently — same length, different meaning for every field.\n */\nexport type BoletoKind = \"banco\" | \"arrecadacao\";\n\n/** Which base date the fator de vencimento counts from. See {@link boletoDueDate}. */\nexport type BoletoEpoch = \"auto\" | \"legacy\" | \"current\";\n\n/** Options shared by every parser here. */\nexport interface BoletoOptions {\n /** Fator de vencimento epoch. Default `\"auto\"`. */\n epoch?: BoletoEpoch;\n /** Date `\"auto\"` measures proximity against. Default `new Date()`. */\n reference?: Date;\n}\n\n/** A cobrança boleto — the kind a bank issues against an invoice. */\nexport interface BoletoBanco {\n kind: \"banco\";\n /** 44 digits. */\n codigoBarras: string;\n /** 47 digits. */\n linhaDigitavel: string;\n /** 3-digit bank code in the clearing house, e.g. `\"341\"`. */\n banco: string;\n /** 1 digit. `\"9\"` is BRL; nothing else is in use. */\n moeda: string;\n /** `\"Real\"` for `\"9\"`, `null` for anything else. */\n moedaLabel: string | null;\n /** The general check digit, position 5 of the barcode. */\n dv: string;\n /** Raw 4-digit field. `0` means the boleto carries no due date. */\n fatorVencimento: number;\n /** Due date, or `null` when the fator is `0`. */\n vencimento: Date | null;\n /** Which epoch {@link vencimento} was resolved under. `null` when there is none. */\n vencimentoEpoch: Exclude<BoletoEpoch, \"auto\"> | null;\n /** Reais. `0` when the issuer left the amount for the payer to fill in. */\n valor: number;\n /** 25 digits the issuing bank defines. Not interpretable without its manual. */\n campoLivre: string;\n}\n\n/** An arrecadação/convênio slip — utilities, taxes, traffic fines. */\nexport interface BoletoArrecadacao {\n kind: \"arrecadacao\";\n /** 44 digits, always starting with `8`. */\n codigoBarras: string;\n /** 48 digits, in four blocks of twelve. */\n linhaDigitavel: string;\n /** Position 2. See {@link segmentoLabel}. */\n segmento: number;\n /** Human label, or `null` for a value the layout does not define. */\n segmentoLabel: string | null;\n /** Position 3: `6`/`8` mean real money, `7`/`9` mean a reference quantity. */\n identificacaoValor: number;\n /** Which modulo position 3 selects for the general check digit. */\n dvModulo: 10 | 11;\n /** The general check digit, position 4. */\n dv: string;\n /** Reais, or `null` when position 3 says the field is a reference, not money. */\n valor: number | null;\n /** The raw 11-digit value field, useful when {@link valor} is `null`. */\n valorRaw: string;\n /**\n * Positions 16-19 — the 4-digit code FEBRABAN assigns the company — or, on\n * segmento 6, positions 16-23, which are the first eight CNPJ digits.\n */\n empresa: string;\n /** `true` when {@link empresa} is a CNPJ prefix rather than a FEBRABAN code. */\n empresaIsCnpj: boolean;\n /** 25 digits, or 21 when the CNPJ took four of them. Issuer-defined. */\n campoLivre: string;\n /**\n * Due date read from the first eight digits of the campo livre.\n *\n * The layout says a due date, **if present**, must sit there as `AAAAMMDD` —\n * but the field is optional and nothing marks its presence, so a campo livre\n * that merely looks like a date lands here too. Treat it as a hint for a UI,\n * never as the date a payment settles against.\n */\n vencimentoCampoLivre: Date | null;\n}\n\n/** What the two parsers return. Narrow on `kind`. */\nexport type Boleto = BoletoBanco | BoletoArrecadacao;\n\n/** Base date of the fator de vencimento as FEBRABAN defined it in 1997. */\nconst LEGACY_EPOCH_UTC = Date.UTC(1997, 9, 7);\n\n/**\n * Base date the fator de vencimento restarted from.\n *\n * FEBRABAN communication FB-009/2023: the 4-digit field hit its ceiling of 9999\n * on 2025-02-21 (1997-10-07 + 9999 days), so from 2025-02-22 the counter restarts\n * at 1000 against a new base of 2022-05-29 (2022-05-29 + 1000 days = 2025-02-22).\n */\nconst CURRENT_EPOCH_UTC = Date.UTC(2022, 4, 29);\n\nconst MS_PER_DAY = 86_400_000;\n\n/** First fator FEBRABAN ever put in circulation, in either epoch. */\nconst FATOR_MIN = 1000;\n\n/** Last fator the 4-digit field can hold. */\nconst FATOR_MAX = 9999;\n\nconst MOD10_WEIGHTS = [2, 1] as const;\nconst MOD11_WEIGHT_FIRST = 2;\nconst MOD11_WEIGHT_LAST = 9;\n\nconst SEGMENTO_LABELS: Record<number, string> = {\n 1: \"Prefeituras\",\n 2: \"Saneamento\",\n 3: \"Energia elétrica e gás\",\n 4: \"Telecomunicações\",\n 5: \"Órgãos governamentais\",\n 6: \"Carnes e assemelhados ou empresas identificadas por CNPJ\",\n 7: \"Multas de trânsito\",\n 9: \"Uso exclusivo do banco\",\n};\n\n/** Segmento whose company identifier is a CNPJ prefix instead of a FEBRABAN code. */\nconst SEGMENTO_CNPJ = 6;\n\n/**\n * Digits of a value that may carry the usual dots, spaces and dashes.\n *\n * Every non-digit is dropped, not only `.`, ` ` and `-`, on purpose (#534):\n * a line copied from a PDF arrives with non-breaking spaces, line breaks, tabs\n * or a leading \"Linha digitável:\", and all four parse today — an allowlist of\n * the three usual separators would reject each of them. Surrounding text that\n * carries digits (a value, a due date) changes the length and fails, and a line\n * assembled from scattered digits still has to pass every field DV and the\n * general DV, so the lenient read cannot produce a boleto the text did not hold.\n */\nfunction digits(value: string): string {\n return value.replace(/\\D/g, \"\");\n}\n\n/**\n * DAC módulo 10, FEBRABAN flavour.\n *\n * Multipliers cycle `2, 1, 2, 1, …` from right to left; the **digits** of each\n * product are summed individually (so `6 × 2 = 12` contributes `1 + 2`); the DAC\n * is `10 - (sum mod 10)`, and `0` when that remainder is `0`.\n *\n * Ported from \"Layout Padrão de Arrecadação/Recebimento com Utilização do Código\n * de Barras\", FEBRABAN version 07 (effective 2023-03-01), section 07 — whose own\n * worked example gives `01230067896 → 3`.\n *\n * @param value - Digits only.\n * @returns The check digit, 0-9.\n * @throws {BoletoError} When `value` is empty or holds a non-digit.\n */\nexport function mod10Dac(value: string): number {\n if (!/^\\d+$/.test(value))\n throw new BoletoError(`mod10Dac needs digits, got ${JSON.stringify(value)}.`);\n let sum = 0;\n for (let index = 0; index < value.length; index += 1) {\n const fromRight = value.length - 1 - index;\n const product = Number(value[index]) * MOD10_WEIGHTS[fromRight % MOD10_WEIGHTS.length]!;\n sum += product > 9 ? product - 9 : product;\n }\n const remainder = sum % 10;\n return remainder === 0 ? 0 : 10 - remainder;\n}\n\n/** Sum of `digit × weight` with weights cycling 2…9 from the right. */\nfunction mod11Sum(value: string): number {\n const span = MOD11_WEIGHT_LAST - MOD11_WEIGHT_FIRST + 1;\n let sum = 0;\n for (let index = 0; index < value.length; index += 1) {\n const fromRight = value.length - 1 - index;\n sum += Number(value[index]) * (MOD11_WEIGHT_FIRST + (fromRight % span));\n }\n return sum;\n}\n\n/**\n * DAC módulo 11 for a **cobrança** barcode — position 5 of a bank boleto.\n *\n * Weights cycle `2…9` from right to left, the products are summed whole, and the\n * DAC is `11 - (sum mod 11)`. A remainder of `0`, `1` or `10` would put `11`, `10`\n * or `1` in a one-digit field, and FEBRABAN resolves all three to **`1`**.\n *\n * That last rule is where cobrança and arrecadação disagree — see\n * {@link mod11DacArrecadacao}, which resolves the same remainders to `0`. Using\n * one flavour on the other layout produces a check digit that is wrong exactly\n * 3 times in 11, which is why they are separate functions here.\n *\n * @param value - The 43 digits of the barcode with position 5 removed.\n * @returns The check digit, 1-9.\n * @throws {BoletoError} When `value` is empty or holds a non-digit.\n */\nexport function mod11DacCobranca(value: string): number {\n if (!/^\\d+$/.test(value)) {\n throw new BoletoError(`mod11DacCobranca needs digits, got ${JSON.stringify(value)}.`);\n }\n const remainder = mod11Sum(value) % 11;\n return remainder === 0 || remainder === 1 || remainder === 10 ? 1 : 11 - remainder;\n}\n\n/**\n * DAC módulo 11 for an **arrecadação** barcode — position 4 of a `8…` slip.\n *\n * Same weights and same subtraction as {@link mod11DacCobranca}, but a remainder\n * of `0` or `1` resolves to **`0`**.\n *\n * Ported from the FEBRABAN version 07 layout, section 10, and pinned by that\n * document's own worked example: the 43-digit sequence\n * `8220000215048200974123220154098290108605940` sums to 705, `705 mod 11 = 1`,\n * and the barcode the spec prints carries `0` in position 4.\n *\n * @param value - The 43 digits of the barcode with position 4 removed.\n * @returns The check digit, 0 or 2-9.\n * @throws {BoletoError} When `value` is empty or holds a non-digit.\n */\nexport function mod11DacArrecadacao(value: string): number {\n if (!/^\\d+$/.test(value)) {\n throw new BoletoError(`mod11DacArrecadacao needs digits, got ${JSON.stringify(value)}.`);\n }\n const remainder = mod11Sum(value) % 11;\n return remainder === 0 || remainder === 1 ? 0 : 11 - remainder;\n}\n\n/**\n * Which layout a string is in, without throwing.\n *\n * Length and first digit have to agree: a 47-digit line is cobrança and never\n * starts with `8`, a 48-digit one is arrecadação and always does. A string where\n * they disagree is in neither layout and comes back `null` — the same input\n * {@link parseLinhaDigitavel} rejects, so the two never name different layouts\n * for one string.\n *\n * @param value - A barcode or typed line, masked or not.\n * @returns The layout, or `null` when the length is not 44, 47 or 48, or when a\n * 47-digit line starts with `8` or a 48-digit one does not.\n */\nexport function boletoKind(value: string): BoletoKind | null {\n const raw = digits(value);\n if (raw.length === 47) return raw.startsWith(\"8\") ? null : \"banco\";\n if (raw.length === 48) return raw.startsWith(\"8\") ? \"arrecadacao\" : null;\n if (raw.length === 44) return raw.startsWith(\"8\") ? \"arrecadacao\" : \"banco\";\n return null;\n}\n\n/** Local midnight of the calendar day `days` after a UTC epoch. */\nfunction dayAfter(epochUtcMs: number, days: number): Date {\n const utc = new Date(epochUtcMs + days * MS_PER_DAY);\n return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());\n}\n\n/**\n * Resolve a fator de vencimento to a calendar date.\n *\n * The field is four digits of days since a base date, and it has had **two** base\n * dates: 1997-10-07 until the counter saturated at 9999 on 2025-02-21, then\n * 2022-05-29 from 2025-02-22, when FEBRABAN restarted it at 1000.\n *\n * !!! danger \"The two epochs are genuinely ambiguous\"\n * Every fator from 1000 to 9999 has a reading under each base — 1997-10-07\n * gives a date in `2000-07-03 … 2025-02-21`, 2022-05-29 gives one in\n * `2025-02-22 … 2049-10-14`. Nothing in the barcode says which. `\"auto\"`\n * picks whichever lands nearer `reference`, which is right for the case that\n * matters (a slip being paid now) and wrong for an archive sweep. Pass\n * `\"legacy\"` or `\"current\"` when you know.\n *\n * @param fator - The raw 4-digit field as a number. `0` means \"no due date\".\n * @param options - Epoch selection. Default `\"auto\"` against `new Date()`.\n * @returns Local midnight of the due date, or `null` when `fator` is `0`.\n *\n * @example\n * boletoDueDate(1000, { epoch: \"legacy\" }); // 2000-07-03\n * boletoDueDate(1000, { epoch: \"current\" }); // 2025-02-22\n */\nexport function boletoDueDate(\n fator: number,\n options: BoletoOptions = {},\n): { date: Date; epoch: Exclude<BoletoEpoch, \"auto\"> } | null {\n if (fator === 0) return null;\n const { epoch = \"auto\", reference = new Date() } = options;\n\n if (epoch === \"legacy\") return { date: dayAfter(LEGACY_EPOCH_UTC, fator), epoch: \"legacy\" };\n if (epoch === \"current\") return { date: dayAfter(CURRENT_EPOCH_UTC, fator), epoch: \"current\" };\n\n const legacy = dayAfter(LEGACY_EPOCH_UTC, fator);\n if (fator < FATOR_MIN) return { date: legacy, epoch: \"legacy\" };\n const current = dayAfter(CURRENT_EPOCH_UTC, fator);\n const at = reference.getTime();\n return Math.abs(current.getTime() - at) <= Math.abs(legacy.getTime() - at)\n ? { date: current, epoch: \"current\" }\n : { date: legacy, epoch: \"legacy\" };\n}\n\n/**\n * Invert {@link boletoDueDate}: the fator that encodes a due date.\n *\n * @param date - The due date. Only its local calendar day is used.\n * @param epoch - Base date to count from. Default `\"current\"`, the epoch in force\n * since 2025-02-22 and therefore the one a boleto issued today must use.\n * @returns The 4-digit fator.\n * @throws {BoletoError} When the date falls outside the 1000-9999 window of that\n * epoch, because no fator can represent it.\n *\n * @example\n * fatorVencimento(new Date(2025, 1, 22)); // 1000\n */\nexport function fatorVencimento(\n date: Date,\n epoch: Exclude<BoletoEpoch, \"auto\"> = \"current\",\n): number {\n const base = epoch === \"legacy\" ? LEGACY_EPOCH_UTC : CURRENT_EPOCH_UTC;\n const target = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());\n const fator = Math.round((target - base) / MS_PER_DAY);\n if (fator < FATOR_MIN || fator > FATOR_MAX) {\n throw new BoletoError(\n `${date.toISOString().slice(0, 10)} is fator ${fator} under the \"${epoch}\" epoch, ` +\n `outside the ${FATOR_MIN}-${FATOR_MAX} the field holds.`,\n );\n }\n return fator;\n}\n\n/**\n * `AAAAMMDD` at the head of an arrecadação campo livre, when it reads as a date.\n *\n * The caller only ever passes a slice of a validated barcode, so the head is\n * always eight digits; what is not guaranteed is that those digits are a date, and\n * `20260231` has to come back `null` rather than roll into March.\n */\nfunction campoLivreDate(campoLivre: string): Date | null {\n const head = campoLivre.slice(0, 8);\n const year = Number(head.slice(0, 4));\n const month = Number(head.slice(4, 6));\n const day = Number(head.slice(6, 8));\n if (year < 1997 || year > 2099 || month < 1 || month > 12 || day < 1 || day > 31) return null;\n const date = new Date(year, month - 1, day);\n return date.getMonth() === month - 1 && date.getDate() === day ? date : null;\n}\n\n/** Assemble the 47-digit typed line from a validated 44-digit bank barcode. */\nfunction bancoLinha(barcode: string): string {\n const campoLivre = barcode.slice(19);\n const field1 = barcode.slice(0, 4) + campoLivre.slice(0, 5);\n const field2 = campoLivre.slice(5, 15);\n const field3 = campoLivre.slice(15, 25);\n return (\n field1 +\n mod10Dac(field1) +\n field2 +\n mod10Dac(field2) +\n field3 +\n mod10Dac(field3) +\n barcode.slice(4, 5) +\n barcode.slice(5, 19)\n );\n}\n\n/** Assemble the 48-digit typed line from a validated 44-digit arrecadação barcode. */\nfunction arrecadacaoLinha(barcode: string): string {\n const dac = mod11Selector(barcode) === 11 ? mod11DacArrecadacao : mod10Dac;\n let line = \"\";\n for (let start = 0; start < 44; start += 11) {\n const block = barcode.slice(start, start + 11);\n line += block + dac(block);\n }\n return line;\n}\n\n/** Which modulo position 3 of an arrecadação barcode selects. */\nfunction mod11Selector(barcode: string): 10 | 11 {\n return barcode[2] === \"8\" || barcode[2] === \"9\" ? 11 : 10;\n}\n\n/** Read a 44-digit bank barcode, whose general DV has already been checked. */\nfunction readBanco(barcode: string, options: BoletoOptions): BoletoBanco {\n const fator = Number(barcode.slice(5, 9));\n const due = boletoDueDate(fator, options);\n const moeda = barcode.slice(3, 4);\n return {\n kind: \"banco\",\n codigoBarras: barcode,\n linhaDigitavel: bancoLinha(barcode),\n banco: barcode.slice(0, 3),\n moeda,\n moedaLabel: moeda === \"9\" ? \"Real\" : null,\n dv: barcode.slice(4, 5),\n fatorVencimento: fator,\n vencimento: due?.date ?? null,\n vencimentoEpoch: due?.epoch ?? null,\n valor: Number(barcode.slice(9, 19)) / 100,\n campoLivre: barcode.slice(19),\n };\n}\n\n/** Read a 44-digit arrecadação barcode, whose general DV has already been checked. */\nfunction readArrecadacao(barcode: string): BoletoArrecadacao {\n const segmento = Number(barcode[1]);\n const identificacaoValor = Number(barcode[2]);\n const empresaIsCnpj = segmento === SEGMENTO_CNPJ;\n const campoLivre = empresaIsCnpj ? barcode.slice(23) : barcode.slice(19);\n const valorRaw = barcode.slice(4, 15);\n const isMoney = identificacaoValor === 6 || identificacaoValor === 8;\n return {\n kind: \"arrecadacao\",\n codigoBarras: barcode,\n linhaDigitavel: arrecadacaoLinha(barcode),\n segmento,\n segmentoLabel: SEGMENTO_LABELS[segmento] ?? null,\n identificacaoValor,\n dvModulo: mod11Selector(barcode),\n dv: barcode.slice(3, 4),\n valor: isMoney ? Number(valorRaw) / 100 : null,\n valorRaw,\n empresa: empresaIsCnpj ? barcode.slice(15, 23) : barcode.slice(15, 19),\n empresaIsCnpj,\n campoLivre,\n vencimentoCampoLivre: campoLivreDate(campoLivre),\n };\n}\n\n/** Recompute and compare the general check digit of a 44-digit barcode. */\nfunction assertBarcodeDv(barcode: string): void {\n if (barcode.startsWith(\"8\")) {\n const body = barcode.slice(0, 3) + barcode.slice(4);\n const dac = mod11Selector(barcode) === 11 ? mod11DacArrecadacao(body) : mod10Dac(body);\n if (String(dac) !== barcode[3]) {\n throw new BoletoError(\n `Arrecadação check digit is ${barcode[3]}, recomputed ${dac} (módulo ${mod11Selector(barcode)}).`,\n );\n }\n return;\n }\n const dac = mod11DacCobranca(barcode.slice(0, 4) + barcode.slice(5));\n if (String(dac) !== barcode[4]) {\n throw new BoletoError(`Barcode check digit is ${barcode[4]}, recomputed ${dac}.`);\n }\n}\n\n/** Reject an arrecadação barcode whose position 3 is not one of 6, 7, 8, 9. */\nfunction assertIdentificacaoValor(barcode: string): void {\n if (!\"6789\".includes(barcode[2]!)) {\n throw new BoletoError(\n `Position 3 of an arrecadação barcode must be 6, 7, 8 or 9 (identificação do valor), got ${barcode[2]}.`,\n );\n }\n}\n\n/**\n * Read a 44-digit barcode — either layout — into its fields.\n *\n * The first digit picks the layout: `8` is an arrecadação/convênio slip, anything\n * else is a cobrança boleto. They are **not** variants of one format; every field\n * moves. Narrow the result on `kind` before touching it.\n *\n * @param value - 44 digits. Spaces and punctuation are ignored.\n * @param options - Fator de vencimento epoch. See {@link boletoDueDate}.\n * @returns The parsed boleto, with the matching typed line filled in.\n * @throws {BoletoError} On a length other than 44, on a general check digit that\n * does not recompute, or on an arrecadação slip whose position 3 is out of spec.\n *\n * @example\n * const boleto = parseCodigoBarras(scanned);\n * if (boleto.kind === \"banco\") console.log(boleto.valor, boleto.vencimento);\n */\nexport function parseCodigoBarras(value: string, options: BoletoOptions = {}): Boleto {\n const barcode = digits(value);\n if (barcode.length !== 44) {\n throw new BoletoError(\n `A barcode has 44 digits, got ${barcode.length}. ` +\n \"A 47- or 48-digit string is a typed line — use parseLinhaDigitavel.\",\n );\n }\n if (barcode.startsWith(\"8\")) {\n assertIdentificacaoValor(barcode);\n assertBarcodeDv(barcode);\n return readArrecadacao(barcode);\n }\n assertBarcodeDv(barcode);\n return readBanco(barcode, options);\n}\n\n/**\n * Read a typed line — 47 digits for a bank boleto, 48 for an arrecadação slip.\n *\n * Both layouts interleave check digits with the data, so the function rebuilds the\n * 44-digit barcode as it goes and every DV is verified: the three (bank) or four\n * (arrecadação) block digits, plus the general one.\n *\n * The length fixes the layout, and the first digit has to agree with it. A\n * 47-digit line starting with `8` is rejected rather than read: its first three\n * digits would be a bank code `8xx`, but the 44-digit barcode it rebuilds starts\n * with `8` too, and in the barcode that digit is what marks an arrecadação slip —\n * {@link parseCodigoBarras}, and any reader that only sees the barcode, would read\n * it as arrecadação. Before this check\n * `81600000090000000000000000000190900000000000000` passed every field DV, came\n * back as `kind: \"arrecadacao\"` with `valor` 900000000 and a 48-digit line, while\n * the cobrança reading of the same digits is bank 816 with `valor` 0 (#529). No\n * single reading is right for both forms, so neither is returned.\n *\n * @param value - 47 or 48 digits. The usual `.`, ` ` and `-` are ignored.\n * @param options - Fator de vencimento epoch. See {@link boletoDueDate}.\n * @returns The parsed boleto, with the barcode filled in.\n * @throws {BoletoError} On a length other than 47 or 48, on a 47-digit line that\n * starts with `8` or a 48-digit one that does not, or on any check digit that does\n * not recompute.\n *\n * @example\n * const boleto = parseLinhaDigitavel(\"34191.09008 64592.181109 00000.463074 1 84410000002000\");\n */\nexport function parseLinhaDigitavel(value: string, options: BoletoOptions = {}): Boleto {\n const line = digits(value);\n if (line.length === 47) return parseCodigoBarras(bancoBarcode(line), options);\n if (line.length === 48) return parseCodigoBarras(arrecadacaoBarcode(line), options);\n throw new BoletoError(\n `A typed line has 47 digits (bank) or 48 (arrecadação), got ${line.length}. ` +\n \"A 44-digit string is a barcode — use parseCodigoBarras.\",\n );\n}\n\n/** Verify the three field DVs of a 47-digit line and rebuild the barcode. */\nfunction bancoBarcode(line: string): string {\n if (line.startsWith(\"8\")) {\n throw new BoletoError(\n \"A 47-digit typed line is a bank boleto and cannot start with 8: \" +\n \"its barcode would read as an arrecadação slip.\",\n );\n }\n const fields: [string, string][] = [\n [line.slice(0, 9), line.slice(9, 10)],\n [line.slice(10, 20), line.slice(20, 21)],\n [line.slice(21, 31), line.slice(31, 32)],\n ];\n fields.forEach(([body, dv], index) => {\n const dac = mod10Dac(body);\n if (String(dac) !== dv) {\n throw new BoletoError(\n `Field ${index + 1} check digit is ${dv}, recomputed ${dac} (módulo 10).`,\n );\n }\n });\n return (\n line.slice(0, 4) +\n line.slice(32, 33) +\n line.slice(33, 47) +\n line.slice(4, 9) +\n line.slice(10, 20) +\n line.slice(21, 31)\n );\n}\n\n/** Verify the four block DVs of a 48-digit line and rebuild the barcode. */\nfunction arrecadacaoBarcode(line: string): string {\n const blocks = [0, 12, 24, 36].map((start) => ({\n body: line.slice(start, start + 11),\n dv: line.slice(start + 11, start + 12),\n }));\n const barcode = blocks.map((block) => block.body).join(\"\");\n if (!barcode.startsWith(\"8\")) {\n throw new BoletoError(\n `A 48-digit typed line is an arrecadação slip and must start with 8, got ${barcode[0]}.`,\n );\n }\n assertIdentificacaoValor(barcode);\n const dac = mod11Selector(barcode) === 11 ? mod11DacArrecadacao : mod10Dac;\n blocks.forEach((block, index) => {\n const expected = dac(block.body);\n if (String(expected) !== block.dv) {\n throw new BoletoError(\n `Block ${index + 1} check digit is ${block.dv}, recomputed ${expected} ` +\n `(módulo ${mod11Selector(barcode)}).`,\n );\n }\n });\n return barcode;\n}\n\n/**\n * Convert a typed line to its 44-digit barcode.\n *\n * @param value - 47 or 48 digits.\n * @returns The 44-digit barcode.\n * @throws {BoletoError} On a bad length or a check digit that does not recompute.\n */\nexport function linhaDigitavelToCodigoBarras(value: string): string {\n return parseLinhaDigitavel(value).codigoBarras;\n}\n\n/**\n * Convert a 44-digit barcode to its typed line — 47 digits, or 48 for `8…`.\n *\n * @param value - 44 digits.\n * @returns The typed line, check digits included.\n * @throws {BoletoError} On a bad length or a general check digit that does not\n * recompute.\n */\nexport function codigoBarrasToLinhaDigitavel(value: string): string {\n return parseCodigoBarras(value).linhaDigitavel;\n}\n\n/**\n * Whether a boleto string is internally consistent.\n *\n * Checks every digit the layout can check — the block DVs of a typed line and the\n * general DV in both representations. It says nothing about whether the boleto\n * exists, is registered, or is still payable: only a bank can answer that. What it\n * *does* catch is the common failure, a mistyped or truncated line.\n *\n * @param value - A barcode (44) or typed line (47/48), masked or not.\n * @returns `true` when everything recomputes.\n *\n * @example\n * if (!validateBoleto(input)) setError(\"Confira a linha digitável.\");\n */\nexport function validateBoleto(value: string): boolean {\n try {\n const raw = digits(value);\n if (raw.length === 44) parseCodigoBarras(raw);\n else parseLinhaDigitavel(raw);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Group a typed line the way it is printed, so a human can read it back.\n *\n * 47 digits become `AAABC.CCCCD EEEEE.EEEEEF GGGGG.GGGGGH I JJJJKKKKKKKKKK`;\n * 48 digits become four blocks of twelve. Anything else is returned untouched —\n * this is a display helper, not a validator.\n *\n * @param value - A typed line, masked or not.\n * @returns The grouped string.\n *\n * @example\n * formatLinhaDigitavel(\"34191090086459218110900000463074184410000002000\");\n * // \"34191.09008 64592.181109 00000.463074 1 84410000002000\"\n */\nexport function formatLinhaDigitavel(value: string): string {\n const line = digits(value);\n if (line.length === 47) {\n return [\n `${line.slice(0, 5)}.${line.slice(5, 10)}`,\n `${line.slice(10, 15)}.${line.slice(15, 21)}`,\n `${line.slice(21, 26)}.${line.slice(26, 32)}`,\n line.slice(32, 33),\n line.slice(33),\n ].join(\" \");\n }\n if (line.length === 48) {\n return [0, 12, 24, 36].map((start) => line.slice(start, start + 12)).join(\" \");\n }\n return value;\n}\n"],"mappings":";AAcA,IAAaA,IAAb,cAAiC,MAAM;CACnC,YAAY,GAAiB;EAEzB,AADA,MAAMC,CAAO,GACb,KAAK,OAAO;CAChB;AACJ,GA8FMC,IAAmB,KAAK,IAAI,MAAM,GAAG,CAAC,GAStCC,IAAoB,KAAK,IAAI,MAAM,GAAG,EAAE,GAExCC,IAAa,OAGbC,IAAY,KAGZC,IAAY,MAEZC,IAAgB,CAAC,GAAG,CAAC,GACrBC,IAAqB,GAGrBC,IAA0C;CAC5C,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACP,GAGMC,IAAgB;AAatB,SAASC,EAAO,GAAuB;CACnC,OAAOC,EAAM,QAAQ,OAAO,EAAE;AAClC;AAiBA,SAAgBC,EAAS,GAAuB;CAC5C,IAAI,CAAC,QAAQ,KAAKD,CAAK,GACnB,MAAM,IAAIZ,EAAY,8BAA8B,KAAK,UAAUY,CAAK,EAAE,EAAE;CAChF,IAAIE,IAAM;CACV,KAAK,IAAIC,IAAQ,GAAGA,IAAQH,EAAM,QAAQ,KAAS,GAAG;EAClD,IAAMI,IAAYJ,EAAM,SAAS,IAAIG,GAC/BE,IAAU,OAAOL,EAAMG,EAAM,IAAIR,EAAcS,IAAYT,EAAc;EAC/E,KAAOU,IAAU,IAAIA,IAAU,IAAIA;CACvC;CACA,IAAMC,IAAYJ,IAAM;CACxB,OAAOI,MAAc,IAAI,IAAI,KAAKA;AACtC;AAGA,SAASC,EAAS,GAAuB;CACrC,IACIL,IAAM;CACV,KAAK,IAAIC,IAAQ,GAAGA,IAAQH,EAAM,QAAQ,KAAS,GAAG;EAClD,IAAMI,IAAYJ,EAAM,SAAS,IAAIG;EACrC,KAAO,OAAOH,EAAMG,EAAM,KAAKP,IAAsBQ,IAAY;CACrE;CACA,OAAOF;AACX;AAkBA,SAAgBM,EAAiB,GAAuB;CACpD,IAAI,CAAC,QAAQ,KAAKR,CAAK,GACnB,MAAM,IAAIZ,EAAY,sCAAsC,KAAK,UAAUY,CAAK,EAAE,EAAE;CAExF,IAAMM,IAAYC,EAASP,CAAK,IAAI;CACpC,OAAOM,MAAc,KAAKA,MAAc,KAAKA,MAAc,KAAK,IAAI,KAAKA;AAC7E;AAiBA,SAAgBG,EAAoB,GAAuB;CACvD,IAAI,CAAC,QAAQ,KAAKT,CAAK,GACnB,MAAM,IAAIZ,EAAY,yCAAyC,KAAK,UAAUY,CAAK,EAAE,EAAE;CAE3F,IAAMM,IAAYC,EAASP,CAAK,IAAI;CACpC,OAAOM,MAAc,KAAKA,MAAc,IAAI,IAAI,KAAKA;AACzD;AAeA,SAAgBI,EAAW,GAAkC;CACzD,IAAMC,IAAMZ,EAAOC,CAAK;CAIxB,OAHIW,EAAI,WAAW,KAAWA,EAAI,WAAW,GAAG,IAAI,OAAO,UACvDA,EAAI,WAAW,KAAWA,EAAI,WAAW,GAAG,IAAI,gBAAgB,OAChEA,EAAI,WAAW,KAAWA,EAAI,WAAW,GAAG,IAAI,gBAAgB,UAC7D;AACX;AAGA,SAASC,EAAS,GAAoB,GAAoB;CACtD,IAAMC,IAAM,IAAI,KAAKC,IAAaC,IAAOvB,CAAU;CACnD,OAAO,IAAI,KAAKqB,EAAI,eAAe,GAAGA,EAAI,YAAY,GAAGA,EAAI,WAAW,CAAC;AAC7E;AAyBA,SAAgBG,EACZ,GACA,IAAyB,CAAC,GACgC;CAC1D,IAAIC,MAAU,GAAG,OAAO;CACxB,IAAM,EAAE,WAAQ,QAAQ,+BAAY,IAAI,KAAK,MAAMC;CAEnD,IAAIC,MAAU,UAAU,OAAO;EAAE,MAAMP,EAAStB,GAAkB2B,CAAK;EAAG,OAAO;CAAS;CAC1F,IAAIE,MAAU,WAAW,OAAO;EAAE,MAAMP,EAASrB,GAAmB0B,CAAK;EAAG,OAAO;CAAU;CAE7F,IAAMG,IAASR,EAAStB,GAAkB2B,CAAK;CAC/C,IAAIA,IAAQxB,GAAW,OAAO;EAAE,MAAM2B;EAAQ,OAAO;CAAS;CAC9D,IAAMC,IAAUT,EAASrB,GAAmB0B,CAAK,GAC3CK,IAAKC,EAAU,QAAQ;CAC7B,OAAO,KAAK,IAAIF,EAAQ,QAAQ,IAAIC,CAAE,KAAK,KAAK,IAAIF,EAAO,QAAQ,IAAIE,CAAE,IACnE;EAAE,MAAMD;EAAS,OAAO;CAAU,IAClC;EAAE,MAAMD;EAAQ,OAAO;CAAS;AAC1C;AAeA,SAAgBI,EACZ,GACA,IAAsC,WAChC;CACN,IAAMC,IAAON,MAAU,WAAW7B,IAAmBC,GAC/CmC,IAAS,KAAK,IAAIC,EAAK,YAAY,GAAGA,EAAK,SAAS,GAAGA,EAAK,QAAQ,CAAC,GACrEV,IAAQ,KAAK,OAAOS,IAASD,KAAQjC,CAAU;CACrD,IAAIyB,IAAQxB,KAAawB,IAAQvB,GAC7B,MAAM,IAAIN,EACN,GAAGuC,EAAK,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE,EAAE,YAAYV,EAAM,cAAcE,EAAM,uBACtD1B,EAAU,GAAGC,EAAU,kBAC9C;CAEJ,OAAOuB;AACX;AASA,SAASW,EAAe,GAAiC;CACrD,IAAMC,IAAOC,EAAW,MAAM,GAAG,CAAC,GAC5BC,IAAO,OAAOF,EAAK,MAAM,GAAG,CAAC,CAAC,GAC9BG,IAAQ,OAAOH,EAAK,MAAM,GAAG,CAAC,CAAC,GAC/BI,IAAM,OAAOJ,EAAK,MAAM,GAAG,CAAC,CAAC;CACnC,IAAIE,IAAO,QAAQA,IAAO,QAAQC,IAAQ,KAAKA,IAAQ,MAAMC,IAAM,KAAKA,IAAM,IAAI,OAAO;CACzF,IAAMN,IAAO,IAAI,KAAKI,GAAMC,IAAQ,GAAGC,CAAG;CAC1C,OAAON,EAAK,SAAS,MAAMK,IAAQ,KAAKL,EAAK,QAAQ,MAAMM,IAAMN,IAAO;AAC5E;AAGA,SAASO,EAAW,GAAyB;CACzC,IAAMJ,IAAaK,EAAQ,MAAM,EAAE,GAC7BC,IAASD,EAAQ,MAAM,GAAG,CAAC,IAAIL,EAAW,MAAM,GAAG,CAAC,GACpDO,IAASP,EAAW,MAAM,GAAG,EAAE,GAC/BQ,IAASR,EAAW,MAAM,IAAI,EAAE;CACtC,OACIM,IACAnC,EAASmC,CAAM,IACfC,IACApC,EAASoC,CAAM,IACfC,IACArC,EAASqC,CAAM,IACfH,EAAQ,MAAM,GAAG,CAAC,IAClBA,EAAQ,MAAM,GAAG,EAAE;AAE3B;AAGA,SAASI,EAAiB,GAAyB;CAC/C,IAAMC,IAAMC,EAAcN,CAAO,MAAM,KAAK1B,IAAsBR,GAC9DyC,IAAO;CACX,KAAK,IAAIC,IAAQ,GAAGA,IAAQ,IAAI,KAAS,IAAI;EACzC,IAAMC,IAAQT,EAAQ,MAAMQ,GAAOA,IAAQ,EAAE;EAC7C,KAAQC,IAAQJ,EAAII,CAAK;CAC7B;CACA,OAAOF;AACX;AAGA,SAASD,EAAc,GAA0B;CAC7C,OAAON,EAAQ,OAAO,OAAOA,EAAQ,OAAO,MAAM,KAAK;AAC3D;AAGA,SAASU,EAAU,GAAiB,GAAqC;CACrE,IAAM5B,IAAQ,OAAOkB,EAAQ,MAAM,GAAG,CAAC,CAAC,GAClCW,IAAM9B,EAAcC,GAAOC,CAAO,GAClC6B,IAAQZ,EAAQ,MAAM,GAAG,CAAC;CAChC,OAAO;EACH,MAAM;EACN,cAAcA;EACd,gBAAgBD,EAAWC,CAAO;EAClC,OAAOA,EAAQ,MAAM,GAAG,CAAC;EACzB;EACA,YAAYY,MAAU,MAAM,SAAS;EACrC,IAAIZ,EAAQ,MAAM,GAAG,CAAC;EACtB,iBAAiBlB;EACjB,YAAY6B,GAAK,QAAQ;EACzB,iBAAiBA,GAAK,SAAS;EAC/B,OAAO,OAAOX,EAAQ,MAAM,GAAG,EAAE,CAAC,IAAI;EACtC,YAAYA,EAAQ,MAAM,EAAE;CAChC;AACJ;AAGA,SAASa,EAAgB,GAAoC;CACzD,IAAMC,IAAW,OAAOd,EAAQ,EAAE,GAC5Be,IAAqB,OAAOf,EAAQ,EAAE,GACtCgB,IAAgBF,MAAanD,GAC7BgC,IAAaqB,IAAgBhB,EAAQ,MAAM,EAAE,IAAIA,EAAQ,MAAM,EAAE,GACjEiB,IAAWjB,EAAQ,MAAM,GAAG,EAAE,GAC9BkB,IAAUH,MAAuB,KAAKA,MAAuB;CACnE,OAAO;EACH,MAAM;EACN,cAAcf;EACd,gBAAgBI,EAAiBJ,CAAO;EACxC;EACA,eAAetC,EAAgBoD,MAAa;EAC5C;EACA,UAAUR,EAAcN,CAAO;EAC/B,IAAIA,EAAQ,MAAM,GAAG,CAAC;EACtB,OAAOkB,IAAU,OAAOD,CAAQ,IAAI,MAAM;EAC1C;EACA,SAASD,IAAgBhB,EAAQ,MAAM,IAAI,EAAE,IAAIA,EAAQ,MAAM,IAAI,EAAE;EACrE;EACA;EACA,sBAAsBP,EAAeE,CAAU;CACnD;AACJ;AAGA,SAASwB,EAAgB,GAAuB;CAC5C,IAAInB,EAAQ,WAAW,GAAG,GAAG;EACzB,IAAMoB,IAAOpB,EAAQ,MAAM,GAAG,CAAC,IAAIA,EAAQ,MAAM,CAAC,GAC5CK,IAAMC,EAAcN,CAAO,MAAM,KAAK1B,EAAoB8C,CAAI,IAAItD,EAASsD,CAAI;EACrF,IAAI,OAAOf,CAAG,MAAML,EAAQ,IACxB,MAAM,IAAI/C,EACN,8BAA8B+C,EAAQ,GAAG,eAAeK,EAAI,WAAWC,EAAcN,CAAO,EAAE,GAClG;EAEJ;CACJ;CACA,IAAMK,IAAMhC,EAAiB2B,EAAQ,MAAM,GAAG,CAAC,IAAIA,EAAQ,MAAM,CAAC,CAAC;CACnE,IAAI,OAAOK,CAAG,MAAML,EAAQ,IACxB,MAAM,IAAI/C,EAAY,0BAA0B+C,EAAQ,GAAG,eAAeK,EAAI,EAAE;AAExF;AAGA,SAASgB,EAAyB,GAAuB;CACrD,IAAI,CAAC,OAAO,SAASrB,EAAQ,EAAG,GAC5B,MAAM,IAAI/C,EACN,2FAA2F+C,EAAQ,GAAG,EAC1G;AAER;AAmBA,SAAgBsB,EAAkB,GAAe,IAAyB,CAAC,GAAW;CAClF,IAAMtB,IAAUpC,EAAOC,CAAK;CAC5B,IAAImC,EAAQ,WAAW,IACnB,MAAM,IAAI/C,EACN,gCAAgC+C,EAAQ,OAAO,sEAEnD;CAQJ,OANIA,EAAQ,WAAW,GAAG,KACtBqB,EAAyBrB,CAAO,GAChCmB,EAAgBnB,CAAO,GAChBa,EAAgBb,CAAO,MAElCmB,EAAgBnB,CAAO,GAChBU,EAAUV,GAASjB,CAAO;AACrC;AA8BA,SAAgBwC,EAAoB,GAAe,IAAyB,CAAC,GAAW;CACpF,IAAMhB,IAAO3C,EAAOC,CAAK;CACzB,IAAI0C,EAAK,WAAW,IAAI,OAAOe,EAAkBE,EAAajB,CAAI,GAAGxB,CAAO;CAC5E,IAAIwB,EAAK,WAAW,IAAI,OAAOe,EAAkBG,EAAmBlB,CAAI,GAAGxB,CAAO;CAClF,MAAM,IAAI9B,EACN,8DAA8DsD,EAAK,OAAO,0DAE9E;AACJ;AAGA,SAASiB,EAAa,GAAsB;CACxC,IAAIjB,EAAK,WAAW,GAAG,GACnB,MAAM,IAAItD,EACN,gHAEJ;CAeJ,OARA;EAJI,CAACsD,EAAK,MAAM,GAAG,CAAC,GAAGA,EAAK,MAAM,GAAG,EAAE,CAAC;EACpC,CAACA,EAAK,MAAM,IAAI,EAAE,GAAGA,EAAK,MAAM,IAAI,EAAE,CAAC;EACvC,CAACA,EAAK,MAAM,IAAI,EAAE,GAAGA,EAAK,MAAM,IAAI,EAAE,CAAC;CAE3C,CAAA,CAAO,SAAS,CAACa,GAAMM,IAAK,MAAU;EAClC,IAAMrB,IAAMvC,EAASsD,CAAI;EACzB,IAAI,OAAOf,CAAG,MAAMqB,GAChB,MAAM,IAAIzE,EACN,SAASe,IAAQ,EAAE,kBAAkB0D,EAAG,eAAerB,EAAI,cAC/D;CAER,CAAC,GAEGE,EAAK,MAAM,GAAG,CAAC,IACfA,EAAK,MAAM,IAAI,EAAE,IACjBA,EAAK,MAAM,IAAI,EAAE,IACjBA,EAAK,MAAM,GAAG,CAAC,IACfA,EAAK,MAAM,IAAI,EAAE,IACjBA,EAAK,MAAM,IAAI,EAAE;AAEzB;AAGA,SAASkB,EAAmB,GAAsB;CAC9C,IAAME,IAAS;EAAC;EAAG;EAAI;EAAI;CAAE,CAAC,CAAC,KAAK,OAAW;EAC3C,MAAMpB,EAAK,MAAMC,GAAOA,IAAQ,EAAE;EAClC,IAAID,EAAK,MAAMC,IAAQ,IAAIA,IAAQ,EAAE;CACzC,EAAE,GACIR,IAAU2B,EAAO,KAAK,MAAUlB,EAAM,IAAI,CAAC,CAAC,KAAK,EAAE;CACzD,IAAI,CAACT,EAAQ,WAAW,GAAG,GACvB,MAAM,IAAI/C,EACN,2EAA2E+C,EAAQ,GAAG,EAC1F;CAEJ,EAAyBA,CAAO;CAChC,IAAMK,IAAMC,EAAcN,CAAO,MAAM,KAAK1B,IAAsBR;CAUlE,OATA6D,EAAO,SAAS,GAAO,MAAU;EAC7B,IAAMC,IAAWvB,EAAII,EAAM,IAAI;EAC/B,IAAI,OAAOmB,CAAQ,MAAMnB,EAAM,IAC3B,MAAM,IAAIxD,EACN,SAASe,IAAQ,EAAE,kBAAkByC,EAAM,GAAG,eAAemB,EAAS,WACvDtB,EAAcN,CAAO,EAAE,GAC1C;CAER,CAAC,GACMA;AACX;AASA,SAAgB6B,EAA6B,GAAuB;CAChE,OAAON,EAAoB1D,CAAK,CAAC,CAAC;AACtC;AAUA,SAAgBiE,EAA6B,GAAuB;CAChE,OAAOR,EAAkBzD,CAAK,CAAC,CAAC;AACpC;AAgBA,SAAgBkE,EAAe,GAAwB;CACnD,IAAI;EACA,IAAMvD,IAAMZ,EAAOC,CAAK;EAGxB,OAFIW,EAAI,WAAW,KAAI8C,EAAkB9C,CAAG,IACvC+C,EAAoB/C,CAAG,GACrB;CACX,QAAQ;EACJ,OAAO;CACX;AACJ;AAgBA,SAAgBwD,EAAqB,GAAuB;CACxD,IAAMzB,IAAO3C,EAAOC,CAAK;CAazB,OAZI0C,EAAK,WAAW,KACT;EACH,GAAGA,EAAK,MAAM,GAAG,CAAC,EAAE,GAAGA,EAAK,MAAM,GAAG,EAAE;EACvC,GAAGA,EAAK,MAAM,IAAI,EAAE,EAAE,GAAGA,EAAK,MAAM,IAAI,EAAE;EAC1C,GAAGA,EAAK,MAAM,IAAI,EAAE,EAAE,GAAGA,EAAK,MAAM,IAAI,EAAE;EAC1CA,EAAK,MAAM,IAAI,EAAE;EACjBA,EAAK,MAAM,EAAE;CACjB,CAAC,CAAC,KAAK,GAAG,IAEVA,EAAK,WAAW,KACT;EAAC;EAAG;EAAI;EAAI;CAAE,CAAC,CAAC,KAAK,MAAUA,EAAK,MAAMC,GAAOA,IAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,IAE1E3C;AACX"}
|
package/dist/br.d.ts
CHANGED
|
@@ -166,8 +166,15 @@ export declare type BoletoKind = "banco" | "arrecadacao";
|
|
|
166
166
|
/**
|
|
167
167
|
* Which layout a string is in, without throwing.
|
|
168
168
|
*
|
|
169
|
+
* Length and first digit have to agree: a 47-digit line is cobrança and never
|
|
170
|
+
* starts with `8`, a 48-digit one is arrecadação and always does. A string where
|
|
171
|
+
* they disagree is in neither layout and comes back `null` — the same input
|
|
172
|
+
* {@link parseLinhaDigitavel} rejects, so the two never name different layouts
|
|
173
|
+
* for one string.
|
|
174
|
+
*
|
|
169
175
|
* @param value - A barcode or typed line, masked or not.
|
|
170
|
-
* @returns The layout, or `null` when the length is not 44, 47 or 48
|
|
176
|
+
* @returns The layout, or `null` when the length is not 44, 47 or 48, or when a
|
|
177
|
+
* 47-digit line starts with `8` or a 48-digit one does not.
|
|
171
178
|
*/
|
|
172
179
|
export declare function boletoKind(value: string): BoletoKind | null;
|
|
173
180
|
|
|
@@ -1143,11 +1150,23 @@ export declare function parseCodigoBarras(value: string, options?: BoletoOptions
|
|
|
1143
1150
|
* 44-digit barcode as it goes and every DV is verified: the three (bank) or four
|
|
1144
1151
|
* (arrecadação) block digits, plus the general one.
|
|
1145
1152
|
*
|
|
1153
|
+
* The length fixes the layout, and the first digit has to agree with it. A
|
|
1154
|
+
* 47-digit line starting with `8` is rejected rather than read: its first three
|
|
1155
|
+
* digits would be a bank code `8xx`, but the 44-digit barcode it rebuilds starts
|
|
1156
|
+
* with `8` too, and in the barcode that digit is what marks an arrecadação slip —
|
|
1157
|
+
* {@link parseCodigoBarras}, and any reader that only sees the barcode, would read
|
|
1158
|
+
* it as arrecadação. Before this check
|
|
1159
|
+
* `81600000090000000000000000000190900000000000000` passed every field DV, came
|
|
1160
|
+
* back as `kind: "arrecadacao"` with `valor` 900000000 and a 48-digit line, while
|
|
1161
|
+
* the cobrança reading of the same digits is bank 816 with `valor` 0 (#529). No
|
|
1162
|
+
* single reading is right for both forms, so neither is returned.
|
|
1163
|
+
*
|
|
1146
1164
|
* @param value - 47 or 48 digits. The usual `.`, ` ` and `-` are ignored.
|
|
1147
1165
|
* @param options - Fator de vencimento epoch. See {@link boletoDueDate}.
|
|
1148
1166
|
* @returns The parsed boleto, with the barcode filled in.
|
|
1149
|
-
* @throws {BoletoError} On a length other than 47 or 48,
|
|
1150
|
-
* that does not
|
|
1167
|
+
* @throws {BoletoError} On a length other than 47 or 48, on a 47-digit line that
|
|
1168
|
+
* starts with `8` or a 48-digit one that does not, or on any check digit that does
|
|
1169
|
+
* not recompute.
|
|
1151
1170
|
*
|
|
1152
1171
|
* @example
|
|
1153
1172
|
* const boleto = parseLinhaDigitavel("34191.09008 64592.181109 00000.463074 1 84410000002000");
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../Checkbox/Checkbox.cjs"),t=require("../ErrorText/ErrorText.cjs"),n=require("../Input/Input.cjs"),r=require("../PasswordInput/PasswordInput.cjs"),i=require("../PinInput/PinInput.cjs"),a=require("../../forms/FormField.cjs"),o=require("../../forms/masked-inputs.cjs");let s=require("react"),c=require("react/jsx-runtime"),l=require("react-hook-form");var u={email:`email`,password:`current-password`,phone:`tel`};function d(e){let t=e.autoComplete??u[e.type??`text`],a={placeholder:e.placeholder,autoComplete:t};switch(e.type){case`password`:return(0,c.jsx)(r.PasswordInput,{...a,showStrength:e.showStrength});case`phone`:return(0,c.jsx)(o.PhoneInput,{...a});case`cpf`:return(0,c.jsx)(o.CPFInput,{...a});case`cnpj`:return(0,c.jsx)(o.CNPJInput,{...a});case`pin`:return(0,c.jsx)(i.PinInput,{length:e.length});case`email`:return(0,c.jsx)(n.Input,{...a,type:`email`,inputMode:`email`});default:return(0,c.jsx)(n.Input,{...a,type:`text`})}}function f({config:n}){let r=(0,s.useId)();return(0,c.jsx)(l.Controller,{name:n.name,render:({field:i,fieldState:a})=>(0,c.jsxs)(`div`,{children:[(0,c.jsx)(e.Checkbox,{ref:i.ref,name:i.name,checked:!!i.value,onChange:e=>i.onChange(e.target.checked),onBlur:i.onBlur,label:n.label,description:a.error?void 0:n.helperText,required:n.required,"aria-invalid":a.error?!0:void 0,"aria-describedby":a.error?r:void 0}),(0,c.jsx)(t.ErrorText,{id:r,children:a.error?.message})]})})}function p({config:e}){let{control:t}=(0,l.useFormContext)(),{render:n}=e;return n?(0,c.jsx)(l.Controller,{name:e.name,control:t,render:({field:t,fieldState:r})=>(0,c.jsx)(c.Fragment,{children:n({field:t,fieldState:r,error:r.error?.message,config:e})})}):e.type===`checkbox`?(0,c.jsx)(f,{config:e}):(0,c.jsx)(a.FormField,{name:e.name,label:e.label,helperText:e.helperText,required:e.required,children:d(e)})}exports.AuthFieldControl=p;
|
|
2
|
+
//# sourceMappingURL=AuthFieldControl.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthFieldControl.cjs","names":["PasswordInput","PhoneInput","CPFInput","CNPJInput","PinInput","Input","useId","Controller","Checkbox","ErrorText","useFormContext","_Fragment","FormField","require_Checkbox","require_ErrorText","require_Input","require_PasswordInput","require_PinInput","require_FormField","require_masked_inputs","react","react_jsx_runtime","react_hook_form","AUTOCOMPLETE","controlFor","autoComplete","config","shared","CheckboxField","errorId","field","event","fieldState","AuthFieldControl","render"],"sources":["../../../src/components/AuthForm/AuthFieldControl.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { Controller, useFormContext } from \"react-hook-form\";\nimport { Checkbox } from \"@/components/Checkbox\";\nimport { ErrorText } from \"@/components/ErrorText\";\nimport { Input } from \"@/components/Input\";\nimport { PasswordInput } from \"@/components/PasswordInput\";\nimport { PinInput } from \"@/components/PinInput\";\nimport { FormField } from \"@/forms/FormField\";\nimport { CNPJInput, CPFInput, PhoneInput } from \"@/forms/masked-inputs\";\nimport type { AuthField } from \"./types\";\n\n/**\n * Default `autocomplete` token per field type.\n *\n * These are what password managers and mobile keyboards key on; a login form\n * without them is the one where the saved password never gets offered.\n */\nconst AUTOCOMPLETE: Partial<Record<NonNullable<AuthField[\"type\"]>, string>> = {\n email: \"email\",\n password: \"current-password\",\n phone: \"tel\",\n};\n\n/**\n * Build the SDK control for a value-typed field.\n *\n * Returned bare, without value or handlers: `FormField` clones it with the\n * react-hook-form binding, the label and the error.\n *\n * @param config - The field's config entry.\n * @returns The control element.\n */\nfunction controlFor(config: AuthField): ReactElement {\n const autoComplete = config.autoComplete ?? AUTOCOMPLETE[config.type ?? \"text\"];\n const shared = { placeholder: config.placeholder, autoComplete };\n switch (config.type) {\n case \"password\":\n return <PasswordInput {...shared} showStrength={config.showStrength} />;\n case \"phone\":\n return <PhoneInput {...shared} />;\n case \"cpf\":\n return <CPFInput {...shared} />;\n case \"cnpj\":\n return <CNPJInput {...shared} />;\n case \"pin\":\n return <PinInput length={config.length} />;\n case \"email\":\n return <Input {...shared} type=\"email\" inputMode=\"email\" />;\n default:\n return <Input {...shared} type=\"text\" />;\n }\n}\n\n/**\n * A checkbox bound to a boolean value, with its error under it.\n *\n * Not routed through `FormField`, which hands the control `value`: a checkbox\n * is driven by `checked`, and `Checkbox` has no error slot of its own.\n *\n * @param props - The field's config entry.\n * @returns The bound checkbox.\n */\nfunction CheckboxField({ config }: { config: AuthField }): ReactNode {\n const errorId = useId();\n return (\n <Controller\n name={config.name}\n render={({ field, fieldState }) => (\n <div>\n <Checkbox\n ref={field.ref}\n name={field.name}\n checked={Boolean(field.value)}\n onChange={(event) => field.onChange(event.target.checked)}\n onBlur={field.onBlur}\n label={config.label}\n description={fieldState.error ? undefined : config.helperText}\n required={config.required}\n aria-invalid={fieldState.error ? true : undefined}\n aria-describedby={fieldState.error ? errorId : undefined}\n />\n <ErrorText id={errorId}>{fieldState.error?.message}</ErrorText>\n </div>\n )}\n />\n );\n}\n\n/**\n * Render one entry of an auth form's `fields` list as its SDK control.\n *\n * Must sit under the `FormProvider` the form mounts; the binding is read from\n * that context.\n *\n * @param props - The field's config entry.\n * @returns The bound control.\n */\nexport function AuthFieldControl({ config }: { config: AuthField }): ReactNode {\n const { control } = useFormContext();\n const { render } = config;\n if (render) {\n return (\n <Controller\n name={config.name}\n control={control}\n render={({ field, fieldState }) => (\n <>{render({ field, fieldState, error: fieldState.error?.message, config })}</>\n )}\n />\n );\n }\n if (config.type === \"checkbox\") return <CheckboxField config={config} />;\n return (\n <FormField\n name={config.name}\n label={config.label}\n helperText={config.helperText}\n required={config.required}\n >\n {controlFor(config)}\n </FormField>\n );\n}\n"],"mappings":"A,+WAkBA,IAAMuB,EAAwE,CAC1E,MAAO,QACP,SAAU,mBACV,MAAO,KACX,EAWA,SAASC,EAAW,EAAiC,CACjD,IAAMC,EAAeC,EAAO,cAAgBH,EAAaG,EAAO,MAAQ,QAClEC,EAAS,CAAE,YAAaD,EAAO,YAAa,cAAa,EAC/D,OAAQA,EAAO,KAAf,CACI,IAAK,WACD,OAAO,EAAAL,EAAA,IAAA,CAACrB,EAAAA,cAAD,CAAe,GAAI2B,EAAQ,aAAcD,EAAO,YAAe,CAAA,EAC1E,IAAK,QACD,OAAO,EAAAL,EAAA,IAAA,CAACpB,EAAAA,WAAD,CAAY,GAAI0B,CAAS,CAAA,EACpC,IAAK,MACD,OAAO,EAAAN,EAAA,IAAA,CAACnB,EAAAA,SAAD,CAAU,GAAIyB,CAAS,CAAA,EAClC,IAAK,OACD,OAAO,EAAAN,EAAA,IAAA,CAAClB,EAAAA,UAAD,CAAW,GAAIwB,CAAS,CAAA,EACnC,IAAK,MACD,OAAO,EAAAN,EAAA,IAAA,CAACjB,EAAAA,SAAD,CAAU,OAAQsB,EAAO,MAAS,CAAA,EAC7C,IAAK,QACD,OAAO,EAAAL,EAAA,IAAA,CAAChB,EAAAA,MAAD,CAAO,GAAIsB,EAAQ,KAAK,QAAQ,UAAU,OAAS,CAAA,EAC9D,QACI,OAAO,EAAAN,EAAA,IAAA,CAAChB,EAAAA,MAAD,CAAO,GAAIsB,EAAQ,KAAK,MAAQ,CAAA,CAC/C,CACJ,CAWA,SAASC,EAAc,CAAE,UAA4C,CACjE,IAAMC,GAAA,EAAUvB,EAAAA,MAAAA,CAAM,EACtB,OACI,EAAAe,EAAA,IAAA,CAACd,EAAAA,WAAD,CACI,KAAMmB,EAAO,KACb,QAAS,CAAE,QAAO,iBACd,EAAAL,EAAA,KAAA,CAAC,MAAD,CAAA,SAAA,EACI,EAAAA,EAAA,IAAA,CAACb,EAAAA,SAAD,CACI,IAAKsB,EAAM,IACX,KAAMA,EAAM,KACZ,QAAS,EAAQA,EAAM,MACvB,SAAW,GAAUA,EAAM,SAASC,EAAM,OAAO,OAAO,EACxD,OAAQD,EAAM,OACd,MAAOJ,EAAO,MACd,YAAaM,EAAW,MAAQ,IAAA,GAAYN,EAAO,WACnD,SAAUA,EAAO,SACjB,eAAcM,EAAW,MAAQ,GAAO,IAAA,GACxC,mBAAkBA,EAAW,MAAQH,EAAU,IAAA,EAClD,CAAA,GACD,EAAAR,EAAA,IAAA,CAACZ,EAAAA,UAAD,CAAW,GAAIoB,EAAU,SAAAG,EAAW,OAAO,OAAmB,CAAA,CAC7D,CAAA,CAAA,CAEZ,CAAA,CAET,CAWA,SAAgBC,EAAiB,CAAE,UAA4C,CAC3E,GAAM,CAAE,YAAA,EAAYvB,EAAAA,eAAAA,CAAe,EAC7B,CAAE,UAAWgB,EAanB,OAZIQ,GAEI,EAAAb,EAAA,IAAA,CAACd,EAAAA,WAAD,CACI,KAAMmB,EAAO,KACJ,UACT,QAAS,CAAE,QAAO,iBACd,EAAAL,EAAA,IAAA,CAAAV,EAAAA,SAAA,CAAA,SAAGuB,EAAO,CAAE,QAAO,aAAY,MAAOF,EAAW,OAAO,QAAS,QAAO,CAAC,CAAI,CAAA,CAEpF,CAAA,EAGLN,EAAO,OAAS,YAAmB,EAAAL,EAAA,IAAA,CAACO,EAAD,CAAuB,QAAS,CAAA,GAEnE,EAAAP,EAAA,IAAA,CAACT,EAAAA,UAAD,CACI,KAAMc,EAAO,KACb,MAAOA,EAAO,MACd,WAAYA,EAAO,WACnB,SAAUA,EAAO,SAEhB,SAAAF,EAAWE,CAAM,CACX,CAAA,CAEnB,C"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Checkbox as e } from "../Checkbox/Checkbox.js";
|
|
2
|
+
import { ErrorText as t } from "../ErrorText/ErrorText.js";
|
|
3
|
+
import { Input as n } from "../Input/Input.js";
|
|
4
|
+
import { PasswordInput as r } from "../PasswordInput/PasswordInput.js";
|
|
5
|
+
import { PinInput as i } from "../PinInput/PinInput.js";
|
|
6
|
+
import { FormField as a } from "../../forms/FormField.js";
|
|
7
|
+
import { CNPJInput as o, CPFInput as s, PhoneInput as c } from "../../forms/masked-inputs.js";
|
|
8
|
+
import { useId as l } from "react";
|
|
9
|
+
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
10
|
+
import { Controller as p, useFormContext as m } from "react-hook-form";
|
|
11
|
+
//#region src/components/AuthForm/AuthFieldControl.tsx
|
|
12
|
+
var h = {
|
|
13
|
+
email: "email",
|
|
14
|
+
password: "current-password",
|
|
15
|
+
phone: "tel"
|
|
16
|
+
};
|
|
17
|
+
function g(e) {
|
|
18
|
+
let t = e.autoComplete ?? h[e.type ?? "text"], a = {
|
|
19
|
+
placeholder: e.placeholder,
|
|
20
|
+
autoComplete: t
|
|
21
|
+
};
|
|
22
|
+
switch (e.type) {
|
|
23
|
+
case "password": return /* @__PURE__ */ d(r, {
|
|
24
|
+
...a,
|
|
25
|
+
showStrength: e.showStrength
|
|
26
|
+
});
|
|
27
|
+
case "phone": return /* @__PURE__ */ d(c, { ...a });
|
|
28
|
+
case "cpf": return /* @__PURE__ */ d(s, { ...a });
|
|
29
|
+
case "cnpj": return /* @__PURE__ */ d(o, { ...a });
|
|
30
|
+
case "pin": return /* @__PURE__ */ d(i, { length: e.length });
|
|
31
|
+
case "email": return /* @__PURE__ */ d(n, {
|
|
32
|
+
...a,
|
|
33
|
+
type: "email",
|
|
34
|
+
inputMode: "email"
|
|
35
|
+
});
|
|
36
|
+
default: return /* @__PURE__ */ d(n, {
|
|
37
|
+
...a,
|
|
38
|
+
type: "text"
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function _({ config: n }) {
|
|
43
|
+
let r = l();
|
|
44
|
+
return /* @__PURE__ */ d(p, {
|
|
45
|
+
name: n.name,
|
|
46
|
+
render: ({ field: i, fieldState: a }) => /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d(e, {
|
|
47
|
+
ref: i.ref,
|
|
48
|
+
name: i.name,
|
|
49
|
+
checked: !!i.value,
|
|
50
|
+
onChange: (e) => i.onChange(e.target.checked),
|
|
51
|
+
onBlur: i.onBlur,
|
|
52
|
+
label: n.label,
|
|
53
|
+
description: a.error ? void 0 : n.helperText,
|
|
54
|
+
required: n.required,
|
|
55
|
+
"aria-invalid": a.error ? !0 : void 0,
|
|
56
|
+
"aria-describedby": a.error ? r : void 0
|
|
57
|
+
}), /* @__PURE__ */ d(t, {
|
|
58
|
+
id: r,
|
|
59
|
+
children: a.error?.message
|
|
60
|
+
})] })
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function v({ config: e }) {
|
|
64
|
+
let { control: t } = m(), { render: n } = e;
|
|
65
|
+
return n ? /* @__PURE__ */ d(p, {
|
|
66
|
+
name: e.name,
|
|
67
|
+
control: t,
|
|
68
|
+
render: ({ field: t, fieldState: r }) => /* @__PURE__ */ d(u, { children: n({
|
|
69
|
+
field: t,
|
|
70
|
+
fieldState: r,
|
|
71
|
+
error: r.error?.message,
|
|
72
|
+
config: e
|
|
73
|
+
}) })
|
|
74
|
+
}) : e.type === "checkbox" ? /* @__PURE__ */ d(_, { config: e }) : /* @__PURE__ */ d(a, {
|
|
75
|
+
name: e.name,
|
|
76
|
+
label: e.label,
|
|
77
|
+
helperText: e.helperText,
|
|
78
|
+
required: e.required,
|
|
79
|
+
children: g(e)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { v as AuthFieldControl };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=AuthFieldControl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthFieldControl.js","names":["_Fragment","Fragment$1","AUTOCOMPLETE","controlFor","autoComplete","config","shared","PasswordInput","PhoneInput","CPFInput","CNPJInput","PinInput","Input","CheckboxField","errorId","useId","Controller","Checkbox","field","event","fieldState","ErrorText","AuthFieldControl","useFormContext","render","FormField"],"sources":["../../../src/components/AuthForm/AuthFieldControl.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { Controller, useFormContext } from \"react-hook-form\";\nimport { Checkbox } from \"@/components/Checkbox\";\nimport { ErrorText } from \"@/components/ErrorText\";\nimport { Input } from \"@/components/Input\";\nimport { PasswordInput } from \"@/components/PasswordInput\";\nimport { PinInput } from \"@/components/PinInput\";\nimport { FormField } from \"@/forms/FormField\";\nimport { CNPJInput, CPFInput, PhoneInput } from \"@/forms/masked-inputs\";\nimport type { AuthField } from \"./types\";\n\n/**\n * Default `autocomplete` token per field type.\n *\n * These are what password managers and mobile keyboards key on; a login form\n * without them is the one where the saved password never gets offered.\n */\nconst AUTOCOMPLETE: Partial<Record<NonNullable<AuthField[\"type\"]>, string>> = {\n email: \"email\",\n password: \"current-password\",\n phone: \"tel\",\n};\n\n/**\n * Build the SDK control for a value-typed field.\n *\n * Returned bare, without value or handlers: `FormField` clones it with the\n * react-hook-form binding, the label and the error.\n *\n * @param config - The field's config entry.\n * @returns The control element.\n */\nfunction controlFor(config: AuthField): ReactElement {\n const autoComplete = config.autoComplete ?? AUTOCOMPLETE[config.type ?? \"text\"];\n const shared = { placeholder: config.placeholder, autoComplete };\n switch (config.type) {\n case \"password\":\n return <PasswordInput {...shared} showStrength={config.showStrength} />;\n case \"phone\":\n return <PhoneInput {...shared} />;\n case \"cpf\":\n return <CPFInput {...shared} />;\n case \"cnpj\":\n return <CNPJInput {...shared} />;\n case \"pin\":\n return <PinInput length={config.length} />;\n case \"email\":\n return <Input {...shared} type=\"email\" inputMode=\"email\" />;\n default:\n return <Input {...shared} type=\"text\" />;\n }\n}\n\n/**\n * A checkbox bound to a boolean value, with its error under it.\n *\n * Not routed through `FormField`, which hands the control `value`: a checkbox\n * is driven by `checked`, and `Checkbox` has no error slot of its own.\n *\n * @param props - The field's config entry.\n * @returns The bound checkbox.\n */\nfunction CheckboxField({ config }: { config: AuthField }): ReactNode {\n const errorId = useId();\n return (\n <Controller\n name={config.name}\n render={({ field, fieldState }) => (\n <div>\n <Checkbox\n ref={field.ref}\n name={field.name}\n checked={Boolean(field.value)}\n onChange={(event) => field.onChange(event.target.checked)}\n onBlur={field.onBlur}\n label={config.label}\n description={fieldState.error ? undefined : config.helperText}\n required={config.required}\n aria-invalid={fieldState.error ? true : undefined}\n aria-describedby={fieldState.error ? errorId : undefined}\n />\n <ErrorText id={errorId}>{fieldState.error?.message}</ErrorText>\n </div>\n )}\n />\n );\n}\n\n/**\n * Render one entry of an auth form's `fields` list as its SDK control.\n *\n * Must sit under the `FormProvider` the form mounts; the binding is read from\n * that context.\n *\n * @param props - The field's config entry.\n * @returns The bound control.\n */\nexport function AuthFieldControl({ config }: { config: AuthField }): ReactNode {\n const { control } = useFormContext();\n const { render } = config;\n if (render) {\n return (\n <Controller\n name={config.name}\n control={control}\n render={({ field, fieldState }) => (\n <>{render({ field, fieldState, error: fieldState.error?.message, config })}</>\n )}\n />\n );\n }\n if (config.type === \"checkbox\") return <CheckboxField config={config} />;\n return (\n <FormField\n name={config.name}\n label={config.label}\n helperText={config.helperText}\n required={config.required}\n >\n {controlFor(config)}\n </FormField>\n );\n}\n"],"mappings":";;;;;;;;;;;AAkBA,IAAME,IAAwE;CAC1E,OAAO;CACP,UAAU;CACV,OAAO;AACX;AAWA,SAASC,EAAW,GAAiC;CACjD,IAAMC,IAAeC,EAAO,gBAAgBH,EAAaG,EAAO,QAAQ,SAClEC,IAAS;EAAE,aAAaD,EAAO;EAAa;CAAa;CAC/D,QAAQA,EAAO,MAAf;EACI,KAAK,YACD,OAAO,kBAACE,GAAD;GAAe,GAAID;GAAQ,cAAcD,EAAO;EAAe,CAAA;EAC1E,KAAK,SACD,OAAO,kBAACG,GAAD,EAAY,GAAIF,EAAS,CAAA;EACpC,KAAK,OACD,OAAO,kBAACG,GAAD,EAAU,GAAIH,EAAS,CAAA;EAClC,KAAK,QACD,OAAO,kBAACI,GAAD,EAAW,GAAIJ,EAAS,CAAA;EACnC,KAAK,OACD,OAAO,kBAACK,GAAD,EAAU,QAAQN,EAAO,OAAS,CAAA;EAC7C,KAAK,SACD,OAAO,kBAACO,GAAD;GAAO,GAAIN;GAAQ,MAAK;GAAQ,WAAU;EAAS,CAAA;EAC9D,SACI,OAAO,kBAACM,GAAD;GAAO,GAAIN;GAAQ,MAAK;EAAQ,CAAA;CAC/C;AACJ;AAWA,SAASO,EAAc,EAAE,aAA4C;CACjE,IAAMC,IAAUC,EAAM;CACtB,OACI,kBAACC,GAAD;EACI,MAAMX,EAAO;EACb,SAAS,EAAE,UAAO,oBACd,kBAAC,OAAD,EAAA,UAAA,CACI,kBAACY,GAAD;GACI,KAAKC,EAAM;GACX,MAAMA,EAAM;GACZ,SAAS,EAAQA,EAAM;GACvB,WAAW,MAAUA,EAAM,SAASC,EAAM,OAAO,OAAO;GACxD,QAAQD,EAAM;GACd,OAAOb,EAAO;GACd,aAAae,EAAW,QAAQ,KAAA,IAAYf,EAAO;GACnD,UAAUA,EAAO;GACjB,gBAAce,EAAW,QAAQ,KAAO,KAAA;GACxC,oBAAkBA,EAAW,QAAQN,IAAU,KAAA;EAClD,CAAA,GACD,kBAACO,GAAD;GAAW,IAAIP;GAAU,UAAAM,EAAW,OAAO;EAAmB,CAAA,CAC7D,EAAA,CAAA;CAEZ,CAAA;AAET;AAWA,SAAgBE,EAAiB,EAAE,aAA4C;CAC3E,IAAM,EAAE,eAAYC,EAAe,GAC7B,EAAE,cAAWlB;CAanB,OAZImB,IAEI,kBAACR,GAAD;EACI,MAAMX,EAAO;EACJ;EACT,SAAS,EAAE,UAAO,oBACd,kBAAAL,GAAA,EAAA,UAAGwB,EAAO;GAAE;GAAO;GAAY,OAAOJ,EAAW,OAAO;GAAS;EAAO,CAAC,EAAI,CAAA;CAEpF,CAAA,IAGLf,EAAO,SAAS,aAAmB,kBAACQ,GAAD,EAAuB,UAAS,CAAA,IAEnE,kBAACY,GAAD;EACI,MAAMpB,EAAO;EACb,OAAOA,EAAO;EACd,YAAYA,EAAO;EACnB,UAAUA,EAAO;EAEhB,UAAAF,EAAWE,CAAM;CACX,CAAA;AAEnB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("../Alert/Alert.cjs"),n=require("../Button/Button.cjs"),r=require("../Divider/Divider.cjs"),i=require("../Form/Form.cjs"),a=require("../../forms/use-zod-form.cjs"),o=require("../../http/errors.cjs"),s=require("../../http/use-describe-api-error.cjs"),c=require("./AuthFieldControl.cjs"),l=require("./auth-defaults.cjs"),u=require("./AuthForm.module.cjs");let d=require("react"),f=require("react/jsx-runtime"),p=require("react-hook-form");function m(e,t){let n={};for(let t of e)n[t.name]=t.type!==`checkbox`&&``;return{...n,...t}}function h(e,t,n){let r=new Set(t.map(e=>e.name)),i=[],a=0;for(let[t,o]of Object.entries(n))r.has(t)?(e.setError(t,{type:`server`,message:o},{shouldFocus:a===0}),a+=1):i.push(o);return{marked:a,unmatched:i}}function g({schema:g,fields:_,onSubmit:v,submitLabel:y=`Enviar`,defaultValues:b,beforeSubmit:x,afterSubmit:S,social:C,labels:w,errorOptions:T,onError:E,className:D}){let O={...l.DEFAULT_AUTH_FORM_LABELS,...w},k=s.useDescribeApiError(),[A,j]=(0,d.useState)(null),M=a.useZodForm(g,{defaultValues:m(_,b)}),N=M.handleSubmit(async e=>{j(null);try{await v(e)}catch(e){let t=o.isApiError(e)?e.fields:void 0,{marked:n,unmatched:r}=t?h(M,_,t):{marked:0,unmatched:[]};n===0?j(k(e,O.error,T)):r.length>0&&j(r.join(` `)),E?.(e)}});return(0,f.jsx)(p.FormProvider,{...M,children:(0,f.jsxs)(i.Form,{noValidate:!0,onSubmit:N,className:e.cn(u.default.form,D),children:[A!==null&&(0,f.jsx)(t.Alert,{variant:`danger`,description:A}),_.map(e=>(0,f.jsx)(c.AuthFieldControl,{config:e},e.name)),x,(0,f.jsx)(n.Button,{type:`submit`,fullWidth:!0,size:`lg`,loading:M.formState.isSubmitting,children:y}),C!==void 0&&(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(r.Divider,{label:O.divider}),(0,f.jsx)(`div`,{className:u.default.social,children:C})]}),S]})})}exports.AuthForm=g;
|
|
2
|
+
//# sourceMappingURL=AuthForm.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthForm.cjs","names":["DEFAULT_AUTH_FORM_LABELS","useDescribeApiError","useState","useZodForm","isApiError","FormProvider","Form","cn","styles","Alert","AuthFieldControl","Button","_Fragment","Divider","require_cn","require_Alert","require_Button","require_Divider","require_Form","require_use_zod_form","require_errors","require_use_describe_api_error","require_AuthFieldControl","require_auth_defaults","require_AuthForm_module","react","react_jsx_runtime","react_hook_form","initialValues","base","field","fields","overrides","markServerFields","names","unmatched","marked","name","message","messages","form","AuthForm","text","labels","describe","failure","setFailure","schema","defaultValues","submit","onSubmit","values","error","errorOptions","onError","className","beforeSubmit","submitLabel","social","afterSubmit"],"sources":["../../../src/components/AuthForm/AuthForm.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { FormProvider } from \"react-hook-form\";\nimport type { DefaultValues, Path, UseFormReturn } from \"react-hook-form\";\nimport type { z } from \"zod\";\nimport { Alert } from \"@/components/Alert\";\nimport { Button } from \"@/components/Button\";\nimport { Divider } from \"@/components/Divider\";\nimport { Form } from \"@/components/Form\";\nimport { useZodForm } from \"@/forms/use-zod-form\";\nimport { isApiError } from \"@/http/errors\";\nimport { useDescribeApiError } from \"@/http/use-describe-api-error\";\nimport { cn } from \"@/utils/cn\";\nimport { AuthFieldControl } from \"./AuthFieldControl\";\nimport { DEFAULT_AUTH_FORM_LABELS } from \"./auth-defaults\";\nimport type { AuthField, AuthFormLabels, AuthFormProps, AuthFormValues } from \"./types\";\nimport styles from \"./AuthForm.module.css\";\n\n/**\n * Initial values for every declared field.\n *\n * react-hook-form needs a defined value per field, or the controlled inputs\n * start uncontrolled and React warns on the first keystroke — and a missing\n * checkbox would submit `undefined`, which a `z.boolean()` rejects with a\n * message about types rather than about the terms.\n *\n * @param fields - The declared fields.\n * @param overrides - The caller's `defaultValues`, which win.\n * @returns One value per field.\n */\nfunction initialValues(\n fields: readonly AuthField[],\n overrides: object | undefined,\n): Record<string, unknown> {\n const base: Record<string, unknown> = {};\n for (const field of fields) base[field.name] = field.type === \"checkbox\" ? false : \"\";\n return { ...base, ...overrides };\n}\n\n/**\n * Attach the server's per-field messages to the fields this form shows.\n *\n * Only names present in `fields` are marked: the API can name a field the screen\n * does not render, and marking an input that does not exist leaves an error the\n * user can never clear. The first marked field takes focus.\n *\n * @param form - The form to mark.\n * @param fields - The declared fields.\n * @param messages - `error.fields`, keyed by field name.\n * @returns The messages that matched no declared field.\n */\nfunction markServerFields<TValues extends AuthFormValues<z.ZodTypeAny>>(\n form: UseFormReturn<TValues>,\n fields: readonly AuthField[],\n messages: Record<string, string>,\n): { marked: number; unmatched: string[] } {\n const names = new Set(fields.map((field) => field.name));\n const unmatched: string[] = [];\n let marked = 0;\n for (const [name, message] of Object.entries(messages)) {\n if (!names.has(name)) {\n unmatched.push(message);\n continue;\n }\n form.setError(\n name as Path<TValues>,\n { type: \"server\", message },\n {\n shouldFocus: marked === 0,\n },\n );\n marked += 1;\n }\n return { marked, unmatched };\n}\n\n/**\n * A complete auth form generated from a list of field configs and a zod schema.\n *\n * Every hand-built login and sign-up screen repeated the same wiring: a\n * `useZodForm`, one labelled input per field with its error slot, a password eye,\n * a submit button disabled while the request runs, and a `catch` that copied the\n * 422's field messages back onto the inputs. The app now declares *which* fields\n * and *what happens on submit*; the rest is here, built on the SDK's own controls\n * and its forms layer (`useZodForm` + `FormProvider` + `FormField`).\n *\n * Errors thrown by `onSubmit` are shown, never rethrown — a rethrow from a submit\n * handler is an unhandled rejection with nowhere to go. A `TempestApiError` whose\n * `fields` name fields of this form marks them; anything else, and any field\n * message that matched no declared field, goes to an `Alert` above the fields,\n * worded by `describeApiError`. Pass `onError` to log.\n *\n * @example\n * const schema = z.object({ email: z.email(\"E-mail inválido\") });\n * <AuthForm\n * schema={schema}\n * fields={[{ name: \"email\", type: \"email\", label: \"E-mail\" }]}\n * submitLabel=\"Continuar\"\n * onSubmit={async (values) => { await api.post(\"/auth/magic-link\", { body: values }); }}\n * />\n */\nexport function AuthForm<TSchema extends z.ZodTypeAny>({\n schema,\n fields,\n onSubmit,\n submitLabel = \"Enviar\",\n defaultValues,\n beforeSubmit,\n afterSubmit,\n social,\n labels,\n errorOptions,\n onError,\n className,\n}: AuthFormProps<TSchema>): ReactNode {\n const text: AuthFormLabels = { ...DEFAULT_AUTH_FORM_LABELS, ...labels };\n const describe = useDescribeApiError();\n const [failure, setFailure] = useState<string | null>(null);\n const form = useZodForm(schema, {\n defaultValues: initialValues(fields, defaultValues) as DefaultValues<\n AuthFormValues<TSchema>\n >,\n });\n\n const submit = form.handleSubmit(async (values) => {\n setFailure(null);\n try {\n await onSubmit(values);\n } catch (error) {\n const messages = isApiError(error) ? error.fields : undefined;\n const { marked, unmatched } = messages\n ? markServerFields(form, fields, messages)\n : { marked: 0, unmatched: [] };\n if (marked === 0) setFailure(describe(error, text.error, errorOptions));\n else if (unmatched.length > 0) setFailure(unmatched.join(\" \"));\n onError?.(error);\n }\n });\n\n return (\n <FormProvider {...form}>\n <Form noValidate onSubmit={submit} className={cn(styles.form, className)}>\n {failure !== null && <Alert variant=\"danger\" description={failure} />}\n {fields.map((field) => (\n <AuthFieldControl key={field.name} config={field} />\n ))}\n {beforeSubmit}\n <Button type=\"submit\" fullWidth size=\"lg\" loading={form.formState.isSubmitting}>\n {submitLabel}\n </Button>\n {social !== undefined && (\n <>\n <Divider label={text.divider} />\n <div className={styles.social}>{social}</div>\n </>\n )}\n {afterSubmit}\n </Form>\n </FormProvider>\n );\n}\n"],"mappings":"A,qeA8BA,SAAS4B,EACL,EACA,EACuB,CACvB,IAAMC,EAAgC,CAAC,EACvC,IAAK,IAAMC,KAASC,EAAQ,EAAKD,EAAM,MAAQA,EAAM,OAAS,YAAqB,GACnF,MAAO,CAAE,GAAGD,EAAM,GAAGG,CAAU,CACnC,CAcA,SAASC,EACL,EACA,EACA,EACuC,CACvC,IAAMC,EAAQ,IAAI,IAAIH,EAAO,IAAK,GAAUD,EAAM,IAAI,CAAC,EACjDK,EAAsB,CAAC,EACzBC,EAAS,EACb,IAAK,GAAM,CAACC,EAAMC,KAAY,OAAO,QAAQC,CAAQ,EAC5CL,EAAM,IAAIG,CAAI,GAInBG,EAAK,SACDH,EACA,CAAE,KAAM,SAAU,SAAQ,EAC1B,CACI,YAAaD,IAAW,CAC5B,CACJ,EACA,GAAU,GAVND,EAAU,KAAKG,CAAO,EAY9B,MAAO,CAAE,SAAQ,WAAU,CAC/B,CA2BA,SAAgBG,EAAuC,CACnD,SACA,SACA,WACA,cAAc,SACd,gBACA,eACA,cACA,SACA,SACA,eACA,UACA,aACkC,CAClC,IAAMC,EAAuB,CAAE,GAAG1C,EAAAA,yBAA0B,GAAG2C,CAAO,EAChEC,EAAW3C,EAAAA,oBAAoB,EAC/B,CAAC4C,EAASC,IAAA,EAAc5C,EAAAA,SAAAA,CAAwB,IAAI,EACpDsC,EAAOrC,EAAAA,WAAW4C,EAAQ,CAC5B,cAAenB,EAAcG,EAAQiB,CAAa,CAGtD,CAAC,EAEKC,EAAST,EAAK,aAAa,KAAO,IAAW,CAC/CM,EAAW,IAAI,EACf,GAAI,CACA,MAAMI,EAASC,CAAM,CACzB,OAASC,EAAO,CACZ,IAAMb,EAAWnC,EAAAA,WAAWgD,CAAK,EAAIA,EAAM,OAAS,IAAA,GAC9C,CAAE,SAAQ,aAAcb,EACxBN,EAAiBO,EAAMT,EAAQQ,CAAQ,EACvC,CAAE,OAAQ,EAAG,UAAW,CAAC,CAAE,EAC7BH,IAAW,EAAGU,EAAWF,EAASQ,EAAOV,EAAK,MAAOW,CAAY,CAAC,EAC7DlB,EAAU,OAAS,GAAGW,EAAWX,EAAU,KAAK,GAAG,CAAC,EAC7DmB,IAAUF,CAAK,CACnB,CACJ,CAAC,EAED,OACI,EAAA1B,EAAA,IAAA,CAACrB,EAAAA,aAAD,CAAc,GAAImC,EACd,UAAA,EAAAd,EAAA,KAAA,CAACpB,EAAAA,KAAD,CAAM,WAAA,GAAW,SAAU2C,EAAQ,UAAW1C,EAAAA,GAAGC,EAAAA,QAAO,KAAM+C,CAAS,EAAvE,SAAA,CACKV,IAAY,OAAQ,EAAAnB,EAAA,IAAA,CAACjB,EAAAA,MAAD,CAAO,QAAQ,SAAS,YAAaoC,CAAU,CAAA,EACnEd,EAAO,IAAK,IACT,EAAAL,EAAA,IAAA,CAAChB,EAAAA,iBAAD,CAAmC,OAAQoB,CAAQ,EAA5BA,EAAM,IAAsB,CACtD,EACA0B,GACD,EAAA9B,EAAA,IAAA,CAACf,EAAAA,OAAD,CAAQ,KAAK,SAAS,UAAA,GAAU,KAAK,KAAK,QAAS6B,EAAK,UAAU,aAC7D,SAAAiB,CACG,CAAA,EACPC,IAAW,IAAA,KACR,EAAAhC,EAAA,KAAA,CAAAd,EAAAA,SAAA,CAAA,SAAA,EACI,EAAAc,EAAA,IAAA,CAACb,EAAAA,QAAD,CAAS,MAAO6B,EAAK,OAAU,CAAA,GAC/B,EAAAhB,EAAA,IAAA,CAAC,MAAD,CAAK,UAAWlB,EAAAA,QAAO,OAAS,SAAAkD,CAAY,CAAA,CAC9C,CAAA,CAAA,EAELC,CACC,C,EACI,CAAA,CAEtB,C"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { cn as e } from "../../utils/cn.js";
|
|
2
|
+
import { Alert as t } from "../Alert/Alert.js";
|
|
3
|
+
import { Button as n } from "../Button/Button.js";
|
|
4
|
+
import { Divider as r } from "../Divider/Divider.js";
|
|
5
|
+
import { Form as i } from "../Form/Form.js";
|
|
6
|
+
import { useZodForm as a } from "../../forms/use-zod-form.js";
|
|
7
|
+
import { isApiError as o } from "../../http/errors.js";
|
|
8
|
+
import { useDescribeApiError as s } from "../../http/use-describe-api-error.js";
|
|
9
|
+
import { AuthFieldControl as c } from "./AuthFieldControl.js";
|
|
10
|
+
import { DEFAULT_AUTH_FORM_LABELS as l } from "./auth-defaults.js";
|
|
11
|
+
import u from "./AuthForm.module.js";
|
|
12
|
+
import { useState as d } from "react";
|
|
13
|
+
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
14
|
+
import { FormProvider as h } from "react-hook-form";
|
|
15
|
+
//#region src/components/AuthForm/AuthForm.tsx
|
|
16
|
+
function g(e, t) {
|
|
17
|
+
let n = {};
|
|
18
|
+
for (let t of e) n[t.name] = t.type !== "checkbox" && "";
|
|
19
|
+
return {
|
|
20
|
+
...n,
|
|
21
|
+
...t
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function _(e, t, n) {
|
|
25
|
+
let r = new Set(t.map((e) => e.name)), i = [], a = 0;
|
|
26
|
+
for (let [t, o] of Object.entries(n)) r.has(t) ? (e.setError(t, {
|
|
27
|
+
type: "server",
|
|
28
|
+
message: o
|
|
29
|
+
}, { shouldFocus: a === 0 }), a += 1) : i.push(o);
|
|
30
|
+
return {
|
|
31
|
+
marked: a,
|
|
32
|
+
unmatched: i
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function v({ schema: v, fields: y, onSubmit: b, submitLabel: x = "Enviar", defaultValues: S, beforeSubmit: C, afterSubmit: w, social: T, labels: E, errorOptions: D, onError: O, className: k }) {
|
|
36
|
+
let A = {
|
|
37
|
+
...l,
|
|
38
|
+
...E
|
|
39
|
+
}, j = s(), [M, N] = d(null), P = a(v, { defaultValues: g(y, S) }), F = P.handleSubmit(async (e) => {
|
|
40
|
+
N(null);
|
|
41
|
+
try {
|
|
42
|
+
await b(e);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
let t = o(e) ? e.fields : void 0, { marked: n, unmatched: r } = t ? _(P, y, t) : {
|
|
45
|
+
marked: 0,
|
|
46
|
+
unmatched: []
|
|
47
|
+
};
|
|
48
|
+
n === 0 ? N(j(e, A.error, D)) : r.length > 0 && N(r.join(" ")), O?.(e);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return /* @__PURE__ */ p(h, {
|
|
52
|
+
...P,
|
|
53
|
+
children: /* @__PURE__ */ m(i, {
|
|
54
|
+
noValidate: !0,
|
|
55
|
+
onSubmit: F,
|
|
56
|
+
className: e(u.form, k),
|
|
57
|
+
children: [
|
|
58
|
+
M !== null && /* @__PURE__ */ p(t, {
|
|
59
|
+
variant: "danger",
|
|
60
|
+
description: M
|
|
61
|
+
}),
|
|
62
|
+
y.map((e) => /* @__PURE__ */ p(c, { config: e }, e.name)),
|
|
63
|
+
C,
|
|
64
|
+
/* @__PURE__ */ p(n, {
|
|
65
|
+
type: "submit",
|
|
66
|
+
fullWidth: !0,
|
|
67
|
+
size: "lg",
|
|
68
|
+
loading: P.formState.isSubmitting,
|
|
69
|
+
children: x
|
|
70
|
+
}),
|
|
71
|
+
T !== void 0 && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(r, { label: A.divider }), /* @__PURE__ */ p("div", {
|
|
72
|
+
className: u.social,
|
|
73
|
+
children: T
|
|
74
|
+
})] }),
|
|
75
|
+
w
|
|
76
|
+
]
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
export { v as AuthForm };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=AuthForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthForm.js","names":["styles","_Fragment","AuthForm_module_default","Fragment$1","initialValues","base","field","fields","overrides","markServerFields","names","unmatched","marked","name","message","messages","form","AuthForm","text","DEFAULT_AUTH_FORM_LABELS","labels","describe","useDescribeApiError","failure","setFailure","useState","useZodForm","schema","defaultValues","submit","onSubmit","values","error","isApiError","errorOptions","onError","FormProvider","Form","cn","className","Alert","AuthFieldControl","beforeSubmit","Button","submitLabel","social","Divider","afterSubmit"],"sources":["../../../src/components/AuthForm/AuthForm.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { FormProvider } from \"react-hook-form\";\nimport type { DefaultValues, Path, UseFormReturn } from \"react-hook-form\";\nimport type { z } from \"zod\";\nimport { Alert } from \"@/components/Alert\";\nimport { Button } from \"@/components/Button\";\nimport { Divider } from \"@/components/Divider\";\nimport { Form } from \"@/components/Form\";\nimport { useZodForm } from \"@/forms/use-zod-form\";\nimport { isApiError } from \"@/http/errors\";\nimport { useDescribeApiError } from \"@/http/use-describe-api-error\";\nimport { cn } from \"@/utils/cn\";\nimport { AuthFieldControl } from \"./AuthFieldControl\";\nimport { DEFAULT_AUTH_FORM_LABELS } from \"./auth-defaults\";\nimport type { AuthField, AuthFormLabels, AuthFormProps, AuthFormValues } from \"./types\";\nimport styles from \"./AuthForm.module.css\";\n\n/**\n * Initial values for every declared field.\n *\n * react-hook-form needs a defined value per field, or the controlled inputs\n * start uncontrolled and React warns on the first keystroke — and a missing\n * checkbox would submit `undefined`, which a `z.boolean()` rejects with a\n * message about types rather than about the terms.\n *\n * @param fields - The declared fields.\n * @param overrides - The caller's `defaultValues`, which win.\n * @returns One value per field.\n */\nfunction initialValues(\n fields: readonly AuthField[],\n overrides: object | undefined,\n): Record<string, unknown> {\n const base: Record<string, unknown> = {};\n for (const field of fields) base[field.name] = field.type === \"checkbox\" ? false : \"\";\n return { ...base, ...overrides };\n}\n\n/**\n * Attach the server's per-field messages to the fields this form shows.\n *\n * Only names present in `fields` are marked: the API can name a field the screen\n * does not render, and marking an input that does not exist leaves an error the\n * user can never clear. The first marked field takes focus.\n *\n * @param form - The form to mark.\n * @param fields - The declared fields.\n * @param messages - `error.fields`, keyed by field name.\n * @returns The messages that matched no declared field.\n */\nfunction markServerFields<TValues extends AuthFormValues<z.ZodTypeAny>>(\n form: UseFormReturn<TValues>,\n fields: readonly AuthField[],\n messages: Record<string, string>,\n): { marked: number; unmatched: string[] } {\n const names = new Set(fields.map((field) => field.name));\n const unmatched: string[] = [];\n let marked = 0;\n for (const [name, message] of Object.entries(messages)) {\n if (!names.has(name)) {\n unmatched.push(message);\n continue;\n }\n form.setError(\n name as Path<TValues>,\n { type: \"server\", message },\n {\n shouldFocus: marked === 0,\n },\n );\n marked += 1;\n }\n return { marked, unmatched };\n}\n\n/**\n * A complete auth form generated from a list of field configs and a zod schema.\n *\n * Every hand-built login and sign-up screen repeated the same wiring: a\n * `useZodForm`, one labelled input per field with its error slot, a password eye,\n * a submit button disabled while the request runs, and a `catch` that copied the\n * 422's field messages back onto the inputs. The app now declares *which* fields\n * and *what happens on submit*; the rest is here, built on the SDK's own controls\n * and its forms layer (`useZodForm` + `FormProvider` + `FormField`).\n *\n * Errors thrown by `onSubmit` are shown, never rethrown — a rethrow from a submit\n * handler is an unhandled rejection with nowhere to go. A `TempestApiError` whose\n * `fields` name fields of this form marks them; anything else, and any field\n * message that matched no declared field, goes to an `Alert` above the fields,\n * worded by `describeApiError`. Pass `onError` to log.\n *\n * @example\n * const schema = z.object({ email: z.email(\"E-mail inválido\") });\n * <AuthForm\n * schema={schema}\n * fields={[{ name: \"email\", type: \"email\", label: \"E-mail\" }]}\n * submitLabel=\"Continuar\"\n * onSubmit={async (values) => { await api.post(\"/auth/magic-link\", { body: values }); }}\n * />\n */\nexport function AuthForm<TSchema extends z.ZodTypeAny>({\n schema,\n fields,\n onSubmit,\n submitLabel = \"Enviar\",\n defaultValues,\n beforeSubmit,\n afterSubmit,\n social,\n labels,\n errorOptions,\n onError,\n className,\n}: AuthFormProps<TSchema>): ReactNode {\n const text: AuthFormLabels = { ...DEFAULT_AUTH_FORM_LABELS, ...labels };\n const describe = useDescribeApiError();\n const [failure, setFailure] = useState<string | null>(null);\n const form = useZodForm(schema, {\n defaultValues: initialValues(fields, defaultValues) as DefaultValues<\n AuthFormValues<TSchema>\n >,\n });\n\n const submit = form.handleSubmit(async (values) => {\n setFailure(null);\n try {\n await onSubmit(values);\n } catch (error) {\n const messages = isApiError(error) ? error.fields : undefined;\n const { marked, unmatched } = messages\n ? markServerFields(form, fields, messages)\n : { marked: 0, unmatched: [] };\n if (marked === 0) setFailure(describe(error, text.error, errorOptions));\n else if (unmatched.length > 0) setFailure(unmatched.join(\" \"));\n onError?.(error);\n }\n });\n\n return (\n <FormProvider {...form}>\n <Form noValidate onSubmit={submit} className={cn(styles.form, className)}>\n {failure !== null && <Alert variant=\"danger\" description={failure} />}\n {fields.map((field) => (\n <AuthFieldControl key={field.name} config={field} />\n ))}\n {beforeSubmit}\n <Button type=\"submit\" fullWidth size=\"lg\" loading={form.formState.isSubmitting}>\n {submitLabel}\n </Button>\n {social !== undefined && (\n <>\n <Divider label={text.divider} />\n <div className={styles.social}>{social}</div>\n </>\n )}\n {afterSubmit}\n </Form>\n </FormProvider>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAASI,EACL,GACA,GACuB;CACvB,IAAMC,IAAgC,CAAC;CACvC,KAAK,IAAMC,KAASC,GAAQ,EAAKD,EAAM,QAAQA,EAAM,SAAS,cAAqB;CACnF,OAAO;EAAE,GAAGD;EAAM,GAAGG;CAAU;AACnC;AAcA,SAASC,EACL,GACA,GACA,GACuC;CACvC,IAAMC,IAAQ,IAAI,IAAIH,EAAO,KAAK,MAAUD,EAAM,IAAI,CAAC,GACjDK,IAAsB,CAAC,GACzBC,IAAS;CACb,KAAK,IAAM,CAACC,GAAMC,MAAY,OAAO,QAAQC,CAAQ,GACjD,AAAKL,EAAM,IAAIG,CAAI,KAInBG,EAAK,SACDH,GACA;EAAE,MAAM;EAAU;CAAQ,GAC1B,EACI,aAAaD,MAAW,EAC5B,CACJ,GACA,KAAU,KAVND,EAAU,KAAKG,CAAO;CAY9B,OAAO;EAAE;EAAQ;CAAU;AAC/B;AA2BA,SAAgBG,EAAuC,EACnD,WACA,WACA,aACA,iBAAc,UACd,kBACA,iBACA,gBACA,WACA,WACA,iBACA,YACA,gBACkC;CAClC,IAAMC,IAAuB;EAAE,GAAGC;EAA0B,GAAGC;CAAO,GAChEC,IAAWC,EAAoB,GAC/B,CAACC,GAASC,KAAcC,EAAwB,IAAI,GACpDT,IAAOU,EAAWC,GAAQ,EAC5B,eAAevB,EAAcG,GAAQqB,CAAa,EAGtD,CAAC,GAEKC,IAASb,EAAK,aAAa,OAAO,MAAW;EAC/C,EAAW,IAAI;EACf,IAAI;GACA,MAAMc,EAASC,CAAM;EACzB,SAASC,GAAO;GACZ,IAAMjB,IAAWkB,EAAWD,CAAK,IAAIA,EAAM,SAAS,KAAA,GAC9C,EAAE,WAAQ,iBAAcjB,IACxBN,EAAiBO,GAAMT,GAAQQ,CAAQ,IACvC;IAAE,QAAQ;IAAG,WAAW,CAAC;GAAE;GAGjC,AAFIH,MAAW,IAAGY,EAAWH,EAASW,GAAOd,EAAK,OAAOgB,CAAY,CAAC,IAC7DvB,EAAU,SAAS,KAAGa,EAAWb,EAAU,KAAK,GAAG,CAAC,GAC7DwB,IAAUH,CAAK;EACnB;CACJ,CAAC;CAED,OACI,kBAACI,GAAD;EAAc,GAAIpB;EACd,UAAA,kBAACqB,GAAD;GAAM,YAAA;GAAW,UAAUR;GAAQ,WAAWS,EAAGtC,EAAO,MAAMuC,CAAS;GAAvE,UAAA;IACKhB,MAAY,QAAQ,kBAACiB,GAAD;KAAO,SAAQ;KAAS,aAAajB;IAAU,CAAA;IACnEhB,EAAO,KAAK,MACT,kBAACkC,GAAD,EAAmC,QAAQnC,EAAQ,GAA5BA,EAAM,IAAsB,CACtD;IACAoC;IACD,kBAACC,GAAD;KAAQ,MAAK;KAAS,WAAA;KAAU,MAAK;KAAK,SAAS3B,EAAK,UAAU;KAC7D,UAAA4B;IACG,CAAA;IACPC,MAAW,KAAA,KACR,kBAAA5C,GAAA,EAAA,UAAA,CACI,kBAAC6C,GAAD,EAAS,OAAO5B,EAAK,QAAU,CAAA,GAC/B,kBAAC,OAAD;KAAK,WAAWlB,EAAO;KAAS,UAAA6C;IAAY,CAAA,CAC9C,EAAA,CAAA;IAELE;GACC;;CACI,CAAA;AAEtB"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
require("../../styles/component/AuthForm.css");
|
|
2
|
+
var e=`tempest_form_Ry1iO`,t=`tempest_social_ZiYgW`,n=`tempest_link_iisLJ`,r=`tempest_forgot_kjNlS`,i=`tempest_prompt_cuJKg`,a=`tempest_hints_AYoGY`,o={form:e,social:t,link:n,forgot:r,prompt:i,hints:a};exports.default=o,exports.forgot=r,exports.form=e,exports.hints=a,exports.link=n,exports.prompt=i,exports.social=t;
|
|
3
|
+
//# sourceMappingURL=AuthForm.module.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthForm.module.cjs","names":["form","social","link","forgot","prompt","hints","AuthForm_module_default"],"sources":["../../../src/components/AuthForm/AuthForm.module.css"],"sourcesContent":["/* ============================================================\n * AuthForm — the generated form and the links its presets add.\n * ============================================================ */\n.form {\n width: 100%;\n}\n\n.social {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--tempest-space-2);\n}\n\n.link {\n color: var(--tempest-primary);\n font-weight: var(--tempest-weight-semibold);\n text-decoration: none;\n border-radius: var(--tempest-radius-xs);\n}\n\n.link:hover {\n text-decoration: underline;\n}\n\n.link:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.forgot {\n align-self: flex-end;\n font-size: var(--tempest-text-sm);\n}\n\n.prompt {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.hints {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n margin: 0;\n padding-left: var(--tempest-space-5);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n"],"mappings":";"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "../../styles/component/AuthForm.css";
|
|
2
|
+
//#region src/components/AuthForm/AuthForm.module.css
|
|
3
|
+
var e = "tempest_form_Ry1iO", t = "tempest_social_ZiYgW", n = "tempest_link_iisLJ", r = "tempest_forgot_kjNlS", i = "tempest_prompt_cuJKg", a = "tempest_hints_AYoGY", o = {
|
|
4
|
+
form: e,
|
|
5
|
+
social: t,
|
|
6
|
+
link: n,
|
|
7
|
+
forgot: r,
|
|
8
|
+
prompt: i,
|
|
9
|
+
hints: a
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { o as default, r as forgot, e as form, a as hints, n as link, i as prompt, t as social };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=AuthForm.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthForm.module.js","names":["form","social","link","forgot","prompt","hints","AuthForm_module_default"],"sources":["../../../src/components/AuthForm/AuthForm.module.css"],"sourcesContent":["/* ============================================================\n * AuthForm — the generated form and the links its presets add.\n * ============================================================ */\n.form {\n width: 100%;\n}\n\n.social {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--tempest-space-2);\n}\n\n.link {\n color: var(--tempest-primary);\n font-weight: var(--tempest-weight-semibold);\n text-decoration: none;\n border-radius: var(--tempest-radius-xs);\n}\n\n.link:hover {\n text-decoration: underline;\n}\n\n.link:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.forgot {\n align-self: flex-end;\n font-size: var(--tempest-text-sm);\n}\n\n.prompt {\n margin: 0;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.hints {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n margin: 0;\n padding-left: var(--tempest-space-5);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n}\n"],"mappings":";"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("../../utils/safe-url.cjs"),n=require("./AuthForm.module.cjs");let r=require("react/jsx-runtime"),i=require("react-router");function a({to:a,children:o,className:s}){let c=t.vettedHref(a);return c===void 0?null:(0,r.jsx)(i.Link,{to:c,className:e.cn(n.default.link,s),children:o})}function o({prompt:e,label:i,to:o}){let s=t.vettedHref(o);return s===void 0?null:(0,r.jsxs)(`p`,{className:n.default.prompt,children:[e,` `,(0,r.jsx)(a,{to:s,children:i})]})}exports.AuthLink=a,exports.AuthPrompt=o;
|
|
2
|
+
//# sourceMappingURL=AuthLinks.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthLinks.cjs","names":["vettedHref","Link","cn","styles","require_cn","require_safe_url","require_AuthForm_module","react_jsx_runtime","react_router","AuthLink","href","to","className","AuthPrompt","prompt","label"],"sources":["../../../src/components/AuthForm/AuthLinks.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Link } from \"react-router\";\nimport { cn } from \"@/utils/cn\";\nimport { vettedHref } from \"@/utils/safe-url\";\nimport styles from \"./AuthForm.module.css\";\n\n/**\n * A router link styled as the auth screens' inline action.\n *\n * Router `Link`, not `<a>`: the screens it connects are routes of the same app,\n * and a full reload between login and sign-up throws away the query cache and\n * any form state the user typed.\n *\n * `to` is vetted with `safeLinkUrl`'s allowlist before it reaches the `Link`, and a\n * destination it rejects renders nothing. The router's `Link` writes the string to\n * the anchor's `href`: React 19 replaces a `javascript:` href with a throwing stub,\n * but React 18 — inside the peer range — writes it verbatim, so an app that fills\n * `links` from a tenant's config or a query string would ship a clickable script\n * link. A dropped link is the same outcome as an unset route.\n *\n * @param props - Destination, content and an extra class.\n * @returns The link, or `null` when the destination is not a safe URL.\n */\nexport function AuthLink({\n to,\n children,\n className,\n}: {\n to: string;\n children: ReactNode;\n className?: string;\n}): ReactNode {\n const href = vettedHref(to);\n if (href === undefined) return null;\n return (\n <Link to={href} className={cn(styles.link, className)}>\n {children}\n </Link>\n );\n}\n\n/**\n * The \"Não tem uma conta? Cadastre-se\" line under a form.\n *\n * @param props - The leading sentence, the link text and its destination.\n * @returns The paragraph, or `null` when there is no destination or it is not\n * a safe URL (see {@link AuthLink}).\n */\nexport function AuthPrompt({\n prompt,\n label,\n to,\n}: {\n prompt: ReactNode;\n label: ReactNode;\n to: string | undefined;\n}): ReactNode {\n const href = vettedHref(to);\n if (href === undefined) return null;\n return (\n <p className={styles.prompt}>\n {prompt} <AuthLink to={href}>{label}</AuthLink>\n </p>\n );\n}\n"],"mappings":"A,4KAuBA,SAAgBS,EAAS,CACrB,KACA,WACA,aAKU,CACV,IAAMC,EAAOV,EAAAA,WAAWW,CAAE,EAE1B,OADID,IAAS,IAAA,GAAkB,MAE3B,EAAAH,EAAA,IAAA,CAACN,EAAAA,KAAD,CAAM,GAAIS,EAAM,UAAWR,EAAAA,GAAGC,EAAAA,QAAO,KAAMS,CAAS,EAC/C,UACC,CAAA,CAEd,CASA,SAAgBC,EAAW,CACvB,SACA,QACA,MAKU,CACV,IAAMH,EAAOV,EAAAA,WAAWW,CAAE,EAE1B,OADID,IAAS,IAAA,GAAkB,MAE3B,EAAAH,EAAA,KAAA,CAAC,IAAD,CAAG,UAAWJ,EAAAA,QAAO,OAArB,SAAA,CACKW,EAAO,KAAC,EAAAP,EAAA,IAAA,CAACE,EAAD,CAAU,GAAIC,EAAO,SAAAK,CAAgB,CAAA,CAC/C,C,EAEX,C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { cn as e } from "../../utils/cn.js";
|
|
2
|
+
import { vettedHref as t } from "../../utils/safe-url.js";
|
|
3
|
+
import n from "./AuthForm.module.js";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
import { Link as a } from "react-router";
|
|
6
|
+
//#region src/components/AuthForm/AuthLinks.tsx
|
|
7
|
+
function o({ to: i, children: o, className: s }) {
|
|
8
|
+
let c = t(i);
|
|
9
|
+
return c === void 0 ? null : /* @__PURE__ */ r(a, {
|
|
10
|
+
to: c,
|
|
11
|
+
className: e(n.link, s),
|
|
12
|
+
children: o
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function s({ prompt: e, label: a, to: s }) {
|
|
16
|
+
let c = t(s);
|
|
17
|
+
return c === void 0 ? null : /* @__PURE__ */ i("p", {
|
|
18
|
+
className: n.prompt,
|
|
19
|
+
children: [
|
|
20
|
+
e,
|
|
21
|
+
" ",
|
|
22
|
+
/* @__PURE__ */ r(o, {
|
|
23
|
+
to: c,
|
|
24
|
+
children: a
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { o as AuthLink, s as AuthPrompt };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=AuthLinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthLinks.js","names":["styles","AuthForm_module_default","AuthLink","href","vettedHref","to","Link","cn","className","AuthPrompt","prompt","label"],"sources":["../../../src/components/AuthForm/AuthLinks.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Link } from \"react-router\";\nimport { cn } from \"@/utils/cn\";\nimport { vettedHref } from \"@/utils/safe-url\";\nimport styles from \"./AuthForm.module.css\";\n\n/**\n * A router link styled as the auth screens' inline action.\n *\n * Router `Link`, not `<a>`: the screens it connects are routes of the same app,\n * and a full reload between login and sign-up throws away the query cache and\n * any form state the user typed.\n *\n * `to` is vetted with `safeLinkUrl`'s allowlist before it reaches the `Link`, and a\n * destination it rejects renders nothing. The router's `Link` writes the string to\n * the anchor's `href`: React 19 replaces a `javascript:` href with a throwing stub,\n * but React 18 — inside the peer range — writes it verbatim, so an app that fills\n * `links` from a tenant's config or a query string would ship a clickable script\n * link. A dropped link is the same outcome as an unset route.\n *\n * @param props - Destination, content and an extra class.\n * @returns The link, or `null` when the destination is not a safe URL.\n */\nexport function AuthLink({\n to,\n children,\n className,\n}: {\n to: string;\n children: ReactNode;\n className?: string;\n}): ReactNode {\n const href = vettedHref(to);\n if (href === undefined) return null;\n return (\n <Link to={href} className={cn(styles.link, className)}>\n {children}\n </Link>\n );\n}\n\n/**\n * The \"Não tem uma conta? Cadastre-se\" line under a form.\n *\n * @param props - The leading sentence, the link text and its destination.\n * @returns The paragraph, or `null` when there is no destination or it is not\n * a safe URL (see {@link AuthLink}).\n */\nexport function AuthPrompt({\n prompt,\n label,\n to,\n}: {\n prompt: ReactNode;\n label: ReactNode;\n to: string | undefined;\n}): ReactNode {\n const href = vettedHref(to);\n if (href === undefined) return null;\n return (\n <p className={styles.prompt}>\n {prompt} <AuthLink to={href}>{label}</AuthLink>\n </p>\n );\n}\n"],"mappings":";;;;;;AAuBA,SAAgBE,EAAS,EACrB,OACA,aACA,gBAKU;CACV,IAAMC,IAAOC,EAAWC,CAAE;CAE1B,OADIF,MAAS,KAAA,IAAkB,OAE3B,kBAACG,GAAD;EAAM,IAAIH;EAAM,WAAWI,EAAGP,EAAO,MAAMQ,CAAS;EAC/C;CACC,CAAA;AAEd;AASA,SAAgBC,EAAW,EACvB,WACA,UACA,SAKU;CACV,IAAMN,IAAOC,EAAWC,CAAE;CAE1B,OADIF,MAAS,KAAA,IAAkB,OAE3B,kBAAC,KAAD;EAAG,WAAWH,EAAO;EAArB,UAAA;GACKU;GAAO;GAAC,kBAACR,GAAD;IAAU,IAAIC;IAAO,UAAAQ;GAAgB,CAAA;EAC/C;;AAEX"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./auth-defaults.cjs"),t=require("./AuthForm.cjs"),n=require("./AuthLinks.cjs"),r=require("./auth-schemas.cjs");let i=require("react/jsx-runtime");var a={signInPrompt:`Lembrou a senha?`,signIn:`Entrar`};function o({schema:o,fields:s,links:c,labels:l,submitLabel:u=`Enviar link`,...d}){let f={...a,...l};return(0,i.jsx)(t.AuthForm,{...d,schema:o??r.forgotPasswordSchema,fields:s??e.FORGOT_PASSWORD_FIELDS,labels:l,submitLabel:u,afterSubmit:(0,i.jsx)(n.AuthPrompt,{prompt:f.signInPrompt,label:f.signIn,to:c?.signIn})})}exports.ForgotPasswordForm=o;
|
|
2
|
+
//# sourceMappingURL=ForgotPasswordForm.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForgotPasswordForm.cjs","names":["AuthForm","forgotPasswordSchema","FORGOT_PASSWORD_FIELDS","AuthPrompt","require_auth_defaults","require_AuthForm","require_AuthLinks","require_auth_schemas","react_jsx_runtime","DEFAULT_LABELS","ForgotPasswordForm","props","text","labels","schema","fields","links"],"sources":["../../../src/components/AuthForm/ForgotPasswordForm.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { z } from \"zod\";\nimport { AuthForm } from \"./AuthForm\";\nimport { FORGOT_PASSWORD_FIELDS } from \"./auth-defaults\";\nimport { AuthPrompt } from \"./AuthLinks\";\nimport { forgotPasswordSchema } from \"./auth-schemas\";\nimport type { AuthField, AuthFieldName, AuthFormLabels, AuthPresetProps } from \"./types\";\n\n/** Sentences of {@link ForgotPasswordForm}, PT-BR by default. */\nexport interface ForgotPasswordFormLabels extends AuthFormLabels {\n /** Default `\"Lembrou a senha?\"`. */\n signInPrompt: string;\n /** Default `\"Entrar\"`. */\n signIn: string;\n}\n\n/** Routes the forgot-password form links to. */\nexport interface ForgotPasswordFormLinks {\n /** \"Entrar\" link, under the form. */\n signIn?: string;\n}\n\nexport interface ForgotPasswordFormProps<\n TSchema extends z.ZodTypeAny = typeof forgotPasswordSchema,\n> extends AuthPresetProps<TSchema> {\n /** Where the links go. */\n links?: ForgotPasswordFormLinks;\n /** Overrides for the fixed sentences. */\n labels?: Partial<ForgotPasswordFormLabels>;\n}\n\nconst DEFAULT_LABELS: Omit<ForgotPasswordFormLabels, keyof AuthFormLabels> = {\n signInPrompt: \"Lembrou a senha?\",\n signIn: \"Entrar\",\n};\n\n/**\n * \"Forgot password\" form: the e-mail the reset link goes to.\n *\n * The confirmation screen after a successful submit is the app's call — most\n * backends answer the same whether or not the address exists, so the copy\n * belongs next to the backend's policy, not here.\n *\n * @example\n * const [sent, setSent] = useState(false);\n * <ForgotPasswordForm\n * onSubmit={async (values) => { await api.post(\"/auth/forgot-password\", { body: values }); setSent(true); }}\n * links={{ signIn: \"/login\" }}\n * />\n */\nexport function ForgotPasswordForm<TSchema extends z.ZodTypeAny = typeof forgotPasswordSchema>({\n schema,\n fields,\n links,\n labels,\n submitLabel = \"Enviar link\",\n ...props\n}: ForgotPasswordFormProps<TSchema>): ReactNode {\n const text = { ...DEFAULT_LABELS, ...labels };\n return (\n <AuthForm<TSchema>\n {...props}\n schema={schema ?? (forgotPasswordSchema as unknown as TSchema)}\n fields={\n fields ?? (FORGOT_PASSWORD_FIELDS as readonly AuthField<AuthFieldName<TSchema>>[])\n }\n labels={labels}\n submitLabel={submitLabel}\n afterSubmit={\n <AuthPrompt prompt={text.signInPrompt} label={text.signIn} to={links?.signIn} />\n }\n />\n );\n}\n"],"mappings":"A,mKA+BA,IAAMS,EAAuE,CACzE,aAAc,mBACd,OAAQ,QACZ,EAgBA,SAAgBC,EAA+E,CAC3F,SACA,SACA,QACA,SACA,cAAc,cACd,GAAGC,GACyC,CAC5C,IAAMC,EAAO,CAAE,GAAGH,EAAgB,GAAGI,CAAO,EAC5C,OACI,EAAAL,EAAA,IAAA,CAACR,EAAAA,SAAD,CACI,GAAIW,EACJ,OAAQG,GAAWb,EAAAA,qBACnB,OACIc,GAAWb,EAAAA,uBAEP,SACK,cACb,aACI,EAAAM,EAAA,IAAA,CAACL,EAAAA,WAAD,CAAY,OAAQS,EAAK,aAAc,MAAOA,EAAK,OAAQ,GAAII,GAAO,MAAS,CAAA,CAEtF,CAAA,CAET,C"}
|