{"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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"}