tempest-react-sdk 0.38.2 → 0.38.3
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/bin/lib/design/collect.mjs +19 -0
- package/bin/lib/design/functions.mjs +5 -0
- package/bin/lib/design/index.mjs +8 -3
- package/bin/lib/design/index.test.mjs +31 -0
- package/bin/lib/design/scan.mjs +34 -2
- package/bin/lib/design/scan.test.mjs +78 -0
- package/bin/lib/doctor/doctor.e2e.test.mjs +85 -0
- package/bin/tempest.mjs +90 -6
- package/dist/audio/level-meter.cjs.map +1 -1
- package/dist/audio/level-meter.js.map +1 -1
- package/dist/audio/use-audio-recorder.cjs.map +1 -1
- package/dist/audio/use-audio-recorder.js.map +1 -1
- package/dist/auth/passkey.cjs.map +1 -1
- package/dist/auth/passkey.js.map +1 -1
- package/dist/auth/use-passkey.cjs.map +1 -1
- package/dist/auth/use-passkey.js.map +1 -1
- package/dist/br/BrazilMap.cjs.map +1 -1
- package/dist/br/BrazilMap.js.map +1 -1
- package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
- package/dist/br/BrazilStateCitySelect.js.map +1 -1
- package/dist/br/BrazilStateMap.cjs.map +1 -1
- package/dist/br/BrazilStateMap.js.map +1 -1
- package/dist/br/PixQRCode.cjs.map +1 -1
- package/dist/br/PixQRCode.js.map +1 -1
- package/dist/br/boleto.cjs.map +1 -1
- package/dist/br/boleto.js.map +1 -1
- package/dist/br/pix.cjs.map +1 -1
- package/dist/br/pix.js.map +1 -1
- package/dist/br.d.ts +8 -0
- package/dist/capture/media-recorder.cjs.map +1 -1
- package/dist/capture/media-recorder.js.map +1 -1
- package/dist/capture/use-barcode-scanner.cjs.map +1 -1
- package/dist/capture/use-barcode-scanner.js.map +1 -1
- package/dist/capture/use-screen-capture.cjs.map +1 -1
- package/dist/capture/use-screen-capture.js.map +1 -1
- package/dist/capture/use-speech-recognition.cjs.map +1 -1
- package/dist/capture/use-speech-recognition.js.map +1 -1
- package/dist/capture/use-video-recorder.cjs.map +1 -1
- package/dist/capture/use-video-recorder.js.map +1 -1
- package/dist/charts/types.cjs.map +1 -1
- package/dist/charts/types.js.map +1 -1
- package/dist/charts.d.ts +8 -0
- package/dist/components/AIChat/AIChat.cjs.map +1 -1
- package/dist/components/AIChat/AIChat.js.map +1 -1
- package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
- package/dist/components/AIChat/AIChatComposer.js.map +1 -1
- package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
- package/dist/components/AIChat/AIChatTurn.js.map +1 -1
- package/dist/components/AppBar/AppBar.cjs.map +1 -1
- package/dist/components/AppBar/AppBar.js.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
- package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
- package/dist/components/Button/Button.cjs.map +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Calendar/Calendar.cjs.map +1 -1
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Carousel/Carousel.cjs.map +1 -1
- package/dist/components/Carousel/Carousel.js.map +1 -1
- package/dist/components/Chat/Chat.cjs.map +1 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
- package/dist/components/ChipInput/ChipInput.js.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
- package/dist/components/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Command/Command.cjs.map +1 -1
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
- package/dist/components/CopyButton/CopyButton.js.map +1 -1
- package/dist/components/DataTable/DataTable.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.module.js.map +1 -1
- package/dist/components/DataTable/EditableCell.cjs.map +1 -1
- package/dist/components/DataTable/EditableCell.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/Drawer/Drawer.cjs.map +1 -1
- package/dist/components/Drawer/Drawer.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
- package/dist/components/Dropzone/Dropzone.js.map +1 -1
- package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
- package/dist/components/FileUpload/FileUpload.js.map +1 -1
- package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar/FilterBar.js.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
- package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
- package/dist/components/Kanban/Kanban.cjs.map +1 -1
- package/dist/components/Kanban/Kanban.js.map +1 -1
- package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
- package/dist/components/Lightbox/Lightbox.js.map +1 -1
- package/dist/components/ListTile/ListTile.cjs.map +1 -1
- package/dist/components/ListTile/ListTile.js.map +1 -1
- package/dist/components/Markdown/Markdown.cjs.map +1 -1
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Markdown/markdown-parse.cjs.map +1 -1
- package/dist/components/Markdown/markdown-parse.js.map +1 -1
- package/dist/components/Menubar/Menubar.cjs.map +1 -1
- package/dist/components/Menubar/Menubar.js.map +1 -1
- package/dist/components/Modal/Modal.cjs.map +1 -1
- package/dist/components/Modal/Modal.js.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
- package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
- package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
- package/dist/components/Page/Page.cjs.map +1 -1
- package/dist/components/Page/Page.js.map +1 -1
- package/dist/components/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
- package/dist/components/PinInput/PinInput.cjs.map +1 -1
- package/dist/components/PinInput/PinInput.js.map +1 -1
- package/dist/components/Popover/Popover.cjs.map +1 -1
- package/dist/components/Popover/Popover.js.map +1 -1
- package/dist/components/Progress/Progress.cjs.map +1 -1
- package/dist/components/Progress/Progress.js.map +1 -1
- package/dist/components/QRCode/qr-encode.cjs.map +1 -1
- package/dist/components/QRCode/qr-encode.js.map +1 -1
- package/dist/components/Radio/Radio.cjs.map +1 -1
- package/dist/components/Radio/Radio.js.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
- package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
- package/dist/components/RatingStars/RatingStars.js.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
- package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
- package/dist/components/Resizable/Resizable.cjs.map +1 -1
- package/dist/components/Resizable/Resizable.js.map +1 -1
- package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
- package/dist/components/Scheduler/Scheduler.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/SignaturePad/SignaturePad.cjs.map +1 -1
- package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
- package/dist/components/Slider/Slider.cjs.map +1 -1
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
- package/dist/components/Sparkline/Sparkline.js.map +1 -1
- package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
- package/dist/components/StepperInput/StepperInput.js.map +1 -1
- package/dist/components/Table/Table.cjs.map +1 -1
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
- package/dist/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/Toast/ToastProvider.cjs.map +1 -1
- package/dist/components/Toast/ToastProvider.js.map +1 -1
- package/dist/components/Tour/Tour.cjs.map +1 -1
- package/dist/components/Tour/Tour.js.map +1 -1
- package/dist/components/Transfer/Transfer.cjs.map +1 -1
- package/dist/components/Transfer/Transfer.js.map +1 -1
- package/dist/components/TreeView/TreeView.cjs.map +1 -1
- package/dist/components/TreeView/TreeView.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
- package/dist/components/Wizard/Wizard.cjs.map +1 -1
- package/dist/components/Wizard/Wizard.js.map +1 -1
- package/dist/editor/RichTextEditor.cjs.map +1 -1
- package/dist/editor/RichTextEditor.js.map +1 -1
- package/dist/forms/FormField.cjs.map +1 -1
- package/dist/forms/FormField.js.map +1 -1
- package/dist/geo/TrajectoryMap.cjs.map +1 -1
- package/dist/geo/TrajectoryMap.js.map +1 -1
- package/dist/geo/estimate.cjs.map +1 -1
- package/dist/geo/estimate.js.map +1 -1
- package/dist/geo/projection.cjs.map +1 -1
- package/dist/geo/projection.js.map +1 -1
- package/dist/hooks/use-event-listener.cjs.map +1 -1
- package/dist/hooks/use-event-listener.js.map +1 -1
- package/dist/hooks/use-local-storage.cjs.map +1 -1
- package/dist/hooks/use-local-storage.js.map +1 -1
- package/dist/hooks/use-sortable.cjs.map +1 -1
- package/dist/hooks/use-sortable.js.map +1 -1
- package/dist/http/api-client.cjs.map +1 -1
- package/dist/http/api-client.js.map +1 -1
- package/dist/http/errors.cjs.map +1 -1
- package/dist/http/errors.js.map +1 -1
- package/dist/http/resumable-upload.cjs.map +1 -1
- package/dist/http/resumable-upload.js.map +1 -1
- package/dist/http/upload-with-progress.cjs.map +1 -1
- package/dist/http/upload-with-progress.js.map +1 -1
- package/dist/i18n/I18nProvider.cjs.map +1 -1
- package/dist/i18n/I18nProvider.js.map +1 -1
- package/dist/imaging/canvas.cjs.map +1 -1
- package/dist/imaging/canvas.js.map +1 -1
- package/dist/imaging.d.ts +5 -0
- package/dist/logger/logger.cjs.map +1 -1
- package/dist/logger/logger.js.map +1 -1
- package/dist/oauth/GoogleSignIn.cjs.map +1 -1
- package/dist/oauth/GoogleSignIn.js.map +1 -1
- package/dist/offline/create-offline-sync.cjs.map +1 -1
- package/dist/offline/create-offline-sync.js.map +1 -1
- package/dist/perf/cache-size.cjs +1 -1
- package/dist/perf/cache-size.cjs.map +1 -1
- package/dist/perf/cache-size.js +27 -6
- package/dist/perf/cache-size.js.map +1 -1
- package/dist/sse/create-event-stream.cjs.map +1 -1
- package/dist/sse/create-event-stream.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/sw/background-sync.cjs.map +1 -1
- package/dist/sw/background-sync.js.map +1 -1
- package/dist/sw/cache.cjs.map +1 -1
- package/dist/sw/cache.js.map +1 -1
- package/dist/sw.d.ts +12 -0
- package/dist/tabular/compact.cjs.map +1 -1
- package/dist/tabular/compact.js.map +1 -1
- package/dist/tabular/predictor.cjs.map +1 -1
- package/dist/tabular/predictor.js.map +1 -1
- package/dist/tabular.d.ts +7 -2
- package/dist/tempest-react-sdk.d.ts +133 -6
- package/dist/theme/ThemeProvider.cjs.map +1 -1
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/color.cjs.map +1 -1
- package/dist/theme/color.js.map +1 -1
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/data-viz-ramps.cjs +1 -1
- package/dist/theme/data-viz-ramps.cjs.map +1 -1
- package/dist/theme/data-viz-ramps.js +1 -1
- package/dist/theme/data-viz-ramps.js.map +1 -1
- package/dist/utils/storage.cjs.map +1 -1
- package/dist/utils/storage.js.map +1 -1
- package/dist/vision/core/canvas.cjs.map +1 -1
- package/dist/vision/core/canvas.js.map +1 -1
- package/dist/vision/core/exceptions.cjs.map +1 -1
- package/dist/vision/core/exceptions.js.map +1 -1
- package/dist/vision/core/graph.cjs.map +1 -1
- package/dist/vision/core/graph.js.map +1 -1
- package/dist/vision/core/metadata.cjs.map +1 -1
- package/dist/vision/core/metadata.js.map +1 -1
- package/dist/vision/core/providers.cjs.map +1 -1
- package/dist/vision/core/providers.js.map +1 -1
- package/dist/vision/core/session.cjs.map +1 -1
- package/dist/vision/core/session.js.map +1 -1
- package/dist/vision/core/timing.cjs.map +1 -1
- package/dist/vision/core/timing.js.map +1 -1
- package/dist/vision/io/image.cjs.map +1 -1
- package/dist/vision/io/image.js.map +1 -1
- package/dist/vision/labels.cjs.map +1 -1
- package/dist/vision/labels.js.map +1 -1
- package/dist/vision/luminance.cjs.map +1 -1
- package/dist/vision/luminance.js.map +1 -1
- package/dist/vision/postprocess/classification.cjs.map +1 -1
- package/dist/vision/postprocess/classification.js.map +1 -1
- package/dist/vision/postprocess/detection.cjs.map +1 -1
- package/dist/vision/postprocess/detection.js.map +1 -1
- package/dist/vision/postprocess/segmentation.cjs.map +1 -1
- package/dist/vision/postprocess/segmentation.js.map +1 -1
- package/dist/vision/preprocess/image.cjs.map +1 -1
- package/dist/vision/preprocess/image.js.map +1 -1
- package/dist/vision/results.cjs.map +1 -1
- package/dist/vision/results.js.map +1 -1
- package/dist/vision/tasks/base.cjs.map +1 -1
- package/dist/vision/tasks/base.js.map +1 -1
- package/dist/vision/tasks/classifier.cjs.map +1 -1
- package/dist/vision/tasks/classifier.js.map +1 -1
- package/dist/vision/tasks/detector.cjs.map +1 -1
- package/dist/vision/tasks/detector.js.map +1 -1
- package/dist/vision/tasks/segmenter.cjs.map +1 -1
- package/dist/vision/tasks/segmenter.js.map +1 -1
- package/dist/vision/types.cjs.map +1 -1
- package/dist/vision/types.js.map +1 -1
- package/dist/vision.d.ts +6 -0
- package/dist/vite/tempest-icons.cjs.map +1 -1
- package/dist/vite/tempest-icons.js.map +1 -1
- package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
- package/dist/vite/tempest-pwa-icons.js.map +1 -1
- package/dist/ws/create-web-socket.cjs.map +1 -1
- package/dist/ws/create-web-socket.js.map +1 -1
- package/package.json +1 -1
package/dist/br/boleto.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boleto.cjs","names":[],"sources":["../../src/br/boleto.ts"],"sourcesContent":["/**\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":"AAMA,IAAa,EAAb,cAAiC,KAAM,CACnC,YAAY,EAAiB,CACzB,MAAM,CAAO,EACb,KAAK,KAAO,aAChB,CACJ,EA8FM,EAAmB,KAAK,IAAI,KAAM,EAAG,CAAC,EAStC,EAAoB,KAAK,IAAI,KAAM,EAAG,EAAE,EAExC,EAAa,MAGb,EAAY,IAGZ,EAAY,KAEZ,EAAgB,CAAC,EAAG,CAAC,EACrB,EAAqB,EAGrB,EAA0C,CAC5C,EAAG,cACH,EAAG,aACH,EAAG,yBACH,EAAG,mBACH,EAAG,wBACH,EAAG,2DACH,EAAG,qBACH,EAAG,wBACP,EAGM,EAAgB,EAGtB,SAAS,EAAO,EAAuB,CACnC,OAAO,EAAM,QAAQ,MAAO,EAAE,CAClC,CAiBA,SAAgB,EAAS,EAAuB,CAC5C,GAAI,CAAC,QAAQ,KAAK,CAAK,EACnB,MAAM,IAAI,EAAY,8BAA8B,KAAK,UAAU,CAAK,EAAE,EAAE,EAChF,IAAI,EAAM,EACV,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,GAAS,EAAG,CAClD,IAAM,EAAY,EAAM,OAAS,EAAI,EAC/B,EAAU,OAAO,EAAM,EAAM,EAAI,EAAc,EAAY,EAAc,QAC/E,GAAO,EAAU,EAAI,EAAU,EAAI,CACvC,CACA,IAAM,EAAY,EAAM,GACxB,OAAO,IAAc,EAAI,EAAI,GAAK,CACtC,CAGA,SAAS,EAAS,EAAuB,CACrC,IACI,EAAM,EACV,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,GAAS,EAAG,CAClD,IAAM,EAAY,EAAM,OAAS,EAAI,EACrC,GAAO,OAAO,EAAM,EAAM,GAAK,EAAsB,EAAY,EACrE,CACA,OAAO,CACX,CAkBA,SAAgB,EAAiB,EAAuB,CACpD,GAAI,CAAC,QAAQ,KAAK,CAAK,EACnB,MAAM,IAAI,EAAY,sCAAsC,KAAK,UAAU,CAAK,EAAE,EAAE,EAExF,IAAM,EAAY,EAAS,CAAK,EAAI,GACpC,OAAO,IAAc,GAAK,IAAc,GAAK,IAAc,GAAK,EAAI,GAAK,CAC7E,CAiBA,SAAgB,EAAoB,EAAuB,CACvD,GAAI,CAAC,QAAQ,KAAK,CAAK,EACnB,MAAM,IAAI,EAAY,yCAAyC,KAAK,UAAU,CAAK,EAAE,EAAE,EAE3F,IAAM,EAAY,EAAS,CAAK,EAAI,GACpC,OAAO,IAAc,GAAK,IAAc,EAAI,EAAI,GAAK,CACzD,CAQA,SAAgB,EAAW,EAAkC,CACzD,IAAM,EAAM,EAAO,CAAK,EAIxB,OAHI,EAAI,SAAW,GAAW,QAC1B,EAAI,SAAW,GAAW,cAC1B,EAAI,SAAW,GAAW,EAAI,WAAW,GAAG,EAAI,cAAgB,QAC7D,IACX,CAGA,SAAS,EAAS,EAAoB,EAAoB,CACtD,IAAM,EAAM,IAAI,KAAK,EAAa,EAAO,CAAU,EACnD,OAAO,IAAI,KAAK,EAAI,eAAe,EAAG,EAAI,YAAY,EAAG,EAAI,WAAW,CAAC,CAC7E,CAyBA,SAAgB,EACZ,EACA,EAAyB,CAAC,EACgC,CAC1D,GAAI,IAAU,EAAG,OAAO,KACxB,GAAM,CAAE,QAAQ,OAAQ,YAAY,IAAI,MAAW,EAEnD,GAAI,IAAU,SAAU,MAAO,CAAE,KAAM,EAAS,EAAkB,CAAK,EAAG,MAAO,QAAS,EAC1F,GAAI,IAAU,UAAW,MAAO,CAAE,KAAM,EAAS,EAAmB,CAAK,EAAG,MAAO,SAAU,EAE7F,IAAM,EAAS,EAAS,EAAkB,CAAK,EAC/C,GAAI,EAAQ,EAAW,MAAO,CAAE,KAAM,EAAQ,MAAO,QAAS,EAC9D,IAAM,EAAU,EAAS,EAAmB,CAAK,EAC3C,EAAK,EAAU,QAAQ,EAC7B,OAAO,KAAK,IAAI,EAAQ,QAAQ,EAAI,CAAE,GAAK,KAAK,IAAI,EAAO,QAAQ,EAAI,CAAE,EACnE,CAAE,KAAM,EAAS,MAAO,SAAU,EAClC,CAAE,KAAM,EAAQ,MAAO,QAAS,CAC1C,CAeA,SAAgB,EACZ,EACA,EAAsC,UAChC,CACN,IAAM,EAAO,IAAU,SAAW,EAAmB,EAC/C,EAAS,KAAK,IAAI,EAAK,YAAY,EAAG,EAAK,SAAS,EAAG,EAAK,QAAQ,CAAC,EACrE,EAAQ,KAAK,OAAO,EAAS,GAAQ,CAAU,EACrD,GAAI,EAAQ,GAAa,EAAQ,EAC7B,MAAM,IAAI,EACN,GAAG,EAAK,YAAY,CAAC,CAAC,MAAM,EAAG,EAAE,EAAE,YAAY,EAAM,cAAc,EAAM,uBACtD,EAAU,GAAG,EAAU,kBAC9C,EAEJ,OAAO,CACX,CASA,SAAS,EAAe,EAAiC,CACrD,IAAM,EAAO,EAAW,MAAM,EAAG,CAAC,EAC5B,EAAO,OAAO,EAAK,MAAM,EAAG,CAAC,CAAC,EAC9B,EAAQ,OAAO,EAAK,MAAM,EAAG,CAAC,CAAC,EAC/B,EAAM,OAAO,EAAK,MAAM,EAAG,CAAC,CAAC,EACnC,GAAI,EAAO,MAAQ,EAAO,MAAQ,EAAQ,GAAK,EAAQ,IAAM,EAAM,GAAK,EAAM,GAAI,OAAO,KACzF,IAAM,EAAO,IAAI,KAAK,EAAM,EAAQ,EAAG,CAAG,EAC1C,OAAO,EAAK,SAAS,IAAM,EAAQ,GAAK,EAAK,QAAQ,IAAM,EAAM,EAAO,IAC5E,CAGA,SAAS,EAAW,EAAyB,CACzC,IAAM,EAAa,EAAQ,MAAM,EAAE,EAC7B,EAAS,EAAQ,MAAM,EAAG,CAAC,EAAI,EAAW,MAAM,EAAG,CAAC,EACpD,EAAS,EAAW,MAAM,EAAG,EAAE,EAC/B,EAAS,EAAW,MAAM,GAAI,EAAE,EACtC,OACI,EACA,EAAS,CAAM,EACf,EACA,EAAS,CAAM,EACf,EACA,EAAS,CAAM,EACf,EAAQ,MAAM,EAAG,CAAC,EAClB,EAAQ,MAAM,EAAG,EAAE,CAE3B,CAGA,SAAS,EAAiB,EAAyB,CAC/C,IAAM,EAAM,EAAc,CAAO,IAAM,GAAK,EAAsB,EAC9D,EAAO,GACX,IAAK,IAAI,EAAQ,EAAG,EAAQ,GAAI,GAAS,GAAI,CACzC,IAAM,EAAQ,EAAQ,MAAM,EAAO,EAAQ,EAAE,EAC7C,GAAQ,EAAQ,EAAI,CAAK,CAC7B,CACA,OAAO,CACX,CAGA,SAAS,EAAc,EAA0B,CAC7C,OAAO,EAAQ,KAAO,KAAO,EAAQ,KAAO,IAAM,GAAK,EAC3D,CAGA,SAAS,EAAU,EAAiB,EAAqC,CACrE,IAAM,EAAQ,OAAO,EAAQ,MAAM,EAAG,CAAC,CAAC,EAClC,EAAM,EAAc,EAAO,CAAO,EAClC,EAAQ,EAAQ,MAAM,EAAG,CAAC,EAChC,MAAO,CACH,KAAM,QACN,aAAc,EACd,eAAgB,EAAW,CAAO,EAClC,MAAO,EAAQ,MAAM,EAAG,CAAC,EACzB,QACA,WAAY,IAAU,IAAM,OAAS,KACrC,GAAI,EAAQ,MAAM,EAAG,CAAC,EACtB,gBAAiB,EACjB,WAAY,GAAK,MAAQ,KACzB,gBAAiB,GAAK,OAAS,KAC/B,MAAO,OAAO,EAAQ,MAAM,EAAG,EAAE,CAAC,EAAI,IACtC,WAAY,EAAQ,MAAM,EAAE,CAChC,CACJ,CAGA,SAAS,EAAgB,EAAoC,CACzD,IAAM,EAAW,OAAO,EAAQ,EAAE,EAC5B,EAAqB,OAAO,EAAQ,EAAE,EACtC,EAAgB,IAAa,EAC7B,EAAa,EAAgB,EAAQ,MAAM,EAAE,EAAI,EAAQ,MAAM,EAAE,EACjE,EAAW,EAAQ,MAAM,EAAG,EAAE,EAC9B,EAAU,IAAuB,GAAK,IAAuB,EACnE,MAAO,CACH,KAAM,cACN,aAAc,EACd,eAAgB,EAAiB,CAAO,EACxC,WACA,cAAe,EAAgB,IAAa,KAC5C,qBACA,SAAU,EAAc,CAAO,EAC/B,GAAI,EAAQ,MAAM,EAAG,CAAC,EACtB,MAAO,EAAU,OAAO,CAAQ,EAAI,IAAM,KAC1C,WACA,QAAS,EAAgB,EAAQ,MAAM,GAAI,EAAE,EAAI,EAAQ,MAAM,GAAI,EAAE,EACrE,gBACA,aACA,qBAAsB,EAAe,CAAU,CACnD,CACJ,CAGA,SAAS,EAAgB,EAAuB,CAC5C,GAAI,EAAQ,WAAW,GAAG,EAAG,CACzB,IAAM,EAAO,EAAQ,MAAM,EAAG,CAAC,EAAI,EAAQ,MAAM,CAAC,EAC5C,EAAM,EAAc,CAAO,IAAM,GAAK,EAAoB,CAAI,EAAI,EAAS,CAAI,EACrF,GAAI,OAAO,CAAG,IAAM,EAAQ,GACxB,MAAM,IAAI,EACN,8BAA8B,EAAQ,GAAG,eAAe,EAAI,WAAW,EAAc,CAAO,EAAE,GAClG,EAEJ,MACJ,CACA,IAAM,EAAM,EAAiB,EAAQ,MAAM,EAAG,CAAC,EAAI,EAAQ,MAAM,CAAC,CAAC,EACnE,GAAI,OAAO,CAAG,IAAM,EAAQ,GACxB,MAAM,IAAI,EAAY,0BAA0B,EAAQ,GAAG,eAAe,EAAI,EAAE,CAExF,CAGA,SAAS,EAAyB,EAAuB,CACrD,GAAI,CAAC,OAAO,SAAS,EAAQ,EAAG,EAC5B,MAAM,IAAI,EACN,2FAA2F,EAAQ,GAAG,EAC1G,CAER,CAmBA,SAAgB,EAAkB,EAAe,EAAyB,CAAC,EAAW,CAClF,IAAM,EAAU,EAAO,CAAK,EAC5B,GAAI,EAAQ,SAAW,GACnB,MAAM,IAAI,EACN,gCAAgC,EAAQ,OAAO,sEAEnD,EAQJ,OANI,EAAQ,WAAW,GAAG,GACtB,EAAyB,CAAO,EAChC,EAAgB,CAAO,EAChB,EAAgB,CAAO,IAElC,EAAgB,CAAO,EAChB,EAAU,EAAS,CAAO,EACrC,CAkBA,SAAgB,EAAoB,EAAe,EAAyB,CAAC,EAAW,CACpF,IAAM,EAAO,EAAO,CAAK,EACzB,GAAI,EAAK,SAAW,GAAI,OAAO,EAAkB,EAAa,CAAI,EAAG,CAAO,EAC5E,GAAI,EAAK,SAAW,GAAI,OAAO,EAAkB,EAAmB,CAAI,EAAG,CAAO,EAClF,MAAM,IAAI,EACN,8DAA8D,EAAK,OAAO,0DAE9E,CACJ,CAGA,SAAS,EAAa,EAAsB,CAcxC,MARA,CAJI,CAAC,EAAK,MAAM,EAAG,CAAC,EAAG,EAAK,MAAM,EAAG,EAAE,CAAC,EACpC,CAAC,EAAK,MAAM,GAAI,EAAE,EAAG,EAAK,MAAM,GAAI,EAAE,CAAC,EACvC,CAAC,EAAK,MAAM,GAAI,EAAE,EAAG,EAAK,MAAM,GAAI,EAAE,CAAC,CAE3C,CAAA,CAAO,SAAS,CAAC,EAAM,GAAK,IAAU,CAClC,IAAM,EAAM,EAAS,CAAI,EACzB,GAAI,OAAO,CAAG,IAAM,EAChB,MAAM,IAAI,EACN,SAAS,EAAQ,EAAE,kBAAkB,EAAG,eAAe,EAAI,cAC/D,CAER,CAAC,EAEG,EAAK,MAAM,EAAG,CAAC,EACf,EAAK,MAAM,GAAI,EAAE,EACjB,EAAK,MAAM,GAAI,EAAE,EACjB,EAAK,MAAM,EAAG,CAAC,EACf,EAAK,MAAM,GAAI,EAAE,EACjB,EAAK,MAAM,GAAI,EAAE,CAEzB,CAGA,SAAS,EAAmB,EAAsB,CAC9C,IAAM,EAAS,CAAC,EAAG,GAAI,GAAI,EAAE,CAAC,CAAC,IAAK,IAAW,CAC3C,KAAM,EAAK,MAAM,EAAO,EAAQ,EAAE,EAClC,GAAI,EAAK,MAAM,EAAQ,GAAI,EAAQ,EAAE,CACzC,EAAE,EACI,EAAU,EAAO,IAAK,GAAU,EAAM,IAAI,CAAC,CAAC,KAAK,EAAE,EACzD,GAAI,CAAC,EAAQ,WAAW,GAAG,EACvB,MAAM,IAAI,EACN,2EAA2E,EAAQ,GAAG,EAC1F,EAEJ,EAAyB,CAAO,EAChC,IAAM,EAAM,EAAc,CAAO,IAAM,GAAK,EAAsB,EAUlE,OATA,EAAO,SAAS,EAAO,IAAU,CAC7B,IAAM,EAAW,EAAI,EAAM,IAAI,EAC/B,GAAI,OAAO,CAAQ,IAAM,EAAM,GAC3B,MAAM,IAAI,EACN,SAAS,EAAQ,EAAE,kBAAkB,EAAM,GAAG,eAAe,EAAS,WACvD,EAAc,CAAO,EAAE,GAC1C,CAER,CAAC,EACM,CACX,CASA,SAAgB,EAA6B,EAAuB,CAChE,OAAO,EAAoB,CAAK,CAAC,CAAC,YACtC,CAUA,SAAgB,EAA6B,EAAuB,CAChE,OAAO,EAAkB,CAAK,CAAC,CAAC,cACpC,CAgBA,SAAgB,EAAe,EAAwB,CACnD,GAAI,CACA,IAAM,EAAM,EAAO,CAAK,EAGxB,OAFI,EAAI,SAAW,GAAI,EAAkB,CAAG,EACvC,EAAoB,CAAG,EACrB,EACX,MAAQ,CACJ,MAAO,EACX,CACJ,CAgBA,SAAgB,EAAqB,EAAuB,CACxD,IAAM,EAAO,EAAO,CAAK,EAazB,OAZI,EAAK,SAAW,GACT,CACH,GAAG,EAAK,MAAM,EAAG,CAAC,EAAE,GAAG,EAAK,MAAM,EAAG,EAAE,IACvC,GAAG,EAAK,MAAM,GAAI,EAAE,EAAE,GAAG,EAAK,MAAM,GAAI,EAAE,IAC1C,GAAG,EAAK,MAAM,GAAI,EAAE,EAAE,GAAG,EAAK,MAAM,GAAI,EAAE,IAC1C,EAAK,MAAM,GAAI,EAAE,EACjB,EAAK,MAAM,EAAE,CACjB,CAAC,CAAC,KAAK,GAAG,EAEV,EAAK,SAAW,GACT,CAAC,EAAG,GAAI,GAAI,EAAE,CAAC,CAAC,IAAK,GAAU,EAAK,MAAM,EAAO,EAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,EAE1E,CACX"}
|
|
1
|
+
{"version":3,"file":"boleto.cjs","names":[],"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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"}
|
package/dist/br/boleto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boleto.js","names":[],"sources":["../../src/br/boleto.ts"],"sourcesContent":["/**\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":[],"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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"}
|
package/dist/br/pix.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pix.cjs","names":[],"sources":["../../src/br/pix.ts"],"sourcesContent":["import { validateCNPJ, validateCPF } from \"@/forms/br-validators\";\n\n/**\n * A Pix payload could not be built or read.\n *\n * Its own class so a caller can tell \"the operator typed a bad key\" apart from a\n * bug, and so an `ErrorBoundary` can render a form error instead of a crash.\n */\nexport class PixError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PixError\";\n }\n}\n\n/** The five key formats DICT accepts. */\nexport type PixKeyType = \"cpf\" | \"cnpj\" | \"email\" | \"phone\" | \"evp\";\n\n/** A key after normalisation, ready to go into the payload. */\nexport interface NormalizedPixKey {\n type: PixKeyType;\n /** The exact string written into the BR Code. */\n value: string;\n}\n\n/** One TLV as it appeared in a payload, unknown tags included. */\nexport interface PixField {\n /** Two-character tag, e.g. `\"59\"`. */\n id: string;\n /** Raw value, still encoded when the tag is itself a template. */\n value: string;\n}\n\n/** A BR Code that carries the key — the one you print on a poster. */\nexport interface PixStaticInput {\n kind?: \"static\";\n /** CPF, CNPJ, e-mail, phone or EVP. Validated and normalised. */\n key: string;\n /** Payee name. Truncated by the spec at 25 characters — longer throws. */\n merchantName: string;\n /** Payee city. Truncated by the spec at 15 characters — longer throws. */\n merchantCity: string;\n /** Amount in BRL. Omit for a payer-chooses-the-value QR. */\n amount?: number;\n /** Reference the PSP echoes back, `[A-Za-z0-9]{1,25}`. Defaults to `\"***\"`. */\n txid?: string;\n /** Free text shown by some wallets. Goes into tag 26, sub-tag 02. */\n description?: string;\n /** CEP, digits only. Optional tag 61. */\n postalCode?: string;\n /** Single-use QR: sets tag 01 to `\"12\"` instead of `\"11\"`. */\n oneTime?: boolean;\n}\n\n/** A BR Code that carries a URL the wallet fetches to learn the amount. */\nexport interface PixDynamicInput {\n kind: \"dynamic\";\n /**\n * `payloadLocation` — the https URL the wallet GETs, **without** the scheme,\n * exactly as BACEN specifies (`pix.example.com/qr/v2/abc`).\n */\n url: string;\n merchantName: string;\n merchantCity: string;\n postalCode?: string;\n /** Single-use QR. Defaults to `true`, which is what a dynamic QR normally is. */\n oneTime?: boolean;\n}\n\n/** Everything `pixPayload` accepts. */\nexport type PixInput = PixStaticInput | PixDynamicInput;\n\n/** A payload taken apart again. */\nexport interface PixData {\n /** `\"dynamic\"` when tag 26 carried a URL instead of a key. */\n kind: \"static\" | \"dynamic\";\n /** Present on a static payload. */\n key?: string;\n keyType?: PixKeyType;\n /** Present on a dynamic payload. */\n url?: string;\n merchantName: string;\n merchantCity: string;\n /** Reais. `undefined` when the payer chooses the amount. */\n amount?: number;\n /** ISO 4217 numeric. `\"986\"` for BRL. */\n currency: string;\n countryCode: string;\n merchantCategoryCode: string;\n /** `\"***\"` on a reusable static QR that identifies no single transaction. */\n txid?: string;\n description?: string;\n postalCode?: string;\n /** Tag 01 read as `\"12\"`. */\n oneTime: boolean;\n /** The four hex characters that closed the payload. */\n crc: string;\n /** Whether those four characters match a recomputed CRC. */\n crcValid: boolean;\n /** Every top-level TLV, in payload order, unknown tags included. */\n fields: PixField[];\n}\n\n/** Options for {@link parsePixPayload}. */\nexport interface ParsePixOptions {\n /**\n * Throw when the checksum does not match. Default `true`.\n *\n * Turn it off only to inspect a payload you already know is broken: a BR Code\n * whose CRC fails has been corrupted in transit, and the account it now points\n * at is not the account the payee published.\n */\n requireCrc?: boolean;\n}\n\n/**\n * Generator polynomial of CRC-16/CCITT-FALSE, `x^16 + x^12 + x^5 + 1`.\n *\n * Taken from the CRC catalogue entry `CRC-16/IBM-3740` (alias CCITT-FALSE):\n * `width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000\n * check=0x29b1`. The BACEN \"Manual de Padrões para Iniciação do Pix\" names this\n * exact variant for tag 63.\n */\nconst CRC16_POLYNOMIAL = 0x1021;\n\n/** Register preset of CRC-16/CCITT-FALSE. Not zero — that is a different variant. */\nconst CRC16_INITIAL = 0xffff;\n\n/** Keeps the shift register 16 bits wide. */\nconst CRC16_MASK = 0xffff;\n\nconst TAG_PAYLOAD_FORMAT = \"00\";\nconst TAG_POINT_OF_INITIATION = \"01\";\nconst TAG_MERCHANT_ACCOUNT_INFO = \"26\";\nconst TAG_MERCHANT_CATEGORY_CODE = \"52\";\nconst TAG_TRANSACTION_CURRENCY = \"53\";\nconst TAG_TRANSACTION_AMOUNT = \"54\";\nconst TAG_COUNTRY_CODE = \"58\";\nconst TAG_MERCHANT_NAME = \"59\";\nconst TAG_MERCHANT_CITY = \"60\";\nconst TAG_POSTAL_CODE = \"61\";\nconst TAG_ADDITIONAL_DATA = \"62\";\nconst TAG_CRC = \"63\";\n\nconst MAI_TAG_GUI = \"00\";\nconst MAI_TAG_KEY = \"01\";\nconst MAI_TAG_DESCRIPTION = \"02\";\nconst MAI_TAG_URL = \"25\";\nconst ADDITIONAL_TAG_TXID = \"05\";\n\n/** Globally Unique Identifier that marks tag 26 as a Pix account. */\nconst PIX_GUI = \"br.gov.bcb.pix\";\n\nconst PAYLOAD_FORMAT_VERSION = \"01\";\nconst POINT_OF_INITIATION_REUSABLE = \"11\";\nconst POINT_OF_INITIATION_SINGLE_USE = \"12\";\nconst DEFAULT_MERCHANT_CATEGORY_CODE = \"0000\";\nconst CURRENCY_BRL = \"986\";\nconst COUNTRY_BR = \"BR\";\nconst TXID_UNSPECIFIED = \"***\";\n\nconst MAX_MERCHANT_NAME = 25;\nconst MAX_MERCHANT_CITY = 15;\nconst MAX_TXID = 25;\nconst MAX_TLV_VALUE = 99;\nconst MAX_EMAIL_KEY = 77;\n\n/**\n * CRC-16/CCITT-FALSE of a string, as four upper-case hex characters.\n *\n * Bitwise rather than table-driven: 200-odd characters at 8 shifts each is\n * nothing, and a 256-entry table is 2 KB of payload every consumer of the `/br`\n * entry would carry.\n *\n * The input is taken as UTF-8 bytes. A Pix payload is ASCII by construction —\n * {@link pixPayload} rejects anything else — but the function is exported and a\n * caller may hand it arbitrary text, and hashing UTF-16 code units would then\n * disagree with every other implementation.\n *\n * @param input - Bytes to run through the register.\n * @returns Four upper-case hex characters, zero-padded.\n *\n * @example\n * pixCrc16(\"123456789\"); // \"29B1\" — the catalogue check value\n */\nexport function pixCrc16(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let crc = CRC16_INITIAL;\n for (const byte of bytes) {\n crc ^= byte << 8;\n for (let bit = 0; bit < 8; bit += 1) {\n crc =\n (crc & 0x8000) !== 0\n ? ((crc << 1) ^ CRC16_POLYNOMIAL) & CRC16_MASK\n : (crc << 1) & CRC16_MASK;\n }\n }\n return crc.toString(16).toUpperCase().padStart(4, \"0\");\n}\n\n/** Digits of a possibly masked value. */\nfunction digits(value: string): string {\n return value.replace(/\\D/g, \"\");\n}\n\n/**\n * Drop diacritics and reject whatever is left outside printable ASCII.\n *\n * The BR Code character set has no room for accents, and a wallet that meets one\n * either fails to parse the QR or shows mojibake. Stripping them is lossy but\n * legible (\"São Paulo\" → \"Sao Paulo\"), which beats both alternatives; anything\n * that is not a diacritic — an emoji, a CJK character — is a mistake the caller\n * has to see, so it throws.\n */\nfunction toPayloadText(value: string, field: string): string {\n const stripped = value.normalize(\"NFD\").replace(/\\p{Diacritic}/gu, \"\");\n if (/[^\\x20-\\x7E]/.test(stripped)) {\n throw new PixError(\n `${field} has characters the BR Code cannot carry: ${JSON.stringify(value)}. ` +\n \"Use unaccented ASCII.\",\n );\n }\n return stripped;\n}\n\n/** One `ID + 2-digit length + value` triple. */\nfunction tlv(id: string, value: string): string {\n if (value.length > MAX_TLV_VALUE) {\n throw new PixError(\n `Tag ${id} is ${value.length} characters; the EMV length field holds at most ${MAX_TLV_VALUE}.`,\n );\n }\n return `${id}${String(value.length).padStart(2, \"0\")}${value}`;\n}\n\n/**\n * Classify a Pix key, or `null` when it matches no accepted format.\n *\n * !!! warning \"CPF and a national phone number are both eleven digits\"\n * `\"11987654321\"` is a valid mobile number and could be a CPF. The check\n * digits break the tie: an 11-digit string is a CPF when its DV validates and\n * a phone otherwise. Pass phone keys as `+5511987654321` to remove the guess\n * entirely.\n *\n * @param key - Raw key, masked or not.\n * @returns The key type, or `null`.\n */\nexport function pixKeyType(key: string): PixKeyType | null {\n const trimmed = key.trim();\n if (trimmed === \"\") return null;\n\n if (trimmed.includes(\"@\")) {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/.test(trimmed) && trimmed.length <= MAX_EMAIL_KEY\n ? \"email\"\n : null;\n }\n if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmed)) {\n return \"evp\";\n }\n\n const numbers = digits(trimmed);\n if (numbers.length === 14) return validateCNPJ(numbers) ? \"cnpj\" : null;\n if (numbers.length === 11 && validateCPF(numbers)) return \"cpf\";\n if (trimmed.startsWith(\"+\")) {\n return /^\\+55\\d{10,11}$/.test(`+${numbers}`) ? \"phone\" : null;\n }\n if (numbers.length === 10 || numbers.length === 11) return \"phone\";\n if (numbers.length === 12 || numbers.length === 13) {\n return numbers.startsWith(\"55\") ? \"phone\" : null;\n }\n return null;\n}\n\n/**\n * Validate a Pix key and return the exact string to write into the payload.\n *\n * Normalisation per type: CPF and CNPJ lose their mask, a phone becomes E.164\n * with the `+55` country code, an EVP is lower-cased, and an e-mail is\n * lower-cased because DICT stores it that way — a key that differs only in case\n * would otherwise fail to resolve.\n *\n * All validation lives in {@link pixKeyType}; past that gate the normalisation is\n * total, which is why the phone branch strips a country code purely on length\n * rather than re-checking the shape.\n *\n * @param key - Raw key, masked or not.\n * @returns The type and the normalised value.\n * @throws {PixError} When the key matches no accepted format, or when a document\n * key fails its check digits.\n *\n * @example\n * normalizePixKey(\"123.456.789-09\"); // { type: \"cpf\", value: \"12345678909\" }\n * normalizePixKey(\"(11) 98765-4321\"); // { type: \"phone\", value: \"+5511987654321\" }\n */\nexport function normalizePixKey(key: string): NormalizedPixKey {\n const trimmed = key.trim();\n const type = pixKeyType(trimmed);\n if (type === null) {\n throw new PixError(\n `Not a Pix key: ${JSON.stringify(key)}. Expected a CPF, CNPJ, e-mail, ` +\n \"phone (+5511987654321) or EVP (UUID).\",\n );\n }\n\n if (type === \"email\") return { type, value: trimmed.toLowerCase() };\n if (type === \"evp\") return { type, value: trimmed.toLowerCase() };\n if (type === \"phone\") {\n const numbers = digits(trimmed);\n return { type, value: `+55${numbers.length > 11 ? numbers.slice(2) : numbers}` };\n }\n return { type, value: digits(trimmed) };\n}\n\n/** Format an amount the way tag 54 wants it: dot separator, two decimals. */\nfunction toAmountField(amount: number): string {\n if (!Number.isFinite(amount)) {\n throw new PixError(`Amount must be a finite number, got ${amount}.`);\n }\n if (amount <= 0) {\n throw new PixError(\n `Amount must be positive, got ${amount}. Omit \\`amount\\` for a QR whose value the payer types.`,\n );\n }\n const field = amount.toFixed(2);\n if (field.length > 13) {\n throw new PixError(`Amount ${field} does not fit tag 54, which holds 13 characters.`);\n }\n return field;\n}\n\n/** Bound the two free-text identity fields the spec caps hard. */\nfunction toBoundedText(value: string, max: number, field: string): string {\n const text = toPayloadText(value.trim(), field);\n if (text === \"\") throw new PixError(`${field} is required.`);\n if (text.length > max) {\n throw new PixError(\n `${field} is ${text.length} characters; the BR Code allows ${max}. Shorten it — ` +\n \"truncating here would silently change what the payer sees.\",\n );\n }\n return text;\n}\n\n/** Tag 62, which exists only to carry the txid. */\nfunction additionalDataField(txid: string | undefined): string {\n const value = txid?.trim() ?? \"\";\n if (value === \"\" || value === TXID_UNSPECIFIED) {\n return tlv(TAG_ADDITIONAL_DATA, tlv(ADDITIONAL_TAG_TXID, TXID_UNSPECIFIED));\n }\n if (!new RegExp(`^[A-Za-z0-9]{1,${MAX_TXID}}$`).test(value)) {\n throw new PixError(\n `txid must be 1 to ${MAX_TXID} letters or digits, got ${JSON.stringify(txid)}.`,\n );\n }\n return tlv(TAG_ADDITIONAL_DATA, tlv(ADDITIONAL_TAG_TXID, value));\n}\n\n/** Tag 26 for a static payload: GUI, key and the optional description. */\nfunction staticMerchantAccount(input: PixStaticInput): string {\n const { value } = normalizePixKey(input.key);\n let inner = tlv(MAI_TAG_GUI, PIX_GUI) + tlv(MAI_TAG_KEY, value);\n const description = input.description?.trim();\n if (description !== undefined && description !== \"\") {\n inner += tlv(MAI_TAG_DESCRIPTION, toPayloadText(description, \"description\"));\n }\n if (inner.length > MAX_TLV_VALUE) {\n throw new PixError(\n `Tag 26 is ${inner.length} characters, over the ${MAX_TLV_VALUE} the length field allows. ` +\n \"Shorten `description`.\",\n );\n }\n return tlv(TAG_MERCHANT_ACCOUNT_INFO, inner);\n}\n\n/** Tag 26 for a dynamic payload: GUI plus the URL, and no key. */\nfunction dynamicMerchantAccount(input: PixDynamicInput): string {\n const url = toPayloadText(input.url.trim(), \"url\").replace(/^https?:\\/\\//i, \"\");\n if (url === \"\") throw new PixError(\"url is required for a dynamic BR Code.\");\n const inner = tlv(MAI_TAG_GUI, PIX_GUI) + tlv(MAI_TAG_URL, url);\n if (inner.length > MAX_TLV_VALUE) {\n throw new PixError(\n `Tag 26 is ${inner.length} characters, over the ${MAX_TLV_VALUE} the length field allows. ` +\n \"Shorten the payload URL.\",\n );\n }\n return tlv(TAG_MERCHANT_ACCOUNT_INFO, inner);\n}\n\n/**\n * Build a Pix \"Copia e Cola\" payload — the string behind a Pix QR code.\n *\n * The format is EMVCo MPM: a flat list of `ID + 2-digit length + value` triples,\n * closed by tag 63 holding a CRC-16/CCITT-FALSE over **everything before it,\n * including the literal `6304` header of tag 63 itself**. That last detail is the\n * one implementations get wrong; see {@link pixCrc16}.\n *\n * Two shapes come out of here:\n *\n * - **static** — tag 26 carries the key, so the QR is self-contained and can be\n * printed. Amount optional; a txid of `\"***\"` means \"identifies no single\n * transaction\", which is what a reusable poster QR wants.\n * - **dynamic** — tag 26 carries a URL instead, and the wallet fetches the amount\n * and payee from the PSP. Use it when the value is per-order. Defaults to\n * single-use (tag 01 = `12`).\n *\n * The distinction matters and is not cosmetic: a static QR settles against\n * whatever the payer typed, a dynamic one against what the PSP served, so a\n * charge that must reconcile to a cent needs the dynamic form.\n *\n * @param input - Static or dynamic payload description.\n * @returns The full payload, CRC included, ready to render as a QR or to copy.\n * @throws {PixError} On an unrecognised key, a field over its length cap, a\n * non-positive amount, or text that is not representable in the BR Code.\n *\n * @example\n * pixPayload({\n * key: \"12345678909\",\n * merchantName: \"Loja Tempest\",\n * merchantCity: \"São Paulo\",\n * amount: 25.5,\n * txid: \"PEDIDO123\",\n * });\n */\nexport function pixPayload(input: PixInput): string {\n const dynamic = input.kind === \"dynamic\";\n const oneTime = input.oneTime ?? dynamic;\n\n let payload = tlv(TAG_PAYLOAD_FORMAT, PAYLOAD_FORMAT_VERSION);\n payload += tlv(\n TAG_POINT_OF_INITIATION,\n oneTime ? POINT_OF_INITIATION_SINGLE_USE : POINT_OF_INITIATION_REUSABLE,\n );\n payload += dynamic ? dynamicMerchantAccount(input) : staticMerchantAccount(input);\n payload += tlv(TAG_MERCHANT_CATEGORY_CODE, DEFAULT_MERCHANT_CATEGORY_CODE);\n payload += tlv(TAG_TRANSACTION_CURRENCY, CURRENCY_BRL);\n if (!dynamic && input.amount !== undefined) {\n payload += tlv(TAG_TRANSACTION_AMOUNT, toAmountField(input.amount));\n }\n payload += tlv(TAG_COUNTRY_CODE, COUNTRY_BR);\n payload += tlv(\n TAG_MERCHANT_NAME,\n toBoundedText(input.merchantName, MAX_MERCHANT_NAME, \"merchantName\"),\n );\n payload += tlv(\n TAG_MERCHANT_CITY,\n toBoundedText(input.merchantCity, MAX_MERCHANT_CITY, \"merchantCity\"),\n );\n const postalCode = input.postalCode === undefined ? \"\" : digits(input.postalCode);\n if (postalCode !== \"\") payload += tlv(TAG_POSTAL_CODE, postalCode);\n payload += additionalDataField(dynamic ? TXID_UNSPECIFIED : input.txid);\n\n const withCrcHeader = `${payload}${TAG_CRC}04`;\n return `${withCrcHeader}${pixCrc16(withCrcHeader)}`;\n}\n\n/**\n * Split a flat run of TLVs. Stops cleanly at the first malformed triple.\n *\n * @throws {PixError} When a length prefix is not two digits or runs past the end.\n */\nfunction parseTlv(input: string, where: string): PixField[] {\n const fields: PixField[] = [];\n let cursor = 0;\n while (cursor < input.length) {\n const id = input.slice(cursor, cursor + 2);\n const rawLength = input.slice(cursor + 2, cursor + 4);\n if (!/^\\d{2}$/.test(id) || !/^\\d{2}$/.test(rawLength)) {\n throw new PixError(\n `Malformed TLV in ${where} at offset ${cursor}: expected a 2-digit tag and length.`,\n );\n }\n const length = Number(rawLength);\n const start = cursor + 4;\n if (start + length > input.length) {\n throw new PixError(\n `Tag ${id} in ${where} declares ${length} characters but only ${input.length - start} remain.`,\n );\n }\n fields.push({ id, value: input.slice(start, start + length) });\n cursor = start + length;\n }\n return fields;\n}\n\n/** First value for a tag, or `undefined`. */\nfunction pick(fields: readonly PixField[], id: string): string | undefined {\n return fields.find((field) => field.id === id)?.value;\n}\n\n/**\n * Read a Pix \"Copia e Cola\" payload back into its parts.\n *\n * Tolerant by design: tags the SDK does not know about are kept verbatim in\n * {@link PixData.fields} instead of raising, because PSPs do add their own\n * templates and a reader that rejects them is useless in production. What is\n * *not* tolerated is a broken frame — a length prefix that runs off the end, a\n * missing tag 63 — or a checksum mismatch, which means the string was corrupted\n * and no longer names the account the payee published.\n *\n * @param payload - The copia-e-cola string. Surrounding whitespace is ignored.\n * @param options - See {@link ParsePixOptions}.\n * @returns The decoded payload.\n * @throws {PixError} On a malformed frame, a missing CRC tag, a tag 26 that is\n * not a Pix account, or — unless `requireCrc` is `false` — a CRC mismatch.\n *\n * @example\n * const data = parsePixPayload(copied);\n * console.log(data.key, data.amount, data.txid);\n */\nexport function parsePixPayload(payload: string, options: ParsePixOptions = {}): PixData {\n const { requireCrc = true } = options;\n const text = payload.trim();\n if (text.length < 8) throw new PixError(\"Payload is too short to be a BR Code.\");\n\n const crcHeaderAt = text.length - 8;\n if (text.slice(crcHeaderAt, crcHeaderAt + 4) !== `${TAG_CRC}04`) {\n throw new PixError(\"Payload does not end in a `6304` CRC tag.\");\n }\n const crc = text.slice(-4).toUpperCase();\n const expected = pixCrc16(text.slice(0, -4));\n const crcValid = crc === expected;\n if (!crcValid && requireCrc) {\n throw new PixError(`CRC mismatch: payload says ${crc}, recomputed ${expected}.`);\n }\n\n const fields = parseTlv(text.slice(0, crcHeaderAt), \"payload\");\n const merchantAccount = pick(fields, TAG_MERCHANT_ACCOUNT_INFO);\n if (merchantAccount === undefined) {\n throw new PixError(\"Payload has no tag 26 (merchant account information).\");\n }\n const account = parseTlv(merchantAccount, \"tag 26\");\n const gui = pick(account, MAI_TAG_GUI);\n if (gui?.toLowerCase() !== PIX_GUI) {\n throw new PixError(\n `Tag 26 is not a Pix account: expected GUI ${PIX_GUI}, got ${JSON.stringify(gui)}.`,\n );\n }\n\n const url = pick(account, MAI_TAG_URL);\n const key = pick(account, MAI_TAG_KEY);\n const amountField = pick(fields, TAG_TRANSACTION_AMOUNT);\n const txid = pick(\n parseTlv(pick(fields, TAG_ADDITIONAL_DATA) ?? \"\", \"tag 62\"),\n ADDITIONAL_TAG_TXID,\n );\n\n return {\n kind: url !== undefined && key === undefined ? \"dynamic\" : \"static\",\n ...(key === undefined ? {} : { key, keyType: pixKeyType(key) ?? undefined }),\n ...(url === undefined ? {} : { url }),\n merchantName: pick(fields, TAG_MERCHANT_NAME) ?? \"\",\n merchantCity: pick(fields, TAG_MERCHANT_CITY) ?? \"\",\n ...(amountField === undefined ? {} : { amount: Number(amountField) }),\n currency: pick(fields, TAG_TRANSACTION_CURRENCY) ?? \"\",\n countryCode: pick(fields, TAG_COUNTRY_CODE) ?? \"\",\n merchantCategoryCode: pick(fields, TAG_MERCHANT_CATEGORY_CODE) ?? \"\",\n ...(txid === undefined ? {} : { txid }),\n ...(pick(account, MAI_TAG_DESCRIPTION) === undefined\n ? {}\n : { description: pick(account, MAI_TAG_DESCRIPTION) }),\n ...(pick(fields, TAG_POSTAL_CODE) === undefined\n ? {}\n : { postalCode: pick(fields, TAG_POSTAL_CODE) }),\n oneTime: pick(fields, TAG_POINT_OF_INITIATION) === POINT_OF_INITIATION_SINGLE_USE,\n crc,\n crcValid,\n fields,\n };\n}\n"],"mappings":"8CAQA,IAAa,EAAb,cAA8B,KAAM,CAChC,YAAY,EAAiB,CACzB,MAAM,CAAO,EACb,KAAK,KAAO,UAChB,CACJ,EA8GM,EAAmB,KAGnB,EAAgB,MAGhB,EAAa,MAEb,EAAqB,KACrB,EAA0B,KAC1B,EAA4B,KAC5B,EAA6B,KAC7B,EAA2B,KAC3B,EAAyB,KACzB,EAAmB,KACnB,EAAoB,KACpB,EAAoB,KACpB,EAAkB,KAClB,EAAsB,KACtB,EAAU,KAEV,EAAc,KACd,EAAc,KACd,EAAsB,KACtB,EAAc,KACd,EAAsB,KAGtB,EAAU,iBAEV,EAAyB,KACzB,EAA+B,KAC/B,EAAiC,KACjC,EAAiC,OACjC,EAAe,MACf,EAAa,KACb,EAAmB,MAEnB,EAAoB,GACpB,EAAoB,GACpB,EAAW,GACX,EAAgB,GAChB,EAAgB,GAoBtB,SAAgB,EAAS,EAAuB,CAC5C,IAAM,EAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,CAAK,EACxC,EAAM,EACV,IAAK,IAAM,KAAQ,EAAO,CACtB,GAAO,GAAQ,EACf,IAAK,IAAI,EAAM,EAAG,EAAM,EAAG,GAAO,EAC9B,EACK,EAAM,OACC,GAAO,EAAK,GAAoB,EACjC,GAAO,EAAK,CAE/B,CACA,OAAO,EAAI,SAAS,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,EAAG,GAAG,CACzD,CAGA,SAAS,EAAO,EAAuB,CACnC,OAAO,EAAM,QAAQ,MAAO,EAAE,CAClC,CAWA,SAAS,EAAc,EAAe,EAAuB,CACzD,IAAM,EAAW,EAAM,UAAU,KAAK,CAAC,CAAC,QAAQ,kBAAmB,EAAE,EACrE,GAAI,eAAe,KAAK,CAAQ,EAC5B,MAAM,IAAI,EACN,GAAG,EAAM,4CAA4C,KAAK,UAAU,CAAK,EAAE,wBAE/E,EAEJ,OAAO,CACX,CAGA,SAAS,EAAI,EAAY,EAAuB,CAC5C,GAAI,EAAM,OAAS,EACf,MAAM,IAAI,EACN,OAAO,EAAG,MAAM,EAAM,OAAO,kDAAkD,EAAc,EACjG,EAEJ,MAAO,GAAG,IAAK,OAAO,EAAM,MAAM,CAAC,CAAC,SAAS,EAAG,GAAG,IAAI,GAC3D,CAcA,SAAgB,EAAW,EAAgC,CACvD,IAAM,EAAU,EAAI,KAAK,EACzB,GAAI,IAAY,GAAI,OAAO,KAE3B,GAAI,EAAQ,SAAS,GAAG,EACpB,MAAO,gCAAgC,KAAK,CAAO,GAAK,EAAQ,QAAU,EACpE,QACA,KAEV,GAAI,kEAAkE,KAAK,CAAO,EAC9E,MAAO,MAGX,IAAM,EAAU,EAAO,CAAO,EAU9B,OATI,EAAQ,SAAW,GAAW,EAAA,aAAa,CAAO,EAAI,OAAS,KAC/D,EAAQ,SAAW,IAAM,EAAA,YAAY,CAAO,EAAU,MACtD,EAAQ,WAAW,GAAG,EACf,kBAAkB,KAAK,IAAI,GAAS,EAAI,QAAU,KAEzD,EAAQ,SAAW,IAAM,EAAQ,SAAW,KAC5C,EAAQ,SAAW,IAAM,EAAQ,SAAW,KACrC,EAAQ,WAAW,IAAI,EAFyB,QAEX,IAGpD,CAuBA,SAAgB,EAAgB,EAA+B,CAC3D,IAAM,EAAU,EAAI,KAAK,EACnB,EAAO,EAAW,CAAO,EAC/B,GAAI,IAAS,KACT,MAAM,IAAI,EACN,kBAAkB,KAAK,UAAU,CAAG,EAAE,sEAE1C,EAIJ,GADI,IAAS,SACT,IAAS,MAAO,MAAO,CAAE,OAAM,MAAO,EAAQ,YAAY,CAAE,EAChE,GAAI,IAAS,QAAS,CAClB,IAAM,EAAU,EAAO,CAAO,EAC9B,MAAO,CAAE,OAAM,MAAO,MAAM,EAAQ,OAAS,GAAK,EAAQ,MAAM,CAAC,EAAI,GAAU,CACnF,CACA,MAAO,CAAE,OAAM,MAAO,EAAO,CAAO,CAAE,CAC1C,CAGA,SAAS,EAAc,EAAwB,CAC3C,GAAI,CAAC,OAAO,SAAS,CAAM,EACvB,MAAM,IAAI,EAAS,uCAAuC,EAAO,EAAE,EAEvE,GAAI,GAAU,EACV,MAAM,IAAI,EACN,gCAAgC,EAAO,wDAC3C,EAEJ,IAAM,EAAQ,EAAO,QAAQ,CAAC,EAC9B,GAAI,EAAM,OAAS,GACf,MAAM,IAAI,EAAS,UAAU,EAAM,iDAAiD,EAExF,OAAO,CACX,CAGA,SAAS,EAAc,EAAe,EAAa,EAAuB,CACtE,IAAM,EAAO,EAAc,EAAM,KAAK,EAAG,CAAK,EAC9C,GAAI,IAAS,GAAI,MAAM,IAAI,EAAS,GAAG,EAAM,cAAc,EAC3D,GAAI,EAAK,OAAS,EACd,MAAM,IAAI,EACN,GAAG,EAAM,MAAM,EAAK,OAAO,kCAAkC,EAAI,0EAErE,EAEJ,OAAO,CACX,CAGA,SAAS,EAAoB,EAAkC,CAC3D,IAAM,EAAQ,GAAM,KAAK,GAAK,GAC9B,GAAI,IAAU,IAAM,IAAU,EAC1B,OAAO,EAAI,EAAqB,EAAI,EAAqB,CAAgB,CAAC,EAE9E,GAAI,CAAK,OAAO,kBAAkB,EAAS,GAAG,CAAC,CAAC,KAAK,CAAK,EACtD,MAAM,IAAI,EACN,qBAAqB,EAAS,0BAA0B,KAAK,UAAU,CAAI,EAAE,EACjF,EAEJ,OAAO,EAAI,EAAqB,EAAI,EAAqB,CAAK,CAAC,CACnE,CAGA,SAAS,EAAsB,EAA+B,CAC1D,GAAM,CAAE,SAAU,EAAgB,EAAM,GAAG,EACvC,EAAQ,EAAI,EAAa,CAAO,EAAI,EAAI,EAAa,CAAK,EACxD,EAAc,EAAM,aAAa,KAAK,EAI5C,GAHI,IAAgB,IAAA,IAAa,IAAgB,KAC7C,GAAS,EAAI,EAAqB,EAAc,EAAa,aAAa,CAAC,GAE3E,EAAM,OAAS,EACf,MAAM,IAAI,EACN,aAAa,EAAM,OAAO,wBAAwB,EAAc,mDAEpE,EAEJ,OAAO,EAAI,EAA2B,CAAK,CAC/C,CAGA,SAAS,EAAuB,EAAgC,CAC5D,IAAM,EAAM,EAAc,EAAM,IAAI,KAAK,EAAG,KAAK,CAAC,CAAC,QAAQ,gBAAiB,EAAE,EAC9E,GAAI,IAAQ,GAAI,MAAM,IAAI,EAAS,wCAAwC,EAC3E,IAAM,EAAQ,EAAI,EAAa,CAAO,EAAI,EAAI,EAAa,CAAG,EAC9D,GAAI,EAAM,OAAS,EACf,MAAM,IAAI,EACN,aAAa,EAAM,OAAO,wBAAwB,EAAc,mDAEpE,EAEJ,OAAO,EAAI,EAA2B,CAAK,CAC/C,CAqCA,SAAgB,EAAW,EAAyB,CAChD,IAAM,EAAU,EAAM,OAAS,UACzB,EAAU,EAAM,SAAW,EAE7B,EAAU,EAAI,EAAoB,CAAsB,EAC5D,GAAW,EACP,EACA,EAAU,EAAiC,CAC/C,EACA,GAAW,EAAU,EAAuB,CAAK,EAAI,EAAsB,CAAK,EAChF,GAAW,EAAI,EAA4B,CAA8B,EACzE,GAAW,EAAI,EAA0B,CAAY,EACjD,CAAC,GAAW,EAAM,SAAW,IAAA,KAC7B,GAAW,EAAI,EAAwB,EAAc,EAAM,MAAM,CAAC,GAEtE,GAAW,EAAI,EAAkB,CAAU,EAC3C,GAAW,EACP,EACA,EAAc,EAAM,aAAc,EAAmB,cAAc,CACvE,EACA,GAAW,EACP,EACA,EAAc,EAAM,aAAc,EAAmB,cAAc,CACvE,EACA,IAAM,EAAa,EAAM,aAAe,IAAA,GAAY,GAAK,EAAO,EAAM,UAAU,EAC5E,IAAe,KAAI,GAAW,EAAI,EAAiB,CAAU,GACjE,GAAW,EAAoB,EAAU,EAAmB,EAAM,IAAI,EAEtE,IAAM,EAAgB,GAAG,IAAU,EAAQ,IAC3C,MAAO,GAAG,IAAgB,EAAS,CAAa,GACpD,CAOA,SAAS,EAAS,EAAe,EAA2B,CACxD,IAAM,EAAqB,CAAC,EACxB,EAAS,EACb,KAAO,EAAS,EAAM,QAAQ,CAC1B,IAAM,EAAK,EAAM,MAAM,EAAQ,EAAS,CAAC,EACnC,EAAY,EAAM,MAAM,EAAS,EAAG,EAAS,CAAC,EACpD,GAAI,CAAC,UAAU,KAAK,CAAE,GAAK,CAAC,UAAU,KAAK,CAAS,EAChD,MAAM,IAAI,EACN,oBAAoB,EAAM,aAAa,EAAO,qCAClD,EAEJ,IAAM,EAAS,OAAO,CAAS,EACzB,EAAQ,EAAS,EACvB,GAAI,EAAQ,EAAS,EAAM,OACvB,MAAM,IAAI,EACN,OAAO,EAAG,MAAM,EAAM,YAAY,EAAO,uBAAuB,EAAM,OAAS,EAAM,SACzF,EAEJ,EAAO,KAAK,CAAE,KAAI,MAAO,EAAM,MAAM,EAAO,EAAQ,CAAM,CAAE,CAAC,EAC7D,EAAS,EAAQ,CACrB,CACA,OAAO,CACX,CAGA,SAAS,EAAK,EAA6B,EAAgC,CACvE,OAAO,EAAO,KAAM,GAAU,EAAM,KAAO,CAAE,CAAC,EAAE,KACpD,CAsBA,SAAgB,EAAgB,EAAiB,EAA2B,CAAC,EAAY,CACrF,GAAM,CAAE,aAAa,IAAS,EACxB,EAAO,EAAQ,KAAK,EAC1B,GAAI,EAAK,OAAS,EAAG,MAAM,IAAI,EAAS,uCAAuC,EAE/E,IAAM,EAAc,EAAK,OAAS,EAClC,GAAI,EAAK,MAAM,EAAa,EAAc,CAAC,IAAM,GAAG,EAAQ,IACxD,MAAM,IAAI,EAAS,2CAA2C,EAElE,IAAM,EAAM,EAAK,MAAM,EAAE,CAAC,CAAC,YAAY,EACjC,EAAW,EAAS,EAAK,MAAM,EAAG,EAAE,CAAC,EACrC,EAAW,IAAQ,EACzB,GAAI,CAAC,GAAY,EACb,MAAM,IAAI,EAAS,8BAA8B,EAAI,eAAe,EAAS,EAAE,EAGnF,IAAM,EAAS,EAAS,EAAK,MAAM,EAAG,CAAW,EAAG,SAAS,EACvD,EAAkB,EAAK,EAAQ,CAAyB,EAC9D,GAAI,IAAoB,IAAA,GACpB,MAAM,IAAI,EAAS,uDAAuD,EAE9E,IAAM,EAAU,EAAS,EAAiB,QAAQ,EAC5C,EAAM,EAAK,EAAS,CAAW,EACrC,GAAI,GAAK,YAAY,IAAM,EACvB,MAAM,IAAI,EACN,6CAA6C,EAAQ,QAAQ,KAAK,UAAU,CAAG,EAAE,EACrF,EAGJ,IAAM,EAAM,EAAK,EAAS,CAAW,EAC/B,EAAM,EAAK,EAAS,CAAW,EAC/B,EAAc,EAAK,EAAQ,CAAsB,EACjD,EAAO,EACT,EAAS,EAAK,EAAQ,CAAmB,GAAK,GAAI,QAAQ,EAC1D,CACJ,EAEA,MAAO,CACH,KAAM,IAAQ,IAAA,IAAa,IAAQ,IAAA,GAAY,UAAY,SAC3D,GAAI,IAAQ,IAAA,GAAY,CAAC,EAAI,CAAE,MAAK,QAAS,EAAW,CAAG,GAAK,IAAA,EAAU,EAC1E,GAAI,IAAQ,IAAA,GAAY,CAAC,EAAI,CAAE,KAAI,EACnC,aAAc,EAAK,EAAQ,CAAiB,GAAK,GACjD,aAAc,EAAK,EAAQ,CAAiB,GAAK,GACjD,GAAI,IAAgB,IAAA,GAAY,CAAC,EAAI,CAAE,OAAQ,OAAO,CAAW,CAAE,EACnE,SAAU,EAAK,EAAQ,CAAwB,GAAK,GACpD,YAAa,EAAK,EAAQ,CAAgB,GAAK,GAC/C,qBAAsB,EAAK,EAAQ,CAA0B,GAAK,GAClE,GAAI,IAAS,IAAA,GAAY,CAAC,EAAI,CAAE,MAAK,EACrC,GAAI,EAAK,EAAS,CAAmB,IAAM,IAAA,GACrC,CAAC,EACD,CAAE,YAAa,EAAK,EAAS,CAAmB,CAAE,EACxD,GAAI,EAAK,EAAQ,CAAe,IAAM,IAAA,GAChC,CAAC,EACD,CAAE,WAAY,EAAK,EAAQ,CAAe,CAAE,EAClD,QAAS,EAAK,EAAQ,CAAuB,IAAM,EACnD,MACA,WACA,QACJ,CACJ"}
|
|
1
|
+
{"version":3,"file":"pix.cjs","names":[],"sources":["../../src/br/pix.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — EMV®QRCPS-MPM for Pix: the TLV writer, the\n * CRC16-CCITT, the field catalogue with its nesting, key-type detection and the\n * parser that has to accept what other banks emit. Reader and writer live together\n * because each one is the other's test — a payload this file builds is a payload it\n * must parse back.\n */\nimport { validateCNPJ, validateCPF } from \"@/forms/br-validators\";\n\n/**\n * A Pix payload could not be built or read.\n *\n * Its own class so a caller can tell \"the operator typed a bad key\" apart from a\n * bug, and so an `ErrorBoundary` can render a form error instead of a crash.\n */\nexport class PixError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PixError\";\n }\n}\n\n/** The five key formats DICT accepts. */\nexport type PixKeyType = \"cpf\" | \"cnpj\" | \"email\" | \"phone\" | \"evp\";\n\n/** A key after normalisation, ready to go into the payload. */\nexport interface NormalizedPixKey {\n type: PixKeyType;\n /** The exact string written into the BR Code. */\n value: string;\n}\n\n/** One TLV as it appeared in a payload, unknown tags included. */\nexport interface PixField {\n /** Two-character tag, e.g. `\"59\"`. */\n id: string;\n /** Raw value, still encoded when the tag is itself a template. */\n value: string;\n}\n\n/** A BR Code that carries the key — the one you print on a poster. */\nexport interface PixStaticInput {\n kind?: \"static\";\n /** CPF, CNPJ, e-mail, phone or EVP. Validated and normalised. */\n key: string;\n /** Payee name. Truncated by the spec at 25 characters — longer throws. */\n merchantName: string;\n /** Payee city. Truncated by the spec at 15 characters — longer throws. */\n merchantCity: string;\n /** Amount in BRL. Omit for a payer-chooses-the-value QR. */\n amount?: number;\n /** Reference the PSP echoes back, `[A-Za-z0-9]{1,25}`. Defaults to `\"***\"`. */\n txid?: string;\n /** Free text shown by some wallets. Goes into tag 26, sub-tag 02. */\n description?: string;\n /** CEP, digits only. Optional tag 61. */\n postalCode?: string;\n /** Single-use QR: sets tag 01 to `\"12\"` instead of `\"11\"`. */\n oneTime?: boolean;\n}\n\n/** A BR Code that carries a URL the wallet fetches to learn the amount. */\nexport interface PixDynamicInput {\n kind: \"dynamic\";\n /**\n * `payloadLocation` — the https URL the wallet GETs, **without** the scheme,\n * exactly as BACEN specifies (`pix.example.com/qr/v2/abc`).\n */\n url: string;\n merchantName: string;\n merchantCity: string;\n postalCode?: string;\n /** Single-use QR. Defaults to `true`, which is what a dynamic QR normally is. */\n oneTime?: boolean;\n}\n\n/** Everything `pixPayload` accepts. */\nexport type PixInput = PixStaticInput | PixDynamicInput;\n\n/** A payload taken apart again. */\nexport interface PixData {\n /** `\"dynamic\"` when tag 26 carried a URL instead of a key. */\n kind: \"static\" | \"dynamic\";\n /** Present on a static payload. */\n key?: string;\n keyType?: PixKeyType;\n /** Present on a dynamic payload. */\n url?: string;\n merchantName: string;\n merchantCity: string;\n /** Reais. `undefined` when the payer chooses the amount. */\n amount?: number;\n /** ISO 4217 numeric. `\"986\"` for BRL. */\n currency: string;\n countryCode: string;\n merchantCategoryCode: string;\n /** `\"***\"` on a reusable static QR that identifies no single transaction. */\n txid?: string;\n description?: string;\n postalCode?: string;\n /** Tag 01 read as `\"12\"`. */\n oneTime: boolean;\n /** The four hex characters that closed the payload. */\n crc: string;\n /** Whether those four characters match a recomputed CRC. */\n crcValid: boolean;\n /** Every top-level TLV, in payload order, unknown tags included. */\n fields: PixField[];\n}\n\n/** Options for {@link parsePixPayload}. */\nexport interface ParsePixOptions {\n /**\n * Throw when the checksum does not match. Default `true`.\n *\n * Turn it off only to inspect a payload you already know is broken: a BR Code\n * whose CRC fails has been corrupted in transit, and the account it now points\n * at is not the account the payee published.\n */\n requireCrc?: boolean;\n}\n\n/**\n * Generator polynomial of CRC-16/CCITT-FALSE, `x^16 + x^12 + x^5 + 1`.\n *\n * Taken from the CRC catalogue entry `CRC-16/IBM-3740` (alias CCITT-FALSE):\n * `width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000\n * check=0x29b1`. The BACEN \"Manual de Padrões para Iniciação do Pix\" names this\n * exact variant for tag 63.\n */\nconst CRC16_POLYNOMIAL = 0x1021;\n\n/** Register preset of CRC-16/CCITT-FALSE. Not zero — that is a different variant. */\nconst CRC16_INITIAL = 0xffff;\n\n/** Keeps the shift register 16 bits wide. */\nconst CRC16_MASK = 0xffff;\n\nconst TAG_PAYLOAD_FORMAT = \"00\";\nconst TAG_POINT_OF_INITIATION = \"01\";\nconst TAG_MERCHANT_ACCOUNT_INFO = \"26\";\nconst TAG_MERCHANT_CATEGORY_CODE = \"52\";\nconst TAG_TRANSACTION_CURRENCY = \"53\";\nconst TAG_TRANSACTION_AMOUNT = \"54\";\nconst TAG_COUNTRY_CODE = \"58\";\nconst TAG_MERCHANT_NAME = \"59\";\nconst TAG_MERCHANT_CITY = \"60\";\nconst TAG_POSTAL_CODE = \"61\";\nconst TAG_ADDITIONAL_DATA = \"62\";\nconst TAG_CRC = \"63\";\n\nconst MAI_TAG_GUI = \"00\";\nconst MAI_TAG_KEY = \"01\";\nconst MAI_TAG_DESCRIPTION = \"02\";\nconst MAI_TAG_URL = \"25\";\nconst ADDITIONAL_TAG_TXID = \"05\";\n\n/** Globally Unique Identifier that marks tag 26 as a Pix account. */\nconst PIX_GUI = \"br.gov.bcb.pix\";\n\nconst PAYLOAD_FORMAT_VERSION = \"01\";\nconst POINT_OF_INITIATION_REUSABLE = \"11\";\nconst POINT_OF_INITIATION_SINGLE_USE = \"12\";\nconst DEFAULT_MERCHANT_CATEGORY_CODE = \"0000\";\nconst CURRENCY_BRL = \"986\";\nconst COUNTRY_BR = \"BR\";\nconst TXID_UNSPECIFIED = \"***\";\n\nconst MAX_MERCHANT_NAME = 25;\nconst MAX_MERCHANT_CITY = 15;\nconst MAX_TXID = 25;\nconst MAX_TLV_VALUE = 99;\nconst MAX_EMAIL_KEY = 77;\n\n/**\n * CRC-16/CCITT-FALSE of a string, as four upper-case hex characters.\n *\n * Bitwise rather than table-driven: 200-odd characters at 8 shifts each is\n * nothing, and a 256-entry table is 2 KB of payload every consumer of the `/br`\n * entry would carry.\n *\n * The input is taken as UTF-8 bytes. A Pix payload is ASCII by construction —\n * {@link pixPayload} rejects anything else — but the function is exported and a\n * caller may hand it arbitrary text, and hashing UTF-16 code units would then\n * disagree with every other implementation.\n *\n * @param input - Bytes to run through the register.\n * @returns Four upper-case hex characters, zero-padded.\n *\n * @example\n * pixCrc16(\"123456789\"); // \"29B1\" — the catalogue check value\n */\nexport function pixCrc16(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let crc = CRC16_INITIAL;\n for (const byte of bytes) {\n crc ^= byte << 8;\n for (let bit = 0; bit < 8; bit += 1) {\n crc =\n (crc & 0x8000) !== 0\n ? ((crc << 1) ^ CRC16_POLYNOMIAL) & CRC16_MASK\n : (crc << 1) & CRC16_MASK;\n }\n }\n return crc.toString(16).toUpperCase().padStart(4, \"0\");\n}\n\n/** Digits of a possibly masked value. */\nfunction digits(value: string): string {\n return value.replace(/\\D/g, \"\");\n}\n\n/**\n * Drop diacritics and reject whatever is left outside printable ASCII.\n *\n * The BR Code character set has no room for accents, and a wallet that meets one\n * either fails to parse the QR or shows mojibake. Stripping them is lossy but\n * legible (\"São Paulo\" → \"Sao Paulo\"), which beats both alternatives; anything\n * that is not a diacritic — an emoji, a CJK character — is a mistake the caller\n * has to see, so it throws.\n */\nfunction toPayloadText(value: string, field: string): string {\n const stripped = value.normalize(\"NFD\").replace(/\\p{Diacritic}/gu, \"\");\n if (/[^\\x20-\\x7E]/.test(stripped)) {\n throw new PixError(\n `${field} has characters the BR Code cannot carry: ${JSON.stringify(value)}. ` +\n \"Use unaccented ASCII.\",\n );\n }\n return stripped;\n}\n\n/** One `ID + 2-digit length + value` triple. */\nfunction tlv(id: string, value: string): string {\n if (value.length > MAX_TLV_VALUE) {\n throw new PixError(\n `Tag ${id} is ${value.length} characters; the EMV length field holds at most ${MAX_TLV_VALUE}.`,\n );\n }\n return `${id}${String(value.length).padStart(2, \"0\")}${value}`;\n}\n\n/**\n * Classify a Pix key, or `null` when it matches no accepted format.\n *\n * !!! warning \"CPF and a national phone number are both eleven digits\"\n * `\"11987654321\"` is a valid mobile number and could be a CPF. The check\n * digits break the tie: an 11-digit string is a CPF when its DV validates and\n * a phone otherwise. Pass phone keys as `+5511987654321` to remove the guess\n * entirely.\n *\n * @param key - Raw key, masked or not.\n * @returns The key type, or `null`.\n */\nexport function pixKeyType(key: string): PixKeyType | null {\n const trimmed = key.trim();\n if (trimmed === \"\") return null;\n\n if (trimmed.includes(\"@\")) {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/.test(trimmed) && trimmed.length <= MAX_EMAIL_KEY\n ? \"email\"\n : null;\n }\n if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmed)) {\n return \"evp\";\n }\n\n const numbers = digits(trimmed);\n if (numbers.length === 14) return validateCNPJ(numbers) ? \"cnpj\" : null;\n if (numbers.length === 11 && validateCPF(numbers)) return \"cpf\";\n if (trimmed.startsWith(\"+\")) {\n return /^\\+55\\d{10,11}$/.test(`+${numbers}`) ? \"phone\" : null;\n }\n if (numbers.length === 10 || numbers.length === 11) return \"phone\";\n if (numbers.length === 12 || numbers.length === 13) {\n return numbers.startsWith(\"55\") ? \"phone\" : null;\n }\n return null;\n}\n\n/**\n * Validate a Pix key and return the exact string to write into the payload.\n *\n * Normalisation per type: CPF and CNPJ lose their mask, a phone becomes E.164\n * with the `+55` country code, an EVP is lower-cased, and an e-mail is\n * lower-cased because DICT stores it that way — a key that differs only in case\n * would otherwise fail to resolve.\n *\n * All validation lives in {@link pixKeyType}; past that gate the normalisation is\n * total, which is why the phone branch strips a country code purely on length\n * rather than re-checking the shape.\n *\n * @param key - Raw key, masked or not.\n * @returns The type and the normalised value.\n * @throws {PixError} When the key matches no accepted format, or when a document\n * key fails its check digits.\n *\n * @example\n * normalizePixKey(\"123.456.789-09\"); // { type: \"cpf\", value: \"12345678909\" }\n * normalizePixKey(\"(11) 98765-4321\"); // { type: \"phone\", value: \"+5511987654321\" }\n */\nexport function normalizePixKey(key: string): NormalizedPixKey {\n const trimmed = key.trim();\n const type = pixKeyType(trimmed);\n if (type === null) {\n throw new PixError(\n `Not a Pix key: ${JSON.stringify(key)}. Expected a CPF, CNPJ, e-mail, ` +\n \"phone (+5511987654321) or EVP (UUID).\",\n );\n }\n\n if (type === \"email\") return { type, value: trimmed.toLowerCase() };\n if (type === \"evp\") return { type, value: trimmed.toLowerCase() };\n if (type === \"phone\") {\n const numbers = digits(trimmed);\n return { type, value: `+55${numbers.length > 11 ? numbers.slice(2) : numbers}` };\n }\n return { type, value: digits(trimmed) };\n}\n\n/** Format an amount the way tag 54 wants it: dot separator, two decimals. */\nfunction toAmountField(amount: number): string {\n if (!Number.isFinite(amount)) {\n throw new PixError(`Amount must be a finite number, got ${amount}.`);\n }\n if (amount <= 0) {\n throw new PixError(\n `Amount must be positive, got ${amount}. Omit \\`amount\\` for a QR whose value the payer types.`,\n );\n }\n const field = amount.toFixed(2);\n if (field.length > 13) {\n throw new PixError(`Amount ${field} does not fit tag 54, which holds 13 characters.`);\n }\n return field;\n}\n\n/** Bound the two free-text identity fields the spec caps hard. */\nfunction toBoundedText(value: string, max: number, field: string): string {\n const text = toPayloadText(value.trim(), field);\n if (text === \"\") throw new PixError(`${field} is required.`);\n if (text.length > max) {\n throw new PixError(\n `${field} is ${text.length} characters; the BR Code allows ${max}. Shorten it — ` +\n \"truncating here would silently change what the payer sees.\",\n );\n }\n return text;\n}\n\n/** Tag 62, which exists only to carry the txid. */\nfunction additionalDataField(txid: string | undefined): string {\n const value = txid?.trim() ?? \"\";\n if (value === \"\" || value === TXID_UNSPECIFIED) {\n return tlv(TAG_ADDITIONAL_DATA, tlv(ADDITIONAL_TAG_TXID, TXID_UNSPECIFIED));\n }\n if (!new RegExp(`^[A-Za-z0-9]{1,${MAX_TXID}}$`).test(value)) {\n throw new PixError(\n `txid must be 1 to ${MAX_TXID} letters or digits, got ${JSON.stringify(txid)}.`,\n );\n }\n return tlv(TAG_ADDITIONAL_DATA, tlv(ADDITIONAL_TAG_TXID, value));\n}\n\n/** Tag 26 for a static payload: GUI, key and the optional description. */\nfunction staticMerchantAccount(input: PixStaticInput): string {\n const { value } = normalizePixKey(input.key);\n let inner = tlv(MAI_TAG_GUI, PIX_GUI) + tlv(MAI_TAG_KEY, value);\n const description = input.description?.trim();\n if (description !== undefined && description !== \"\") {\n inner += tlv(MAI_TAG_DESCRIPTION, toPayloadText(description, \"description\"));\n }\n if (inner.length > MAX_TLV_VALUE) {\n throw new PixError(\n `Tag 26 is ${inner.length} characters, over the ${MAX_TLV_VALUE} the length field allows. ` +\n \"Shorten `description`.\",\n );\n }\n return tlv(TAG_MERCHANT_ACCOUNT_INFO, inner);\n}\n\n/** Tag 26 for a dynamic payload: GUI plus the URL, and no key. */\nfunction dynamicMerchantAccount(input: PixDynamicInput): string {\n const url = toPayloadText(input.url.trim(), \"url\").replace(/^https?:\\/\\//i, \"\");\n if (url === \"\") throw new PixError(\"url is required for a dynamic BR Code.\");\n const inner = tlv(MAI_TAG_GUI, PIX_GUI) + tlv(MAI_TAG_URL, url);\n if (inner.length > MAX_TLV_VALUE) {\n throw new PixError(\n `Tag 26 is ${inner.length} characters, over the ${MAX_TLV_VALUE} the length field allows. ` +\n \"Shorten the payload URL.\",\n );\n }\n return tlv(TAG_MERCHANT_ACCOUNT_INFO, inner);\n}\n\n/**\n * Build a Pix \"Copia e Cola\" payload — the string behind a Pix QR code.\n *\n * The format is EMVCo MPM: a flat list of `ID + 2-digit length + value` triples,\n * closed by tag 63 holding a CRC-16/CCITT-FALSE over **everything before it,\n * including the literal `6304` header of tag 63 itself**. That last detail is the\n * one implementations get wrong; see {@link pixCrc16}.\n *\n * Two shapes come out of here:\n *\n * - **static** — tag 26 carries the key, so the QR is self-contained and can be\n * printed. Amount optional; a txid of `\"***\"` means \"identifies no single\n * transaction\", which is what a reusable poster QR wants.\n * - **dynamic** — tag 26 carries a URL instead, and the wallet fetches the amount\n * and payee from the PSP. Use it when the value is per-order. Defaults to\n * single-use (tag 01 = `12`).\n *\n * The distinction matters and is not cosmetic: a static QR settles against\n * whatever the payer typed, a dynamic one against what the PSP served, so a\n * charge that must reconcile to a cent needs the dynamic form.\n *\n * @param input - Static or dynamic payload description.\n * @returns The full payload, CRC included, ready to render as a QR or to copy.\n * @throws {PixError} On an unrecognised key, a field over its length cap, a\n * non-positive amount, or text that is not representable in the BR Code.\n *\n * @example\n * pixPayload({\n * key: \"12345678909\",\n * merchantName: \"Loja Tempest\",\n * merchantCity: \"São Paulo\",\n * amount: 25.5,\n * txid: \"PEDIDO123\",\n * });\n */\nexport function pixPayload(input: PixInput): string {\n const dynamic = input.kind === \"dynamic\";\n const oneTime = input.oneTime ?? dynamic;\n\n let payload = tlv(TAG_PAYLOAD_FORMAT, PAYLOAD_FORMAT_VERSION);\n payload += tlv(\n TAG_POINT_OF_INITIATION,\n oneTime ? POINT_OF_INITIATION_SINGLE_USE : POINT_OF_INITIATION_REUSABLE,\n );\n payload += dynamic ? dynamicMerchantAccount(input) : staticMerchantAccount(input);\n payload += tlv(TAG_MERCHANT_CATEGORY_CODE, DEFAULT_MERCHANT_CATEGORY_CODE);\n payload += tlv(TAG_TRANSACTION_CURRENCY, CURRENCY_BRL);\n if (!dynamic && input.amount !== undefined) {\n payload += tlv(TAG_TRANSACTION_AMOUNT, toAmountField(input.amount));\n }\n payload += tlv(TAG_COUNTRY_CODE, COUNTRY_BR);\n payload += tlv(\n TAG_MERCHANT_NAME,\n toBoundedText(input.merchantName, MAX_MERCHANT_NAME, \"merchantName\"),\n );\n payload += tlv(\n TAG_MERCHANT_CITY,\n toBoundedText(input.merchantCity, MAX_MERCHANT_CITY, \"merchantCity\"),\n );\n const postalCode = input.postalCode === undefined ? \"\" : digits(input.postalCode);\n if (postalCode !== \"\") payload += tlv(TAG_POSTAL_CODE, postalCode);\n payload += additionalDataField(dynamic ? TXID_UNSPECIFIED : input.txid);\n\n const withCrcHeader = `${payload}${TAG_CRC}04`;\n return `${withCrcHeader}${pixCrc16(withCrcHeader)}`;\n}\n\n/**\n * Split a flat run of TLVs. Stops cleanly at the first malformed triple.\n *\n * @throws {PixError} When a length prefix is not two digits or runs past the end.\n */\nfunction parseTlv(input: string, where: string): PixField[] {\n const fields: PixField[] = [];\n let cursor = 0;\n while (cursor < input.length) {\n const id = input.slice(cursor, cursor + 2);\n const rawLength = input.slice(cursor + 2, cursor + 4);\n if (!/^\\d{2}$/.test(id) || !/^\\d{2}$/.test(rawLength)) {\n throw new PixError(\n `Malformed TLV in ${where} at offset ${cursor}: expected a 2-digit tag and length.`,\n );\n }\n const length = Number(rawLength);\n const start = cursor + 4;\n if (start + length > input.length) {\n throw new PixError(\n `Tag ${id} in ${where} declares ${length} characters but only ${input.length - start} remain.`,\n );\n }\n fields.push({ id, value: input.slice(start, start + length) });\n cursor = start + length;\n }\n return fields;\n}\n\n/** First value for a tag, or `undefined`. */\nfunction pick(fields: readonly PixField[], id: string): string | undefined {\n return fields.find((field) => field.id === id)?.value;\n}\n\n/**\n * Read a Pix \"Copia e Cola\" payload back into its parts.\n *\n * Tolerant by design: tags the SDK does not know about are kept verbatim in\n * {@link PixData.fields} instead of raising, because PSPs do add their own\n * templates and a reader that rejects them is useless in production. What is\n * *not* tolerated is a broken frame — a length prefix that runs off the end, a\n * missing tag 63 — or a checksum mismatch, which means the string was corrupted\n * and no longer names the account the payee published.\n *\n * @param payload - The copia-e-cola string. Surrounding whitespace is ignored.\n * @param options - See {@link ParsePixOptions}.\n * @returns The decoded payload.\n * @throws {PixError} On a malformed frame, a missing CRC tag, a tag 26 that is\n * not a Pix account, or — unless `requireCrc` is `false` — a CRC mismatch.\n *\n * @example\n * const data = parsePixPayload(copied);\n * console.log(data.key, data.amount, data.txid);\n */\nexport function parsePixPayload(payload: string, options: ParsePixOptions = {}): PixData {\n const { requireCrc = true } = options;\n const text = payload.trim();\n if (text.length < 8) throw new PixError(\"Payload is too short to be a BR Code.\");\n\n const crcHeaderAt = text.length - 8;\n if (text.slice(crcHeaderAt, crcHeaderAt + 4) !== `${TAG_CRC}04`) {\n throw new PixError(\"Payload does not end in a `6304` CRC tag.\");\n }\n const crc = text.slice(-4).toUpperCase();\n const expected = pixCrc16(text.slice(0, -4));\n const crcValid = crc === expected;\n if (!crcValid && requireCrc) {\n throw new PixError(`CRC mismatch: payload says ${crc}, recomputed ${expected}.`);\n }\n\n const fields = parseTlv(text.slice(0, crcHeaderAt), \"payload\");\n const merchantAccount = pick(fields, TAG_MERCHANT_ACCOUNT_INFO);\n if (merchantAccount === undefined) {\n throw new PixError(\"Payload has no tag 26 (merchant account information).\");\n }\n const account = parseTlv(merchantAccount, \"tag 26\");\n const gui = pick(account, MAI_TAG_GUI);\n if (gui?.toLowerCase() !== PIX_GUI) {\n throw new PixError(\n `Tag 26 is not a Pix account: expected GUI ${PIX_GUI}, got ${JSON.stringify(gui)}.`,\n );\n }\n\n const url = pick(account, MAI_TAG_URL);\n const key = pick(account, MAI_TAG_KEY);\n const amountField = pick(fields, TAG_TRANSACTION_AMOUNT);\n const txid = pick(\n parseTlv(pick(fields, TAG_ADDITIONAL_DATA) ?? \"\", \"tag 62\"),\n ADDITIONAL_TAG_TXID,\n );\n\n return {\n kind: url !== undefined && key === undefined ? \"dynamic\" : \"static\",\n ...(key === undefined ? {} : { key, keyType: pixKeyType(key) ?? undefined }),\n ...(url === undefined ? {} : { url }),\n merchantName: pick(fields, TAG_MERCHANT_NAME) ?? \"\",\n merchantCity: pick(fields, TAG_MERCHANT_CITY) ?? \"\",\n ...(amountField === undefined ? {} : { amount: Number(amountField) }),\n currency: pick(fields, TAG_TRANSACTION_CURRENCY) ?? \"\",\n countryCode: pick(fields, TAG_COUNTRY_CODE) ?? \"\",\n merchantCategoryCode: pick(fields, TAG_MERCHANT_CATEGORY_CODE) ?? \"\",\n ...(txid === undefined ? {} : { txid }),\n ...(pick(account, MAI_TAG_DESCRIPTION) === undefined\n ? {}\n : { description: pick(account, MAI_TAG_DESCRIPTION) }),\n ...(pick(fields, TAG_POSTAL_CODE) === undefined\n ? {}\n : { postalCode: pick(fields, TAG_POSTAL_CODE) }),\n oneTime: pick(fields, TAG_POINT_OF_INITIATION) === POINT_OF_INITIATION_SINGLE_USE,\n crc,\n crcValid,\n fields,\n };\n}\n"],"mappings":"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"}
|