@kreiseck/kasseneck-api 0.6.45 → 0.6.49

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 (110) hide show
  1. package/README.md +95 -15
  2. package/dist/cjs/client/aufrufe.d.ts +1 -1
  3. package/dist/cjs/client/aufrufe.js +2 -0
  4. package/dist/cjs/client/errors.d.ts +7 -1
  5. package/dist/cjs/client/errors.js +8 -1
  6. package/dist/cjs/client/receipts.d.ts +16 -0
  7. package/dist/cjs/client/receipts.js +10 -0
  8. package/dist/cjs/client/transport.js +5 -4
  9. package/dist/cjs/index.d.ts +1 -1
  10. package/dist/cjs/index.js +4 -2
  11. package/dist/cjs/kasse/index.d.ts +1 -0
  12. package/dist/cjs/kasse/index.js +3 -0
  13. package/dist/cjs/kasse/trinkgeld.d.ts +10 -0
  14. package/dist/cjs/kasse/trinkgeld.js +27 -0
  15. package/dist/cjs/models/cancellation.d.ts +22 -0
  16. package/dist/cjs/models/cancellation.js +31 -1
  17. package/dist/cjs/models/hobex-receipt.js +9 -2
  18. package/dist/cjs/models/index.d.ts +1 -1
  19. package/dist/cjs/models/index.js +3 -1
  20. package/dist/cjs/models/receipt.js +3 -0
  21. package/dist/cjs/models/voucher.js +18 -2
  22. package/dist/cjs/payments/hobex-hps/connect-client.d.ts +104 -0
  23. package/dist/cjs/payments/hobex-hps/connect-client.js +159 -0
  24. package/dist/cjs/payments/hobex-hps/errors.d.ts +122 -0
  25. package/dist/cjs/payments/hobex-hps/errors.js +158 -0
  26. package/dist/cjs/payments/hobex-hps/events.d.ts +22 -0
  27. package/dist/cjs/payments/hobex-hps/events.js +2 -0
  28. package/dist/cjs/payments/hobex-hps/index.d.ts +27 -0
  29. package/dist/cjs/payments/hobex-hps/index.js +66 -0
  30. package/dist/cjs/payments/hobex-hps/outcome.d.ts +31 -0
  31. package/dist/cjs/payments/hobex-hps/outcome.js +7 -0
  32. package/dist/cjs/payments/hobex-hps/payments.d.ts +149 -0
  33. package/dist/cjs/payments/hobex-hps/payments.js +550 -0
  34. package/dist/cjs/payments/hobex-hps/receipt.d.ts +28 -0
  35. package/dist/cjs/payments/hobex-hps/receipt.js +60 -0
  36. package/dist/cjs/payments/hobex-hps/transaction-id.d.ts +65 -0
  37. package/dist/cjs/payments/hobex-hps/transaction-id.js +91 -0
  38. package/dist/cjs/payments/hobex-hps/transaction-response.d.ts +163 -0
  39. package/dist/cjs/payments/hobex-hps/transaction-response.js +245 -0
  40. package/dist/cjs/payments/hobex.js +9 -6
  41. package/dist/cjs/payments/index.d.ts +26 -14
  42. package/dist/cjs/payments/index.js +59 -15
  43. package/dist/cjs/printing/index.d.ts +1 -1
  44. package/dist/cjs/printing/index.js +2 -1
  45. package/dist/cjs/printing/webusb.d.ts +37 -7
  46. package/dist/cjs/printing/webusb.js +76 -18
  47. package/dist/cjs/receipt/epos.d.ts +18 -0
  48. package/dist/cjs/receipt/epos.js +78 -6
  49. package/dist/cjs/receipt/index.d.ts +1 -1
  50. package/dist/cjs/receipt/index.js +2 -1
  51. package/dist/cjs/register/index.d.ts +1 -1
  52. package/dist/cjs/register/index.js +2 -1
  53. package/dist/cjs/register/pairing.d.ts +67 -1
  54. package/dist/cjs/register/pairing.js +59 -3
  55. package/dist/esm/client/aufrufe.d.ts +1 -1
  56. package/dist/esm/client/aufrufe.js +2 -0
  57. package/dist/esm/client/errors.d.ts +7 -1
  58. package/dist/esm/client/errors.js +8 -1
  59. package/dist/esm/client/receipts.d.ts +16 -0
  60. package/dist/esm/client/receipts.js +10 -0
  61. package/dist/esm/client/transport.js +5 -4
  62. package/dist/esm/index.d.ts +1 -1
  63. package/dist/esm/index.js +1 -1
  64. package/dist/esm/kasse/index.d.ts +1 -0
  65. package/dist/esm/kasse/index.js +1 -0
  66. package/dist/esm/kasse/trinkgeld.d.ts +10 -0
  67. package/dist/esm/kasse/trinkgeld.js +24 -0
  68. package/dist/esm/models/cancellation.d.ts +22 -0
  69. package/dist/esm/models/cancellation.js +29 -0
  70. package/dist/esm/models/hobex-receipt.js +10 -3
  71. package/dist/esm/models/index.d.ts +1 -1
  72. package/dist/esm/models/index.js +1 -1
  73. package/dist/esm/models/receipt.js +3 -0
  74. package/dist/esm/models/voucher.js +18 -2
  75. package/dist/esm/payments/hobex-hps/connect-client.d.ts +104 -0
  76. package/dist/esm/payments/hobex-hps/connect-client.js +156 -0
  77. package/dist/esm/payments/hobex-hps/errors.d.ts +122 -0
  78. package/dist/esm/payments/hobex-hps/errors.js +149 -0
  79. package/dist/esm/payments/hobex-hps/events.d.ts +22 -0
  80. package/dist/esm/payments/hobex-hps/events.js +1 -0
  81. package/dist/esm/payments/hobex-hps/index.d.ts +27 -0
  82. package/dist/esm/payments/hobex-hps/index.js +26 -0
  83. package/dist/esm/payments/hobex-hps/outcome.d.ts +31 -0
  84. package/dist/esm/payments/hobex-hps/outcome.js +4 -0
  85. package/dist/esm/payments/hobex-hps/payments.d.ts +149 -0
  86. package/dist/esm/payments/hobex-hps/payments.js +547 -0
  87. package/dist/esm/payments/hobex-hps/receipt.d.ts +28 -0
  88. package/dist/esm/payments/hobex-hps/receipt.js +57 -0
  89. package/dist/esm/payments/hobex-hps/transaction-id.d.ts +65 -0
  90. package/dist/esm/payments/hobex-hps/transaction-id.js +86 -0
  91. package/dist/esm/payments/hobex-hps/transaction-response.d.ts +163 -0
  92. package/dist/esm/payments/hobex-hps/transaction-response.js +233 -0
  93. package/dist/esm/payments/hobex.js +9 -6
  94. package/dist/esm/payments/index.d.ts +26 -14
  95. package/dist/esm/payments/index.js +26 -14
  96. package/dist/esm/printing/index.d.ts +1 -1
  97. package/dist/esm/printing/index.js +1 -1
  98. package/dist/esm/printing/webusb.d.ts +37 -7
  99. package/dist/esm/printing/webusb.js +74 -17
  100. package/dist/esm/receipt/epos.d.ts +18 -0
  101. package/dist/esm/receipt/epos.js +76 -6
  102. package/dist/esm/receipt/index.d.ts +1 -1
  103. package/dist/esm/receipt/index.js +1 -1
  104. package/dist/esm/register/index.d.ts +1 -1
  105. package/dist/esm/register/index.js +1 -1
  106. package/dist/esm/register/pairing.d.ts +67 -1
  107. package/dist/esm/register/pairing.js +58 -3
  108. package/fixtures/hobex-hps-codes.json +67 -0
  109. package/fixtures/oberflaeche.json +3 -1
  110. package/package.json +4 -2
@@ -0,0 +1,156 @@
1
+ import { HpsConnectTerminalError, HpsConnectTransportError, HpsPreflightError, HpsTransactionIdError, PREFLIGHT_CONNECT_CODES, } from './errors.js';
2
+ import { isValidHpsTransactionId } from './transaction-id.js';
3
+ import { parseHpsTransactionResponse } from './transaction-response.js';
4
+ const DEFAULT_BASE_URL = 'http://127.0.0.1:27182';
5
+ const DEFAULT_SHORT_TIMEOUT_MS = 30_000;
6
+ const DEFAULT_PAYMENT_TIMEOUT_MS = 4 * 60_000 + 30_000;
7
+ export function createHpsConnectClient(options) {
8
+ const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
9
+ const token = options.token;
10
+ const shortTimeoutMs = options.shortTimeoutMs ?? DEFAULT_SHORT_TIMEOUT_MS;
11
+ const paymentTimeoutMs = options.paymentTimeoutMs ?? DEFAULT_PAYMENT_TIMEOUT_MS;
12
+ const holen = options.fetch ?? globalHpsConnectFetch();
13
+ async function rufen(path, body, timeoutMs) {
14
+ const abbruch = new AbortController();
15
+ const wecker = setTimeout(() => abbruch.abort(), timeoutMs);
16
+ let antwort;
17
+ let text;
18
+ try {
19
+ try {
20
+ antwort = await holen(`${baseUrl}${path}`, {
21
+ method: 'POST',
22
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
23
+ body: JSON.stringify(body),
24
+ signal: abbruch.signal,
25
+ });
26
+ text = await antwort.text();
27
+ }
28
+ catch (ursache) {
29
+ // Connect selbst nicht erreichbar (Agent nicht gestartet, falscher
30
+ // Port, Zeitueberschreitung dieses Aufrufs). Kein Terminal-Kontakt
31
+ // versucht -- das entscheidet payments.ts aber nicht hier, sondern
32
+ // ueber die Fehlerart: [HpsConnectTransportError] wird dort wie jeder
33
+ // andere Transportfehler behandelt (klaeren, niemals `declined`).
34
+ const grund = abbruch.signal.aborted ? `Zeitueberschreitung nach ${timeoutMs} ms` : String(ursache);
35
+ throw new HpsConnectTransportError(`Kasseneck Connect nicht erreichbar (${baseUrl}): ${grund}`);
36
+ }
37
+ }
38
+ finally {
39
+ clearTimeout(wecker);
40
+ }
41
+ let huelle;
42
+ try {
43
+ huelle = text.trim() === '' ? null : JSON.parse(text);
44
+ }
45
+ catch {
46
+ throw new HpsConnectTransportError(`Antwort von Kasseneck Connect ist kein JSON (HTTP ${antwort.status})`);
47
+ }
48
+ if (huelle === null || typeof huelle !== 'object' || !('ok' in huelle)) {
49
+ throw new HpsConnectTransportError(`Antwort von Kasseneck Connect ohne "ok"-Feld (HTTP ${antwort.status})`);
50
+ }
51
+ const h = huelle;
52
+ if (h.ok === true) {
53
+ return h;
54
+ }
55
+ const code = typeof h.error?.code === 'string' ? h.error.code : undefined;
56
+ const message = typeof h.error?.message === 'string' && h.error.message.trim() !== ''
57
+ ? h.error.message
58
+ : `Kasseneck Connect meldet einen Fehler (HTTP ${antwort.status})`;
59
+ if (code !== undefined && PREFLIGHT_CONNECT_CODES.has(code)) {
60
+ // Siehe errors.ts: diese Codes entstehen laut `kasseneck-connect`
61
+ // ausnahmslos VOR jedem Terminal-Kontakt -- beweisbar nichts gesendet.
62
+ throw new HpsPreflightError(message, code);
63
+ }
64
+ // terminal_error / timeout / terminal_offline -- oder ein Code, den
65
+ // dieses Paket nicht kennt. Bewusst dieselbe Klasse fuer beide: ein
66
+ // unbekannter Code ist keine bewiesene Nicht-Aussendung, siehe
67
+ // PREFLIGHT_CONNECT_CODES.
68
+ //
69
+ // `error.detail.terminalHttpStatus` reist seit `kasseneck-connect`
70
+ // Commit `0fb6f66` mit, wenn das TERMINAL selbst einen HTTP-Status
71
+ // genannt hat (nie bei einem Transportfehler -- der erfindet keinen
72
+ // Status). Siehe errors.ts, `HpsConnectTerminalError.isTerminalBusy`.
73
+ const detail = h.error?.detail;
74
+ const terminalHttpStatus = typeof detail?.terminalHttpStatus === 'number' ? detail.terminalHttpStatus : undefined;
75
+ throw new HpsConnectTerminalError(code ?? 'unbekannt', message, terminalHttpStatus);
76
+ }
77
+ function checkedTransactionId(value) {
78
+ if (!isValidHpsTransactionId(value)) {
79
+ throw new HpsTransactionIdError(value);
80
+ }
81
+ return value;
82
+ }
83
+ function target(t) {
84
+ return { host: t.host, port: t.port, tid: t.tid };
85
+ }
86
+ return {
87
+ async payment(o) {
88
+ const transactionId = checkedTransactionId(o.transactionId);
89
+ const antwort = await rufen('/v1/terminal/payment', {
90
+ ...target(o),
91
+ transactionId,
92
+ amountCents: o.amountCents,
93
+ tipCents: o.tipCents,
94
+ reference: o.reference,
95
+ currency: o.currency,
96
+ language: o.language,
97
+ }, paymentTimeoutMs);
98
+ return parseHpsTransactionResponse(antwort['hps']);
99
+ },
100
+ async status(o) {
101
+ const transactionId = checkedTransactionId(o.transactionId);
102
+ const antwort = await rufen('/v1/terminal/status', { ...target(o), transactionId }, shortTimeoutMs);
103
+ return parseHpsTransactionResponse(antwort['hps']);
104
+ },
105
+ async abort(o) {
106
+ const transactionId = checkedTransactionId(o.transactionId);
107
+ const antwort = await rufen('/v1/terminal/abort', { ...target(o), transactionId }, shortTimeoutMs);
108
+ return parseHpsTransactionResponse(antwort['hps']);
109
+ },
110
+ async refund(o) {
111
+ // Beide Kennungen gehen ans Terminal -- beide muessen die
112
+ // Ziffernpruefung bestehen, sonst ist der Vorgang spaeter dauerhaft
113
+ // unauffindbar (siehe HpsClient._checkTransactionId im Dart-Zwilling).
114
+ const transactionId = checkedTransactionId(o.transactionId);
115
+ const originalTransactionId = checkedTransactionId(o.originalTransactionId);
116
+ const antwort = await rufen('/v1/terminal/refund', {
117
+ ...target(o),
118
+ transactionId,
119
+ originalTransactionId,
120
+ amountCents: o.amountCents,
121
+ reference: o.reference,
122
+ currency: o.currency,
123
+ language: o.language,
124
+ },
125
+ // Gutschrift ist ein Kartenfluss wie die Zahlung -- dieselbe lange Frist.
126
+ paymentTimeoutMs);
127
+ return parseHpsTransactionResponse(antwort['hps']);
128
+ },
129
+ async cancel(o) {
130
+ // Hier ist [transactionId] die der URSPRUENGLICHEN Zahlung -- die
131
+ // Ziffernpruefung gilt trotzdem unveraendert, sonst liefe die
132
+ // anschliessende Statusabfrage darauf ins Leere.
133
+ const transactionId = checkedTransactionId(o.transactionId);
134
+ const antwort = await rufen('/v1/terminal/cancel', {
135
+ ...target(o),
136
+ transactionId,
137
+ amountCents: o.amountCents,
138
+ currency: o.currency,
139
+ language: o.language,
140
+ }, shortTimeoutMs);
141
+ return parseHpsTransactionResponse(antwort['hps']);
142
+ },
143
+ async diagnosis(o) {
144
+ const antwort = await rufen('/v1/terminal/diagnosis', target(o), shortTimeoutMs);
145
+ const hps = antwort['hps'];
146
+ return hps !== null && typeof hps === 'object' && !Array.isArray(hps) ? hps : {};
147
+ },
148
+ };
149
+ }
150
+ function globalHpsConnectFetch() {
151
+ const umgebung = globalThis;
152
+ if (typeof umgebung.fetch !== 'function') {
153
+ throw new Error('createHpsConnectClient: kein globales fetch vorhanden -- Node >= 20.18 verwenden oder eine fetch-Umsetzung uebergeben');
154
+ }
155
+ return (url, init) => umgebung.fetch(url, init);
156
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Fehlerarten auf dem Weg ueber **Kasseneck Connect** zum hobex-HPS-Terminal.
3
+ *
4
+ * Drei Arten, bewusst getrennt, weil `payments.ts` auf jede anders reagiert —
5
+ * das ist die wichtigste Unterscheidung in diesem ganzen Vorhaben:
6
+ *
7
+ * - [HpsPreflightError] — es ist NACHWEISLICH nichts gesendet worden. Entweder
8
+ * die Kennung selbst war unbrauchbar (siehe `connect-client.ts`), oder
9
+ * Connect hat die Anfrage VOR dem Terminal-Kontakt abgelehnt (falscher
10
+ * Host, keine Kopplung, ...). Wird von `payments.ts` unveraendert
11
+ * weitergeworfen, niemals in einen Ausgang uebersetzt — Zwilling von
12
+ * Dart's `ArgumentError`-Sonderfall in `HpsPayments.pay()`.
13
+ * - [HpsConnectTerminalError] — die Anfrage GING RAUS (oder der Versuch dazu
14
+ * scheiterte am Transport), aber es kam keine schluessige Antwort. Das
15
+ * umfasst ausdruecklich auch [isTerminalBusy]: HTTP `409` ist die einzige
16
+ * dieser Lagen, die als [isTerminalBusy] eine POSITIVE Aussage traegt,
17
+ * siehe dort.
18
+ * - [HpsConnectTransportError] — Connect selbst war nicht erreichbar oder
19
+ * antwortete nicht in der erwarteten Form (kein JSON, keine Huelle).
20
+ *
21
+ * Beide letzteren werden von `payments.ts` in die Klaerung (Abbruch + Polling)
22
+ * geschickt, NIE in `declined` uebersetzt — mit der einen, gemessenen
23
+ * Ausnahme [isTerminalBusy].
24
+ */
25
+ export declare abstract class HpsConnectException extends Error {
26
+ }
27
+ /**
28
+ * Nichts ist gesendet worden. `reason` ist deutscher Klartext, `connectCode`
29
+ * gesetzt, wenn die Ablehnung von Connect kam (statt von der lokalen
30
+ * Kennungspruefung).
31
+ */
32
+ export declare class HpsPreflightError extends HpsConnectException {
33
+ readonly name: string;
34
+ readonly connectCode: string | undefined;
35
+ constructor(reason: string, connectCode?: string);
36
+ }
37
+ /**
38
+ * Die Transaktionskennung ist unbrauchbar (nicht rein numerisch, leer, oder
39
+ * laenger als 18 Stellen) — geprueft BEVOR irgendetwas an Connect geht, wie
40
+ * bei `HpsClient._checkTransactionId` im Dart-Zwilling.
41
+ *
42
+ * Eigene Klasse (statt nur [HpsPreflightError]) macht die Unterscheidung
43
+ * `instanceof`-pruefbar, ohne sich auf einen Text zu verlassen.
44
+ */
45
+ export declare class HpsTransactionIdError extends HpsPreflightError {
46
+ readonly name = "HpsTransactionIdError";
47
+ readonly value: string;
48
+ constructor(value: string);
49
+ }
50
+ /**
51
+ * Bekannte Connect-Fehlercodes, die VOR jedem Terminal-Kontakt entstehen (aus
52
+ * `kasseneck-connect/lib/src/api/{auth,responses,routes_terminal}.dart`):
53
+ * Middleware (Herkunft, Token, Pfad, Rumpfgroesse) oder die Feldpruefung in
54
+ * `_ziel`/`_handlePayment`/`_mitTransaktion` laufen alle, BEVOR die Bruecke
55
+ * `HpsBridge` das Terminal ueberhaupt anspricht.
56
+ *
57
+ * Bewusst eine Positivliste: nur ein hier benannter Code gilt als "beweisbar
58
+ * nichts gesendet". Ein Code, den diese Liste nicht kennt, wird in
59
+ * `connect-client.ts` NICHT als [HpsPreflightError] gelesen, sondern als
60
+ * [HpsConnectTerminalError] — die sichere Richtung, falls Connect einmal um
61
+ * einen Fehlercode erweitert wird, der doch am Terminal entsteht.
62
+ */
63
+ export declare const PREFLIGHT_CONNECT_CODES: ReadonlySet<string>;
64
+ /**
65
+ * Die Anfrage ging (oder der Versuch dazu) in Richtung Terminal, aber es kam
66
+ * keine schluessige Antwort — Connect meldete `terminal_error`, `timeout`
67
+ * oder `terminal_offline` (`kasseneck-connect/lib/src/terminal/hps.dart`),
68
+ * oder einen Fehlercode, den dieses Paket nicht kennt.
69
+ */
70
+ export declare class HpsConnectTerminalError extends HpsConnectException {
71
+ readonly name = "HpsConnectTerminalError";
72
+ /** Fehlercode von Connect, z. B. `terminal_error`, `timeout`, `terminal_offline`. */
73
+ readonly connectCode: string;
74
+ /**
75
+ * Der rohe HTTP-Status des Terminals, wenn Connect einen genannt hat
76
+ * (`error.detail.terminalHttpStatus`, seit `kasseneck-connect` Commit
77
+ * `0fb6f66`, "fix(terminal): den rohen HTTP-Status des Terminals mitgeben").
78
+ * `undefined` bei einem Transportfehler (Connect erfindet dort keinen) oder
79
+ * bei einer aelteren Connect-Fassung, die das Feld noch nicht sendet.
80
+ */
81
+ readonly terminalHttpStatus: number | undefined;
82
+ constructor(connectCode: string, message: string, terminalHttpStatus?: number);
83
+ /**
84
+ * `true`, wenn dies der gemessene "Terminal beschaeftigt"-Fall ist: das
85
+ * Terminal hat mit HTTP `409` geantwortet.
86
+ *
87
+ * Liest bevorzugt [terminalHttpStatus] — das strukturierte Feld, das
88
+ * Connect seit `0fb6f66` mitgibt. Nur wenn das Feld fehlt (aeltere
89
+ * Connect-Fassung im Feld, die es noch nicht kennt), faellt die Pruefung
90
+ * auf den Meldungstext zurueck (`_call` in
91
+ * `kasseneck-connect/lib/src/terminal/hps.dart` schrieb schon vor `0fb6f66`
92
+ * wortgleich `'Terminal meldet (HTTP ${response.statusCode}): ...'`).
93
+ *
94
+ * **Der Rueckfall ist eine Uebergangsloesung, kein Dauerzustand.** Sobald
95
+ * jede Kasse im Feld gegen einen Connect-Agenten mit `terminalHttpStatus`
96
+ * spricht, kann der Textabgleich entfallen — bis dahin bleibt er die
97
+ * einzige Absicherung fuer eine Installation, die noch nicht aktualisiert
98
+ * hat. Bricht auch das Textmuster (Formulierungsaenderung in Connect),
99
+ * faellt diese Erkennung auf `false` zurueck — die sichere Richtung: aus
100
+ * einem `409` wuerde dann `unresolved` statt des beweisbaren `declined`,
101
+ * niemals umgekehrt.
102
+ */
103
+ get isTerminalBusy(): boolean;
104
+ }
105
+ /**
106
+ * Connect selbst war nicht erreichbar, oder die Antwort hatte nicht die
107
+ * erwartete Form (kein JSON, keine `{ok, ...}`-Huelle, unerwarteter
108
+ * HTTP-Status ohne diese Huelle).
109
+ */
110
+ export declare class HpsConnectTransportError extends HpsConnectException {
111
+ readonly name = "HpsConnectTransportError";
112
+ constructor(message: string);
113
+ }
114
+ /**
115
+ * Das Klaerbudget ist aufgebraucht, WAEHREND ein einzelner Abruf (Abbruch
116
+ * oder Statusabfrage) noch lief. Wird in `payments.ts` wie jeder andere
117
+ * Transportfehler behandelt — siehe `withinBudget`.
118
+ */
119
+ export declare class HpsClarifyTimeoutError extends HpsConnectException {
120
+ readonly name = "HpsClarifyTimeoutError";
121
+ constructor(budgetMs: number);
122
+ }
@@ -0,0 +1,149 @@
1
+ import { TERMINAL_BUSY_HTTP_STATUS } from './transaction-response.js';
2
+ /**
3
+ * Fehlerarten auf dem Weg ueber **Kasseneck Connect** zum hobex-HPS-Terminal.
4
+ *
5
+ * Drei Arten, bewusst getrennt, weil `payments.ts` auf jede anders reagiert —
6
+ * das ist die wichtigste Unterscheidung in diesem ganzen Vorhaben:
7
+ *
8
+ * - [HpsPreflightError] — es ist NACHWEISLICH nichts gesendet worden. Entweder
9
+ * die Kennung selbst war unbrauchbar (siehe `connect-client.ts`), oder
10
+ * Connect hat die Anfrage VOR dem Terminal-Kontakt abgelehnt (falscher
11
+ * Host, keine Kopplung, ...). Wird von `payments.ts` unveraendert
12
+ * weitergeworfen, niemals in einen Ausgang uebersetzt — Zwilling von
13
+ * Dart's `ArgumentError`-Sonderfall in `HpsPayments.pay()`.
14
+ * - [HpsConnectTerminalError] — die Anfrage GING RAUS (oder der Versuch dazu
15
+ * scheiterte am Transport), aber es kam keine schluessige Antwort. Das
16
+ * umfasst ausdruecklich auch [isTerminalBusy]: HTTP `409` ist die einzige
17
+ * dieser Lagen, die als [isTerminalBusy] eine POSITIVE Aussage traegt,
18
+ * siehe dort.
19
+ * - [HpsConnectTransportError] — Connect selbst war nicht erreichbar oder
20
+ * antwortete nicht in der erwarteten Form (kein JSON, keine Huelle).
21
+ *
22
+ * Beide letzteren werden von `payments.ts` in die Klaerung (Abbruch + Polling)
23
+ * geschickt, NIE in `declined` uebersetzt — mit der einen, gemessenen
24
+ * Ausnahme [isTerminalBusy].
25
+ */
26
+ export class HpsConnectException extends Error {
27
+ }
28
+ /**
29
+ * Nichts ist gesendet worden. `reason` ist deutscher Klartext, `connectCode`
30
+ * gesetzt, wenn die Ablehnung von Connect kam (statt von der lokalen
31
+ * Kennungspruefung).
32
+ */
33
+ export class HpsPreflightError extends HpsConnectException {
34
+ name = 'HpsPreflightError';
35
+ connectCode;
36
+ constructor(reason, connectCode) {
37
+ super(reason);
38
+ this.connectCode = connectCode;
39
+ }
40
+ }
41
+ /**
42
+ * Die Transaktionskennung ist unbrauchbar (nicht rein numerisch, leer, oder
43
+ * laenger als 18 Stellen) — geprueft BEVOR irgendetwas an Connect geht, wie
44
+ * bei `HpsClient._checkTransactionId` im Dart-Zwilling.
45
+ *
46
+ * Eigene Klasse (statt nur [HpsPreflightError]) macht die Unterscheidung
47
+ * `instanceof`-pruefbar, ohne sich auf einen Text zu verlassen.
48
+ */
49
+ export class HpsTransactionIdError extends HpsPreflightError {
50
+ name = 'HpsTransactionIdError';
51
+ value;
52
+ constructor(value) {
53
+ super(`Transaktionskennung "${value}" ist unbrauchbar -- HPS erlaubt 1 bis 18 `
54
+ + 'Ziffern, rein numerisch');
55
+ this.value = value;
56
+ }
57
+ }
58
+ /**
59
+ * Bekannte Connect-Fehlercodes, die VOR jedem Terminal-Kontakt entstehen (aus
60
+ * `kasseneck-connect/lib/src/api/{auth,responses,routes_terminal}.dart`):
61
+ * Middleware (Herkunft, Token, Pfad, Rumpfgroesse) oder die Feldpruefung in
62
+ * `_ziel`/`_handlePayment`/`_mitTransaktion` laufen alle, BEVOR die Bruecke
63
+ * `HpsBridge` das Terminal ueberhaupt anspricht.
64
+ *
65
+ * Bewusst eine Positivliste: nur ein hier benannter Code gilt als "beweisbar
66
+ * nichts gesendet". Ein Code, den diese Liste nicht kennt, wird in
67
+ * `connect-client.ts` NICHT als [HpsPreflightError] gelesen, sondern als
68
+ * [HpsConnectTerminalError] — die sichere Richtung, falls Connect einmal um
69
+ * einen Fehlercode erweitert wird, der doch am Terminal entsteht.
70
+ */
71
+ export const PREFLIGHT_CONNECT_CODES = new Set([
72
+ 'bad_request',
73
+ 'unauthorized',
74
+ 'origin_forbidden',
75
+ 'not_found',
76
+ 'body_too_large',
77
+ ]);
78
+ /**
79
+ * Die Anfrage ging (oder der Versuch dazu) in Richtung Terminal, aber es kam
80
+ * keine schluessige Antwort — Connect meldete `terminal_error`, `timeout`
81
+ * oder `terminal_offline` (`kasseneck-connect/lib/src/terminal/hps.dart`),
82
+ * oder einen Fehlercode, den dieses Paket nicht kennt.
83
+ */
84
+ export class HpsConnectTerminalError extends HpsConnectException {
85
+ name = 'HpsConnectTerminalError';
86
+ /** Fehlercode von Connect, z. B. `terminal_error`, `timeout`, `terminal_offline`. */
87
+ connectCode;
88
+ /**
89
+ * Der rohe HTTP-Status des Terminals, wenn Connect einen genannt hat
90
+ * (`error.detail.terminalHttpStatus`, seit `kasseneck-connect` Commit
91
+ * `0fb6f66`, "fix(terminal): den rohen HTTP-Status des Terminals mitgeben").
92
+ * `undefined` bei einem Transportfehler (Connect erfindet dort keinen) oder
93
+ * bei einer aelteren Connect-Fassung, die das Feld noch nicht sendet.
94
+ */
95
+ terminalHttpStatus;
96
+ constructor(connectCode, message, terminalHttpStatus) {
97
+ super(message);
98
+ this.connectCode = connectCode;
99
+ this.terminalHttpStatus = terminalHttpStatus;
100
+ }
101
+ /**
102
+ * `true`, wenn dies der gemessene "Terminal beschaeftigt"-Fall ist: das
103
+ * Terminal hat mit HTTP `409` geantwortet.
104
+ *
105
+ * Liest bevorzugt [terminalHttpStatus] — das strukturierte Feld, das
106
+ * Connect seit `0fb6f66` mitgibt. Nur wenn das Feld fehlt (aeltere
107
+ * Connect-Fassung im Feld, die es noch nicht kennt), faellt die Pruefung
108
+ * auf den Meldungstext zurueck (`_call` in
109
+ * `kasseneck-connect/lib/src/terminal/hps.dart` schrieb schon vor `0fb6f66`
110
+ * wortgleich `'Terminal meldet (HTTP ${response.statusCode}): ...'`).
111
+ *
112
+ * **Der Rueckfall ist eine Uebergangsloesung, kein Dauerzustand.** Sobald
113
+ * jede Kasse im Feld gegen einen Connect-Agenten mit `terminalHttpStatus`
114
+ * spricht, kann der Textabgleich entfallen — bis dahin bleibt er die
115
+ * einzige Absicherung fuer eine Installation, die noch nicht aktualisiert
116
+ * hat. Bricht auch das Textmuster (Formulierungsaenderung in Connect),
117
+ * faellt diese Erkennung auf `false` zurueck — die sichere Richtung: aus
118
+ * einem `409` wuerde dann `unresolved` statt des beweisbaren `declined`,
119
+ * niemals umgekehrt.
120
+ */
121
+ get isTerminalBusy() {
122
+ if (this.terminalHttpStatus !== undefined) {
123
+ return this.terminalHttpStatus === TERMINAL_BUSY_HTTP_STATUS;
124
+ }
125
+ return this.connectCode === 'terminal_error' && new RegExp(`\\(HTTP ${TERMINAL_BUSY_HTTP_STATUS}\\)`).test(this.message);
126
+ }
127
+ }
128
+ /**
129
+ * Connect selbst war nicht erreichbar, oder die Antwort hatte nicht die
130
+ * erwartete Form (kein JSON, keine `{ok, ...}`-Huelle, unerwarteter
131
+ * HTTP-Status ohne diese Huelle).
132
+ */
133
+ export class HpsConnectTransportError extends HpsConnectException {
134
+ name = 'HpsConnectTransportError';
135
+ constructor(message) {
136
+ super(message);
137
+ }
138
+ }
139
+ /**
140
+ * Das Klaerbudget ist aufgebraucht, WAEHREND ein einzelner Abruf (Abbruch
141
+ * oder Statusabfrage) noch lief. Wird in `payments.ts` wie jeder andere
142
+ * Transportfehler behandelt — siehe `withinBudget`.
143
+ */
144
+ export class HpsClarifyTimeoutError extends HpsConnectException {
145
+ name = 'HpsClarifyTimeoutError';
146
+ constructor(budgetMs) {
147
+ super(`Klaerbudget ueberschritten (${budgetMs} ms)`);
148
+ }
149
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Ereignisse der Klaerung — Zwilling von `HpsEventKind`/`HpsObserver`
3
+ * (`kasseneck_api/lib/src/hobex_hps/observer.dart`), hier nur fuer die
4
+ * Klaerungsphase in `payments.ts` (kein eigenes Ereignis je HTTP-Aufruf an
5
+ * Connect — die stehen bereits, mit Begruendung, in `HpsPaymentResult.steps`).
6
+ */
7
+ export type HpsPaymentEventKind =
8
+ /** Der Ausgang ist nach der direkten Antwort offen, die Klaerung laeuft. */
9
+ 'resolving'
10
+ /** Der Ausgang steht fest. */
11
+ | 'resolved'
12
+ /** Ein Fehler beim Auswerten der Antwort, der KEIN erwarteter Connect-Fehler ist. */
13
+ | 'unexpectedError';
14
+ /** Ein Ereignis der Klaerung. Bewusst schlank und ohne Kartendaten. */
15
+ export interface HpsPaymentEvent {
16
+ readonly kind: HpsPaymentEventKind;
17
+ readonly message: string;
18
+ readonly transactionId: string;
19
+ readonly error?: unknown;
20
+ }
21
+ /** Empfaenger der Ereignisse — die App legt ihn typischerweise auf ihr Protokoll. */
22
+ export type HpsPaymentObserver = (event: HpsPaymentEvent) => void;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Hobex-**HPS**-Kartenzahlung ueber **Kasseneck Connect** — den lokalen
3
+ * Geraete-Agenten, der ueber HTTP erreichbar ist und mit dem physischen
4
+ * Terminal spricht. Siehe `payments.ts` fuer den Klaerweg (Doku dort ist der
5
+ * Maszstab) und `connect-client.ts` fuer die Abgrenzung zum Dart-Zwilling
6
+ * `HpsClient` (der das Terminal DIREKT anspricht, ohne Connect).
7
+ *
8
+ * `pay`/`refund`/`cancel` — seit `kasseneck-connect` Commit `1c8a003` traegt
9
+ * Connect auch Gutschrift und Aufhebung, die Luecke aus einer frueheren
10
+ * Fassung dieses Moduls ist geschlossen.
11
+ *
12
+ * **Verbleibt: keine Adress-/Port-Ermittlung fuer Connect.** Der Agent kann
13
+ * auf `127.0.0.1:27182` bis `27189` laufen (belegter Port faellt auf den
14
+ * naechsten zurueck, siehe `kasseneck-connect`s README). Dieses Modul nimmt
15
+ * eine FESTE `baseUrl` entgegen (`HpsConnectClientOptions.baseUrl`, Vorgabe
16
+ * `27182`) und probiert die Portreihe nicht selbst durch — das Aufloesen der
17
+ * tatsaechlichen Adresse (z. B. ueber `GET /v1/status` je Port) bleibt Sache
18
+ * des Aufrufers.
19
+ */
20
+ export { type HpsConnectCancelOptions, type HpsConnectClient, type HpsConnectClientOptions, type HpsConnectFetch, type HpsConnectFetchResponse, type HpsConnectPaymentOptions, type HpsConnectRefundOptions, type HpsConnectTarget, type HpsConnectTransactionOptions, createHpsConnectClient, } from './connect-client.js';
21
+ export { HpsClarifyTimeoutError, HpsConnectException, HpsConnectTerminalError, HpsConnectTransportError, HpsPreflightError, HpsTransactionIdError, PREFLIGHT_CONNECT_CODES, } from './errors.js';
22
+ export { type HpsPaymentEvent, type HpsPaymentEventKind, type HpsPaymentObserver, } from './events.js';
23
+ export { type CardPaymentOutcome, type HpsPaymentResult, mayRetrySafely, } from './outcome.js';
24
+ export { type HpsCancelOptions, type HpsPaymentOptions, type HpsPayments, type HpsPaymentsOptions, type HpsRefundOptions, createHpsPayments, } from './payments.js';
25
+ export { MAX_TRANSACTION_ID_LENGTH, createHpsTransactionIdGenerator, isValidHpsTransactionId, newHpsTransactionId, type HpsTransactionIdGeneratorOptions, } from './transaction-id.js';
26
+ export { ABORTED_CODE, APPROVED_CODE, CARD_NOT_PRESENT_CODE, HPS_MEASURED_CODES, INVALID_TRANSACTION_CODE, NOT_ABORTABLE_CODE, INVALID_AMOUNT_CODE, AMOUNT_OUT_OF_RANGE_CODE, INVALID_TID_CODE, NO_STATEMENT_CODE, TECHNICAL_ERROR_CODE, TERMINAL_BUSY_HTTP_STATUS, TRANSACTION_CANCELED_CODE, isApproved, isCanceled, isConclusive, isInProgress, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, parseHpsTransactionResponse, type HpsMeasuredCode, type HpsTransactionResponse, } from './transaction-response.js';
27
+ export { hobexReceiptFromHps } from './receipt.js';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Hobex-**HPS**-Kartenzahlung ueber **Kasseneck Connect** — den lokalen
3
+ * Geraete-Agenten, der ueber HTTP erreichbar ist und mit dem physischen
4
+ * Terminal spricht. Siehe `payments.ts` fuer den Klaerweg (Doku dort ist der
5
+ * Maszstab) und `connect-client.ts` fuer die Abgrenzung zum Dart-Zwilling
6
+ * `HpsClient` (der das Terminal DIREKT anspricht, ohne Connect).
7
+ *
8
+ * `pay`/`refund`/`cancel` — seit `kasseneck-connect` Commit `1c8a003` traegt
9
+ * Connect auch Gutschrift und Aufhebung, die Luecke aus einer frueheren
10
+ * Fassung dieses Moduls ist geschlossen.
11
+ *
12
+ * **Verbleibt: keine Adress-/Port-Ermittlung fuer Connect.** Der Agent kann
13
+ * auf `127.0.0.1:27182` bis `27189` laufen (belegter Port faellt auf den
14
+ * naechsten zurueck, siehe `kasseneck-connect`s README). Dieses Modul nimmt
15
+ * eine FESTE `baseUrl` entgegen (`HpsConnectClientOptions.baseUrl`, Vorgabe
16
+ * `27182`) und probiert die Portreihe nicht selbst durch — das Aufloesen der
17
+ * tatsaechlichen Adresse (z. B. ueber `GET /v1/status` je Port) bleibt Sache
18
+ * des Aufrufers.
19
+ */
20
+ export { createHpsConnectClient, } from './connect-client.js';
21
+ export { HpsClarifyTimeoutError, HpsConnectException, HpsConnectTerminalError, HpsConnectTransportError, HpsPreflightError, HpsTransactionIdError, PREFLIGHT_CONNECT_CODES, } from './errors.js';
22
+ export { mayRetrySafely, } from './outcome.js';
23
+ export { createHpsPayments, } from './payments.js';
24
+ export { MAX_TRANSACTION_ID_LENGTH, createHpsTransactionIdGenerator, isValidHpsTransactionId, newHpsTransactionId, } from './transaction-id.js';
25
+ export { ABORTED_CODE, APPROVED_CODE, CARD_NOT_PRESENT_CODE, HPS_MEASURED_CODES, INVALID_TRANSACTION_CODE, NOT_ABORTABLE_CODE, INVALID_AMOUNT_CODE, AMOUNT_OUT_OF_RANGE_CODE, INVALID_TID_CODE, NO_STATEMENT_CODE, TECHNICAL_ERROR_CODE, TERMINAL_BUSY_HTTP_STATUS, TRANSACTION_CANCELED_CODE, isApproved, isCanceled, isConclusive, isInProgress, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, parseHpsTransactionResponse, } from './transaction-response.js';
26
+ export { hobexReceiptFromHps } from './receipt.js';
@@ -0,0 +1,31 @@
1
+ import type { HpsTransactionResponse } from './transaction-response.js';
2
+ /**
3
+ * Ausgang eines Kartenzahlvorgangs — die einzige Frage, die ein Aufrufer
4
+ * wirklich hat: darf ich es nochmal versuchen?
5
+ *
6
+ * Drei Werte, nicht zwei: ein `boolean` oder ein `null` als Ergebnis einer
7
+ * Zahlung waere ein Fehler, kein Stil (Zwilling: `CardPaymentOutcome` in
8
+ * `kasseneck_api/lib/src/payments/card_payment_outcome.dart`).
9
+ */
10
+ export type CardPaymentOutcome = 'approved' | 'declined' | 'unresolved';
11
+ /**
12
+ * Ergebnis einer Kartenzahlung samt Kennung und Klaerungsverlauf.
13
+ *
14
+ * [transactionId] ist IMMER gesetzt, auch bei `outcome: 'unresolved'` — ohne
15
+ * sie sind Statusabfrage und weitere Klaerung unerreichbar, und genau daran
16
+ * ist der Vorfall vom 24.08.2026 gescheitert.
17
+ */
18
+ export interface HpsPaymentResult {
19
+ readonly outcome: CardPaymentOutcome;
20
+ readonly transactionId: string;
21
+ /** Die letzte Antwort des Terminals, sofern eine schluessige ankam. */
22
+ readonly response?: HpsTransactionResponse;
23
+ /**
24
+ * Verlauf der Klaerung, in Reihenfolge — der Nachweis, der im
25
+ * Belastungsstreit gelesen wird. Behauptet nie eine Ursache, die nicht
26
+ * feststeht.
27
+ */
28
+ readonly steps: readonly string[];
29
+ }
30
+ /** Nur bei `'declined'` steht fest, dass nichts belastet wurde. */
31
+ export declare function mayRetrySafely(result: Pick<HpsPaymentResult, 'outcome'>): boolean;
@@ -0,0 +1,4 @@
1
+ /** Nur bei `'declined'` steht fest, dass nichts belastet wurde. */
2
+ export function mayRetrySafely(result) {
3
+ return result.outcome === 'declined';
4
+ }