kassza 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -0
  3. package/agents/README.md +59 -0
  4. package/agents/api.md +206 -0
  5. package/agents/pitfalls.md +52 -0
  6. package/agents/recipes.md +217 -0
  7. package/agents/skills/kassza/SKILL.md +29 -0
  8. package/assets/logo-wordmark.svg +25 -0
  9. package/assets/logo.svg +19 -0
  10. package/dist/binary-B89HM03_.cjs +63 -0
  11. package/dist/binary-D0M9U2MD.js +34 -0
  12. package/dist/client-B9kbKKBf.d.cts +748 -0
  13. package/dist/client-zv4enyq7.d.ts +748 -0
  14. package/dist/cookie-stores/index.cjs +153 -0
  15. package/dist/cookie-stores/index.d.cts +63 -0
  16. package/dist/cookie-stores/index.d.ts +63 -0
  17. package/dist/cookie-stores/index.js +144 -0
  18. package/dist/create-BZd6CUO7.cjs +1160 -0
  19. package/dist/create-DDZaNlOz.js +939 -0
  20. package/dist/dates-D2XebOIg.js +34 -0
  21. package/dist/dates-DtHzwNU6.d.cts +7 -0
  22. package/dist/dates-DtHzwNU6.d.ts +7 -0
  23. package/dist/dates-PPxH0n5H.cjs +57 -0
  24. package/dist/errors-B0QJhUW1.cjs +302 -0
  25. package/dist/errors-DapdV5DK.js +273 -0
  26. package/dist/index-CYAGCdKJ.d.cts +56 -0
  27. package/dist/index-CYAGCdKJ.d.ts +56 -0
  28. package/dist/index.cjs +1406 -0
  29. package/dist/index.d.cts +8 -0
  30. package/dist/index.d.ts +8 -0
  31. package/dist/index.js +1394 -0
  32. package/dist/ipn/index.cjs +108 -0
  33. package/dist/ipn/index.d.cts +32 -0
  34. package/dist/ipn/index.d.ts +32 -0
  35. package/dist/ipn/index.js +101 -0
  36. package/dist/money/index.cjs +15 -0
  37. package/dist/money/index.d.cts +2 -0
  38. package/dist/money/index.d.ts +2 -0
  39. package/dist/money/index.js +2 -0
  40. package/dist/money-C9j7nBNP.js +258 -0
  41. package/dist/money-DkiGukAw.cjs +335 -0
  42. package/dist/session-CRGOuz-R.cjs +100 -0
  43. package/dist/session-Dm_45x8K.d.cts +11 -0
  44. package/dist/session-Dm_45x8K.d.ts +11 -0
  45. package/dist/session-OJMLGufT.js +77 -0
  46. package/dist/shared-CrxlxI8n.cjs +207 -0
  47. package/dist/shared-D6DLa4b7.js +100 -0
  48. package/dist/storage/fs.cjs +88 -0
  49. package/dist/storage/fs.d.cts +13 -0
  50. package/dist/storage/fs.d.ts +13 -0
  51. package/dist/storage/fs.js +87 -0
  52. package/dist/storage/index.cjs +643 -0
  53. package/dist/storage/index.d.cts +288 -0
  54. package/dist/storage/index.d.ts +288 -0
  55. package/dist/storage/index.js +619 -0
  56. package/dist/testing/index.cjs +409 -0
  57. package/dist/testing/index.d.cts +35 -0
  58. package/dist/testing/index.d.ts +35 -0
  59. package/dist/testing/index.js +407 -0
  60. package/dist/types-DVRgwcqg.d.cts +26 -0
  61. package/dist/types-DVRgwcqg.d.ts +26 -0
  62. package/dist/validators/index.cjs +296 -0
  63. package/dist/validators/index.d.cts +51 -0
  64. package/dist/validators/index.d.ts +51 -0
  65. package/dist/validators/index.js +278 -0
  66. package/llms.txt +16 -0
  67. package/package.json +151 -0
@@ -0,0 +1,217 @@
1
+ # kassza: recipes
2
+
3
+ Copy-paste starting points. Each recipe follows the rules in [pitfalls.md](./pitfalls.md).
4
+
5
+ ## 1. One shared client (server only)
6
+
7
+ ```ts
8
+ import { createKassza } from 'kassza'
9
+
10
+ export const kassza = createKassza({
11
+ defaults: {
12
+ invoice: { prefix: 'WEB', paymentDueInDays: 8, seller: { emailReplyTo: 'billing@example.hu' } },
13
+ receipt: { prefix: 'NYGT', paymentMethod: 'bankkártya' },
14
+ },
15
+ })
16
+ ```
17
+
18
+ The client reads `SZAMLAZZ_AGENT_KEY` from the environment. Create it once per process, not once per request, so the session cookie is reused.
19
+
20
+ ## 2. Paid order → invoice, safely (Stripe, Barion, SimplePay webhooks)
21
+
22
+ ```ts
23
+ import { isSzamlazzError } from 'kassza'
24
+ import { kassza } from './kassza'
25
+
26
+ export async function invoiceOrder(order: Order) {
27
+ const orderNumber = `ORDER-${order.id}`
28
+
29
+ const existing = await kassza.invoices.find({ orderNumber })
30
+ if (existing) return existing.header.number
31
+
32
+ try {
33
+ const invoice = await kassza.invoices.create({
34
+ orderNumber,
35
+ paid: true,
36
+ paymentMethod: 'bankkártya',
37
+ buyer: {
38
+ name: order.billingName,
39
+ zip: order.zip,
40
+ city: order.city,
41
+ address: order.street,
42
+ email: order.email,
43
+ taxNumber: order.taxNumber,
44
+ },
45
+ items: order.lines.map((line) => ({
46
+ name: line.title,
47
+ quantity: line.quantity,
48
+ grossUnitPrice: line.unitPriceHuf,
49
+ vat: 27,
50
+ })),
51
+ })
52
+ return invoice.number
53
+ } catch (error) {
54
+ if (isSzamlazzError(error) && ['network', 'timeout', 'partial_success', 'duplicate'].includes(error.category)) {
55
+ const created = await kassza.invoices.find({ orderNumber })
56
+ if (created) return created.header.number
57
+ }
58
+ throw error
59
+ }
60
+ }
61
+ ```
62
+
63
+ The first `find` makes the webhook idempotent when the payment provider redelivers the event.
64
+
65
+ ## 3. Event registration: proforma → payment → invoice
66
+
67
+ ```ts
68
+ const proforma = await kassza.invoices.create({
69
+ type: 'proforma',
70
+ orderNumber: `REG-${entry.id}`,
71
+ buyer,
72
+ items: [{ name: 'Nevezési díj', grossUnitPrice: 26_000, vat: 27 }],
73
+ })
74
+
75
+ const invoice = await kassza.invoices.create({
76
+ orderNumber: `REG-${entry.id}`,
77
+ proformaNumber: proforma.number,
78
+ paid: true,
79
+ buyer,
80
+ items: [{ name: 'Nevezési díj', grossUnitPrice: 26_000, vat: 27 }],
81
+ })
82
+
83
+ await kassza.invoices.deleteProforma({ orderNumber: `REG-${entry.id}` })
84
+ ```
85
+
86
+ - `buyer` is the same buyer object on both documents.
87
+ - Call `deleteProforma` only if the proforma was never paid and must be cancelled.
88
+
89
+ ## 4. Payment notification (IPN) webhook, Next.js App Router
90
+
91
+ ```ts
92
+ import { ipnOkResponse, readIpnNotification } from 'kassza/ipn'
93
+
94
+ export async function POST(request: Request) {
95
+ const ipn = await readIpnNotification(request)
96
+ if (ipn.isFullyPaid) await markOrderPaid({ invoiceNumber: ipn.invoiceNumber, orderNumber: ipn.orderNumber })
97
+ return ipnOkResponse()
98
+ }
99
+ ```
100
+
101
+ Set the webhook URL in Számlázz.hu under Fiók beállítások / Számlázás alapadatok. `markOrderPaid` must be idempotent, because the same notification can arrive more than once.
102
+
103
+ ## 5. Cash register receipt
104
+
105
+ ```ts
106
+ const receipt = await kassza.receipts.create({
107
+ callId: `POS-${sale.id}`,
108
+ paymentMethod: sale.card ? 'bankkártya' : 'készpénz',
109
+ items: sale.lines.map((line) => ({ name: line.name, quantity: line.qty, grossUnitPrice: line.price, vat: 27 })),
110
+ })
111
+
112
+ if (sale.email) await kassza.receipts.send({ receiptNumber: receipt.number, emails: sale.email })
113
+ ```
114
+
115
+ ## 6. Save the PDF to S3 or Cloudflare R2 (no AWS SDK needed)
116
+
117
+ ```ts
118
+ import { invoicePdfKey, s3FetchStorage, storePdf } from 'kassza/storage'
119
+
120
+ const storage = s3FetchStorage({
121
+ bucket: 'invoices',
122
+ region: 'auto',
123
+ endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
124
+ accessKeyId: process.env.R2_ACCESS_KEY_ID!,
125
+ secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
126
+ })
127
+
128
+ const invoice = await kassza.invoices.create(input)
129
+ if (invoice.pdf) {
130
+ const stored = await storePdf(storage, invoicePdfKey({ number: invoice.number }), invoice.pdf)
131
+ await db.invoice.update({ where: { orderNumber }, data: { pdfKey: stored.key } })
132
+ }
133
+ ```
134
+
135
+ Other adapters with the same interface:
136
+
137
+ - `s3Storage` (AWS SDK v3 client)
138
+ - `r2BindingStorage` (Workers binding)
139
+ - `vercelBlobStorage`
140
+ - `uploadthingStorage`
141
+ - `supabaseStorage`
142
+ - `fsStorage` from `kassza/storage/fs`
143
+ - `memoryStorage`
144
+
145
+ ## 7. Serverless and edge: share the session
146
+
147
+ ```ts
148
+ import { Redis } from '@upstash/redis'
149
+ import { createKassza } from 'kassza'
150
+ import { upstashRedisCookieStore } from 'kassza/cookie-stores'
151
+
152
+ const kassza = createKassza({ cookieStore: upstashRedisCookieStore(Redis.fromEnv()) })
153
+ ```
154
+
155
+ - On Cloudflare Workers, use `cloudflareKvCookieStore(env.KASSZA_KV)`.
156
+ - Other stores: `ioredisCookieStore`, `nodeRedisCookieStore`, `customCookieStore({ get, set, delete })`.
157
+ - If the store fails, kassza simply continues without a session.
158
+
159
+ ## 8. Unit tests without calling Számlázz.hu
160
+
161
+ ```ts
162
+ import { createMockKassza } from 'kassza/testing'
163
+ import { expect, test } from 'vitest'
164
+
165
+ test('invoices a paid order once', async () => {
166
+ const kassza = createMockKassza()
167
+
168
+ await invoiceOrder(order, kassza)
169
+ await invoiceOrder(order, kassza)
170
+
171
+ expect(kassza.calls.filter((call) => call.method === 'invoices.create')).toHaveLength(1)
172
+ })
173
+
174
+ test('does not swallow a network failure when nothing was created', async () => {
175
+ const kassza = createMockKassza()
176
+ kassza.failNext('invoices.create')
177
+
178
+ await expect(invoiceOrder(order, kassza)).rejects.toMatchObject({ category: 'network' })
179
+ })
180
+ ```
181
+
182
+ Inject the client into your function, for example `invoiceOrder(order, kassza = defaultKassza)`, so tests can pass the mock. Mock method names match the API paths: `'invoices.create'`, `'invoices.get'` (also used by `find`), `'receipts.send'`, and so on.
183
+
184
+ ## 9. Fill the buyer from a tax number
185
+
186
+ ```ts
187
+ import { parseHungarianTaxNumber } from 'kassza/validators'
188
+
189
+ if (!parseHungarianTaxNumber(input)) throw new Error('Érvénytelen adószám')
190
+
191
+ const company = await kassza.taxpayer.query(input)
192
+ if (company.valid && company.address) {
193
+ buyer = {
194
+ name: company.name ?? '',
195
+ zip: company.address.postalCode,
196
+ city: company.address.city,
197
+ address: company.address.formatted.split(', ').slice(1).join(', '),
198
+ taxNumber: company.taxNumber?.formatted,
199
+ }
200
+ }
201
+ ```
202
+
203
+ ## 10. Foreign currency and EU buyer
204
+
205
+ ```ts
206
+ await kassza.invoices.create({
207
+ currency: 'EUR',
208
+ language: 'en',
209
+ buyer: {
210
+ name: 'Acme GmbH', country: 'Germany', zip: '10115', city: 'Berlin', address: 'Hauptstr. 1',
211
+ euTaxNumber: 'DE123456789', taxpayerType: 'euBusiness',
212
+ },
213
+ items: [{ name: 'Consulting', quantity: 8, unit: 'hour', netUnitPrice: 95, vat: 'EUFAD37' }],
214
+ })
215
+ ```
216
+
217
+ The exchange rate comes from MNB automatically when `exchangeRate` is omitted. Choose the VAT code together with an accountant.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: kassza
3
+ description: Issue Hungarian invoices, proformas and receipts through Számlázz.hu with the kassza npm package. Use when code creates, reverses, queries or emails számla, díjbekérő or nyugta documents, handles Számlázz.hu IPN webhooks, looks up Hungarian tax numbers, or mentions szamlazz.hu, Számla Agent or SZAMLAZZ_AGENT_KEY.
4
+ ---
5
+
6
+ # kassza: Számlázz.hu integration
7
+
8
+ Before writing code, read the package docs from `node_modules/kassza/agents/`:
9
+
10
+ - `pitfalls.md`: hard rules, always read it.
11
+ - `api.md`: exact method signatures.
12
+ - `recipes.md`: patterns for webhooks, receipts, IPN, PDF storage, serverless and tests.
13
+
14
+ ## Non-negotiable rules
15
+
16
+ 1. Create one server-side client with `createKassza()`. The key comes from `SZAMLAZZ_AGENT_KEY`. Never import kassza in client-side code.
17
+ 2. Set `orderNumber` on every invoice and `callId` on every receipt, derived from the order ID.
18
+ 3. Give prices as `netUnitPrice` (B2B) or `grossUnitPrice` (B2C) together with `vat`. Do not compute item amounts, and do not pass UTC date strings.
19
+ 4. Never retry `invoices.create` or `receipts.create` yourself. On an error with category `network`, `timeout`, `partial_success` or `duplicate`, call `kassza.invoices.find({ orderNumber })` before doing anything else.
20
+ 5. Branch on `SzamlazzError.category` and `code`, not on message text.
21
+ 6. Tests must use `createMockKassza()` from `kassza/testing`, never a real Agent key.
22
+
23
+ ## Checklist before finishing
24
+
25
+ - [ ] The webhook or job that issues documents is idempotent: it runs `find` first, or catches `duplicate`.
26
+ - [ ] The PDF is stored (`kassza/storage`) or re-fetched with `invoices.getPdf`, not stored as base64 in the database.
27
+ - [ ] The IPN route returns HTTP 200 (`ipnOkResponse()`) and processes notifications idempotently.
28
+ - [ ] In serverless or edge environments, a shared `cookieStore` from `kassza/cookie-stores` is configured.
29
+ - [ ] There is a unit test with `createMockKassza()`.
@@ -0,0 +1,25 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="320" viewBox="0 0 1200 320" role="img" aria-labelledby="title">
2
+ <title id="title">kassza</title>
3
+ <style>.word{fill:#14532D}.tag{fill:#4B5563}@media (prefers-color-scheme:dark){.word{fill:#4ADE80}.tag{fill:#D1D5DB}}</style>
4
+ <defs>
5
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
6
+ <stop offset="0" stop-color="#14532D"/>
7
+ <stop offset="1" stop-color="#052E16"/>
8
+ </linearGradient>
9
+ <linearGradient id="paper" x1="0" y1="0" x2="0" y2="1">
10
+ <stop offset="0" stop-color="#FFFDF5"/>
11
+ <stop offset="1" stop-color="#F3EBD3"/>
12
+ </linearGradient>
13
+ </defs>
14
+ <g transform="translate(24 24) scale(0.53125)">
15
+ <rect width="512" height="512" rx="112" fill="url(#bg)"/>
16
+ <path d="M146 84H366A20 20 0 0 1 386 104V428l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18V104A20 20 0 0 1 146 84Z" fill="#000" opacity=".22" transform="translate(0 10)"/>
17
+ <path d="M146 84H366A20 20 0 0 1 386 104V428l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18V104A20 20 0 0 1 146 84Z" fill="url(#paper)"/>
18
+ <path d="M170 136h40v88l76-88h50l-80 90 86 116h-50l-62-86-20 22v64h-40z" fill="#14532D"/>
19
+ <rect x="160" y="368" width="120" height="12" rx="6" fill="#14532D" opacity=".28"/>
20
+ <rect x="304" y="368" width="48" height="12" rx="6" fill="#F59E0B"/>
21
+ </g>
22
+ <text x="340" y="196" font-family="ui-rounded, 'SF Pro Rounded', 'Nunito', 'Inter', system-ui, sans-serif" font-size="168" font-weight="800" letter-spacing="-6" class="word">kassza</text>
23
+ <rect x="348" y="226" width="96" height="14" rx="7" fill="#F59E0B"/>
24
+ <text x="464" y="240" font-family="ui-monospace, 'SF Mono', 'JetBrains Mono', monospace" font-size="30" font-weight="500" class="tag">Számlázz.hu, TypeScriptben</text>
25
+ </svg>
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-labelledby="title">
2
+ <title id="title">kassza</title>
3
+ <defs>
4
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
5
+ <stop offset="0" stop-color="#14532D"/>
6
+ <stop offset="1" stop-color="#052E16"/>
7
+ </linearGradient>
8
+ <linearGradient id="paper" x1="0" y1="0" x2="0" y2="1">
9
+ <stop offset="0" stop-color="#FFFDF5"/>
10
+ <stop offset="1" stop-color="#F3EBD3"/>
11
+ </linearGradient>
12
+ </defs>
13
+ <rect width="512" height="512" rx="112" fill="url(#bg)"/>
14
+ <path d="M146 84H366A20 20 0 0 1 386 104V428l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18V104A20 20 0 0 1 146 84Z" fill="#000" opacity=".22" transform="translate(0 10)"/>
15
+ <path d="M146 84H366A20 20 0 0 1 386 104V428l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18 l-13 -18 l-13 18V104A20 20 0 0 1 146 84Z" fill="url(#paper)"/>
16
+ <path d="M170 136h40v88l76-88h50l-80 90 86 116h-50l-62-86-20 22v64h-40z" fill="#14532D"/>
17
+ <rect x="160" y="368" width="120" height="12" rx="6" fill="#14532D" opacity=".28"/>
18
+ <rect x="304" y="368" width="48" height="12" rx="6" fill="#F59E0B"/>
19
+ </svg>
@@ -0,0 +1,63 @@
1
+ //#region src/core/binary.ts
2
+ const PDF_MAGIC = [
3
+ 37,
4
+ 80,
5
+ 68,
6
+ 70
7
+ ];
8
+ function isPdf(bytes) {
9
+ if (bytes.length < PDF_MAGIC.length) return false;
10
+ return PDF_MAGIC.every((byte, index) => bytes[index] === byte);
11
+ }
12
+ const utf8Decoder = new TextDecoder("utf-8");
13
+ const utf8Encoder = new TextEncoder();
14
+ function decodeUtf8(bytes) {
15
+ return utf8Decoder.decode(bytes);
16
+ }
17
+ function encodeUtf8(value) {
18
+ return utf8Encoder.encode(value);
19
+ }
20
+ function base64ToBytes(base64) {
21
+ const clean = base64.replace(/[^A-Za-z0-9+/=_-]/g, "").replace(/-/g, "+").replace(/_/g, "/");
22
+ const binary = atob(clean);
23
+ const bytes = new Uint8Array(binary.length);
24
+ for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
25
+ return bytes;
26
+ }
27
+ const BASE64_CHUNK_SIZE = 32768;
28
+ function bytesToBase64(bytes) {
29
+ let binary = "";
30
+ for (let offset = 0; offset < bytes.length; offset += BASE64_CHUNK_SIZE) binary += String.fromCharCode(...bytes.subarray(offset, offset + BASE64_CHUNK_SIZE));
31
+ return btoa(binary);
32
+ }
33
+ //#endregion
34
+ Object.defineProperty(exports, "base64ToBytes", {
35
+ enumerable: true,
36
+ get: function() {
37
+ return base64ToBytes;
38
+ }
39
+ });
40
+ Object.defineProperty(exports, "bytesToBase64", {
41
+ enumerable: true,
42
+ get: function() {
43
+ return bytesToBase64;
44
+ }
45
+ });
46
+ Object.defineProperty(exports, "decodeUtf8", {
47
+ enumerable: true,
48
+ get: function() {
49
+ return decodeUtf8;
50
+ }
51
+ });
52
+ Object.defineProperty(exports, "encodeUtf8", {
53
+ enumerable: true,
54
+ get: function() {
55
+ return encodeUtf8;
56
+ }
57
+ });
58
+ Object.defineProperty(exports, "isPdf", {
59
+ enumerable: true,
60
+ get: function() {
61
+ return isPdf;
62
+ }
63
+ });
@@ -0,0 +1,34 @@
1
+ //#region src/core/binary.ts
2
+ const PDF_MAGIC = [
3
+ 37,
4
+ 80,
5
+ 68,
6
+ 70
7
+ ];
8
+ function isPdf(bytes) {
9
+ if (bytes.length < PDF_MAGIC.length) return false;
10
+ return PDF_MAGIC.every((byte, index) => bytes[index] === byte);
11
+ }
12
+ const utf8Decoder = new TextDecoder("utf-8");
13
+ const utf8Encoder = new TextEncoder();
14
+ function decodeUtf8(bytes) {
15
+ return utf8Decoder.decode(bytes);
16
+ }
17
+ function encodeUtf8(value) {
18
+ return utf8Encoder.encode(value);
19
+ }
20
+ function base64ToBytes(base64) {
21
+ const clean = base64.replace(/[^A-Za-z0-9+/=_-]/g, "").replace(/-/g, "+").replace(/_/g, "/");
22
+ const binary = atob(clean);
23
+ const bytes = new Uint8Array(binary.length);
24
+ for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
25
+ return bytes;
26
+ }
27
+ const BASE64_CHUNK_SIZE = 32768;
28
+ function bytesToBase64(bytes) {
29
+ let binary = "";
30
+ for (let offset = 0; offset < bytes.length; offset += BASE64_CHUNK_SIZE) binary += String.fromCharCode(...bytes.subarray(offset, offset + BASE64_CHUNK_SIZE));
31
+ return btoa(binary);
32
+ }
33
+ //#endregion
34
+ export { isPdf as a, encodeUtf8 as i, bytesToBase64 as n, decodeUtf8 as r, base64ToBytes as t };