# @generaloutsource/ksef-pdf-preview

Podgląd PDF faktur **KSeF** (FA(1)/FA(2)/FA(3)/FA_RR(1)) oraz **UPO** (v4_2/4_3) z plików XML — w **Angularze** (przez API) i w **czystym HTML** (przez web component `<ksef-pdf-preview>`). Jeden pakiet, dwa wejścia.

Renderowanie po stronie klienta, bez backendu: XML → PDF (Blob) → `blob:` URL wpięty w `<iframe>` (natywny renderer PDF przeglądarki, bez pdf.js).

> Wrapper na **oficjalny generator MF** [`CIRFMF/ksef-pdf-generator`](https://github.com/CIRFMF/ksef-pdf-generator) (`@akmf/ksef-fe-invoice-converter`). Generator jest **vendorowany** (zbudowany dist w `vendor/generator/`, nietknięty) i bundlowany do outputu. Licencja MIT (zob. atrybucja niżej).

## Instalacja

```bash
npm install @generaloutsource/ksef-pdf-preview
```

## Angular (API)

Importujesz funkcję, dostajesz `blob:` URL, renderujesz po swojemu. Ładuj **dynamicznie** (`import()`), bo bundle generatora jest ciężki (~3 MB, fonty pdfmake w środku) — nie chcesz go w głównym bundlu.

```ts
const { createInvoicePreviewUrl } = await import('@generaloutsource/ksef-pdf-preview');
const url = await createInvoicePreviewUrl(file, { nrKSeF: 'PODGLĄD', watermark: 'PODGLĄD' });
// url → <iframe [src]="sanitizer.bypassSecurityTrustResourceUrl(url)">
// po zniszczeniu komponentu: URL.revokeObjectURL(url)
```

Gotowy serwis i komponent: [`examples/angular/`](examples/angular/) (`ksef-preview.service.ts`, `preview.component.ts`).

## Czysty HTML (web component)

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@generaloutsource/ksef-pdf-preview/dist/element.js"></script>

<ksef-pdf-preview id="p" nr-ksef="PODGLĄD" watermark="PODGLĄD"></ksef-pdf-preview>
<script type="module">
  document.getElementById('p').xml = '<Faktura>...</Faktura>';   // albo .file = inputEl.files[0]
</script>
```

Działający przykład: [`examples/html/index.html`](examples/html/index.html) (`npm run example`).

### API web componentu

| | |
|---|---|
| **Atrybuty** | `nr-ksef`, `watermark`, `type` (`invoice` \| `upo`) |
| **Property** | `file` (File/Blob), `xml` (string), `data` (nadpisuje atrybuty) |
| **Zdarzenia** | `rendered` (`detail.url`), `error` (`detail.error`), `loading` |
| **CSS parts** | `iframe`, `status` |

Element pokrywa też Angulara (przez `CUSTOM_ELEMENTS_SCHEMA` + `import '@generaloutsource/ksef-pdf-preview/element'`), ale w Angularze typowane API jest zwykle wygodniejsze.

## API (wejście `.`)

```ts
generateInvoicePdf(input, data)            // → Promise<Blob>   (FA1/FA2/FA3/FA_RR, wersja wykrywana auto)
generateInvoicePdf(input, data, 'base64')  // → Promise<string>
generateUpoPdf(input)                      // → Promise<Blob>   (UPO 4_2/4_3)
createInvoicePreviewUrl(input, data?)      // → Promise<string> (blob: URL do <iframe>)
createUpoPreviewUrl(input)                 // → Promise<string>
revokePreviewUrl(url)                      // zwolnij URL
```

`input: File | Blob | string` (XML). `data: { nrKSeF: string; qrCode?; qr2Code?; isMobile?; watermark? }` — `nrKSeF` wymagane przez generator; do podglądu roboczego podaj wartość zastępczą (`PREVIEW_DEFAULTS`). Re-eksportowane są też niskopoziomowe `generateInvoice` / `generatePDFUPO` z generatora.

## Obsługiwane dokumenty

FA(1), FA(2), FA(3), FA_RR(1), UPO v4_2 i v4_3 — zgodnie z aktualnym vendorowanym generatorem MF (`vendor/generator/package.json` → pole `version`).

## Utrzymanie / aktualizacja generatora

Nasze dodatki (API + web component) to **cienka warstwa nad nietkniętym upstreamem**. Aktualizacja generatora to jedno polecenie:

```bash
npm run update:generator        # klonuje, buduje upstream, podmienia vendor/generator
npm run build                   # przebudowuje bibliotekę
```

## Uwagi

- **Tylko przeglądarka.** Generator używa `FileReader`/`pdfmake` — nie zadziała w czystym Node/SSR. W Angular SSR ładuj wyłącznie po stronie klienta.
- **Rozmiar.** `dist/index.js` ≈ 3 MB (fonty pdfmake wbudowane). `dist/element.js` jest mały i dociąga `index.js` jako moduł — zero duplikacji.
- **Zarządzanie pamięcią.** Każdy `create*PreviewUrl` tworzy obiektowy URL — zwalniaj go (`revokePreviewUrl` / `URL.revokeObjectURL`), gdy podgląd znika. Web component robi to sam.

## Atrybucja i licencja

Fork/wrapper [`CIRFMF/ksef-pdf-generator`](https://github.com/CIRFMF/ksef-pdf-generator) (Copyright © 2025 CIRF, **MIT**). Zachowano oryginalną notę licencyjną. Ten pakiet **nie jest oficjalnym produktem Ministerstwa Finansów** — to niezależny wrapper publikowany pod własną nazwą. Licencja: MIT.
