@gopaycz/gopay-js-sdk 1.6.6

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/dist/index.js ADDED
@@ -0,0 +1,1135 @@
1
+ // ../internal/core/dist/index.js
2
+ var GoPayErrorCodes = {
3
+ // Authentication errors
4
+ /** No access token in store — call authenticate() or setClientToken() */
5
+ AUTH_TOKEN_MISSING: "AUTH_TOKEN_MISSING",
6
+ /** Re-authentication (client_credentials grant) failed */
7
+ AUTH_REFRESH_FAILED: "AUTH_REFRESH_FAILED",
8
+ /** Token response from server is missing required fields */
9
+ AUTH_INVALID_RESPONSE: "AUTH_INVALID_RESPONSE",
10
+ /** No client credentials stored — call authenticate() first */
11
+ AUTH_CREDENTIALS_MISSING: "AUTH_CREDENTIALS_MISSING",
12
+ /** Access token JWT is malformed or missing the sub claim */
13
+ AUTH_INVALID_TOKEN: "AUTH_INVALID_TOKEN",
14
+ /** Request was unauthorized even after a successful token refresh */
15
+ AUTH_UNAUTHORIZED: "AUTH_UNAUTHORIZED",
16
+ // Network errors
17
+ /** Request timed out */
18
+ NETWORK_TIMEOUT: "NETWORK_TIMEOUT",
19
+ /** Network-level failure (no response received) */
20
+ NETWORK_ERROR: "NETWORK_ERROR",
21
+ // Card form errors
22
+ /** The GoPay card encryption iframe reported an error */
23
+ CARD_FORM_ERROR: "CARD_FORM_ERROR",
24
+ /** mountCardForm() was called while a session is already active — call unmount() first */
25
+ CARD_FORM_ALREADY_MOUNTED: "CARD_FORM_ALREADY_MOUNTED",
26
+ // Charge polling errors
27
+ /** Charge did not leave REQUESTED/PROCESSING within the initial timeout */
28
+ CHARGE_TIMEOUT: "CHARGE_TIMEOUT",
29
+ /** Charge reached terminal FAILED state */
30
+ CHARGE_FAILED: "CHARGE_FAILED",
31
+ // Browser SDK payment attachment
32
+ /** attachPayment() must be called before payment-scoped operations (charge, Apple/Google Pay, status) */
33
+ PAYMENT_NOT_ATTACHED: "PAYMENT_NOT_ATTACHED",
34
+ // Wallet button errors (mountApplePayButton / mountGooglePayButton)
35
+ /** The Apple Pay or Google Pay button encountered an error (unavailable, script load failure, charge error) */
36
+ WALLET_BUTTON_ERROR: "WALLET_BUTTON_ERROR",
37
+ // Usage errors
38
+ /** SDK configuration is invalid (e.g. malformed baseUrl, wrong runtime environment) */
39
+ INVALID_CONFIG: "INVALID_CONFIG",
40
+ /** A required argument is missing or invalid */
41
+ INVALID_ARGUMENT: "INVALID_ARGUMENT"
42
+ };
43
+ var GoPaySDKError = class extends Error {
44
+ constructor(message, options) {
45
+ super(message);
46
+ this.name = "GoPaySDKError";
47
+ if (options?.cause !== void 0) {
48
+ this.cause = options.cause;
49
+ }
50
+ this.errorCode = options?.errorCode;
51
+ }
52
+ };
53
+ var GoPayHTTPError = class extends Error {
54
+ constructor(status, body) {
55
+ super(`GoPay API error: HTTP ${status}`);
56
+ this.status = status;
57
+ this.body = body;
58
+ this.name = "GoPayHTTPError";
59
+ }
60
+ };
61
+ function awaitCharge(poll, options) {
62
+ const intervalMs = options?.intervalMs ?? 2e3;
63
+ const initialTimeoutMs = options?.initialTimeoutMs ?? 3e4;
64
+ if (options?.signal?.aborted) {
65
+ return Promise.reject(
66
+ new GoPaySDKError("[GoPaySDK] Charge polling aborted.", {
67
+ errorCode: GoPayErrorCodes.CHARGE_FAILED
68
+ })
69
+ );
70
+ }
71
+ return new Promise((resolve, reject) => {
72
+ let stopped = false;
73
+ let lastActionRequiredUrl = null;
74
+ const stop = (fn) => {
75
+ if (stopped) {
76
+ return;
77
+ }
78
+ stopped = true;
79
+ clearTimeout(initialTimer);
80
+ options?.signal?.removeEventListener("abort", onAbort);
81
+ fn();
82
+ };
83
+ let onAbort;
84
+ onAbort = () => {
85
+ stop(
86
+ () => reject(
87
+ new GoPaySDKError("[GoPaySDK] Charge polling aborted.", {
88
+ errorCode: GoPayErrorCodes.CHARGE_FAILED
89
+ })
90
+ )
91
+ );
92
+ };
93
+ options?.signal?.addEventListener("abort", onAbort, { once: true });
94
+ const initialTimer = setTimeout(() => {
95
+ stop(
96
+ () => reject(
97
+ new GoPaySDKError(
98
+ "[GoPaySDK] Charge did not progress within the initial timeout",
99
+ { errorCode: GoPayErrorCodes.CHARGE_TIMEOUT }
100
+ )
101
+ )
102
+ );
103
+ }, initialTimeoutMs);
104
+ const doPoll = () => {
105
+ if (stopped) {
106
+ return;
107
+ }
108
+ poll().then((state) => {
109
+ if (stopped) {
110
+ return;
111
+ }
112
+ options?.onStateChange?.(state);
113
+ if (state.state === "SUCCEEDED") {
114
+ stop(() => resolve(state));
115
+ return;
116
+ }
117
+ if (state.state === "FAILED") {
118
+ stop(
119
+ () => reject(
120
+ new GoPaySDKError("[GoPaySDK] Charge failed", {
121
+ errorCode: GoPayErrorCodes.CHARGE_FAILED
122
+ })
123
+ )
124
+ );
125
+ return;
126
+ }
127
+ if (state.state === "ACTION_REQUIRED") {
128
+ clearTimeout(initialTimer);
129
+ if (state.action?.redirect_url && state.action.redirect_url !== lastActionRequiredUrl) {
130
+ lastActionRequiredUrl = state.action.redirect_url;
131
+ options?.onActionRequired?.(
132
+ state.action.redirect_url
133
+ );
134
+ }
135
+ }
136
+ setTimeout(doPoll, intervalMs);
137
+ }).catch((err) => {
138
+ if (stopped) {
139
+ return;
140
+ }
141
+ stop(() => reject(err));
142
+ });
143
+ };
144
+ doPoll();
145
+ });
146
+ }
147
+ var BASE_URLS = {
148
+ sandbox: "https://api.sandbox.gopay.com/api/merchant/payments/4.0",
149
+ production: "https://api.gopay.com/api/merchant/payments/4.0"
150
+ };
151
+ function resolveBaseUrl(config) {
152
+ const rawBaseUrl = config.baseUrl ?? BASE_URLS[config.environment ?? "sandbox"];
153
+ if (config.baseUrl) {
154
+ let parsed;
155
+ try {
156
+ parsed = new URL(config.baseUrl);
157
+ } catch {
158
+ throw new GoPaySDKError(
159
+ `[GoPaySDK] config.baseUrl is not a valid URL: "${config.baseUrl}"`,
160
+ { errorCode: GoPayErrorCodes.INVALID_CONFIG }
161
+ );
162
+ }
163
+ const isLocalhost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "::1";
164
+ const isInsecureAllowed = (config.environment ?? "sandbox") === "sandbox" && isLocalhost;
165
+ if (parsed.protocol !== "https:" && !isInsecureAllowed) {
166
+ throw new GoPaySDKError(
167
+ `[GoPaySDK] config.baseUrl must use HTTPS. Got "${config.baseUrl}". Plain HTTP is only permitted for localhost in the sandbox environment.`,
168
+ { errorCode: GoPayErrorCodes.INVALID_CONFIG }
169
+ );
170
+ }
171
+ }
172
+ return rawBaseUrl;
173
+ }
174
+ function buildUrl(baseUrl, path) {
175
+ const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
176
+ const relative = path.startsWith("/") ? path.slice(1) : path;
177
+ return new URL(relative, base).toString();
178
+ }
179
+ var MAX_RETRIES = 2;
180
+ var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS", "PUT", "DELETE"]);
181
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
182
+ async function fetchWithRetry(url, init, timeoutMs) {
183
+ const method = (init?.method ?? "GET").toUpperCase();
184
+ const isIdempotent = IDEMPOTENT_METHODS.has(method);
185
+ let lastResponse;
186
+ let lastError;
187
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
188
+ if (attempt > 0) {
189
+ await sleep(2 ** (attempt - 1) * 200);
190
+ }
191
+ try {
192
+ const response = await fetch(
193
+ new Request(url, {
194
+ ...init,
195
+ signal: AbortSignal.timeout(timeoutMs)
196
+ })
197
+ );
198
+ if (response.status < 500) {
199
+ return response;
200
+ }
201
+ if (!isIdempotent) {
202
+ return response;
203
+ }
204
+ lastResponse = response;
205
+ } catch (err) {
206
+ if (err instanceof Error && err.name === "TimeoutError") {
207
+ throw err;
208
+ }
209
+ if (!isIdempotent) {
210
+ throw err;
211
+ }
212
+ lastError = err;
213
+ }
214
+ }
215
+ if (lastResponse !== void 0) {
216
+ return lastResponse;
217
+ }
218
+ throw lastError;
219
+ }
220
+ async function parseBody(response) {
221
+ const text = await response.text();
222
+ const contentType = response.headers.get("content-type") ?? "";
223
+ if (!contentType.includes("application/json")) {
224
+ return text;
225
+ }
226
+ try {
227
+ return JSON.parse(text);
228
+ } catch {
229
+ return text;
230
+ }
231
+ }
232
+ var AUTH_PATH = "/oauth2/token";
233
+ function createAuthHandler(deps) {
234
+ const reAuth = deps.reAuthAction ?? "Call authenticate() again.";
235
+ let refreshPromise = null;
236
+ async function injectAuth(headers, url, options) {
237
+ if (options?.headers) {
238
+ for (const [k, v] of Object.entries(options.headers)) {
239
+ headers.set(k, v);
240
+ }
241
+ }
242
+ if (url.includes(AUTH_PATH)) {
243
+ return;
244
+ }
245
+ if (headers.has("Authorization")) {
246
+ return;
247
+ }
248
+ if (options?.accessToken) {
249
+ headers.set("Authorization", `Bearer ${options.accessToken}`);
250
+ return;
251
+ }
252
+ if (deps.store.isExpiringSoon()) {
253
+ await refresh();
254
+ }
255
+ const tokens = deps.store.get();
256
+ if (!tokens) {
257
+ const shareableKey = deps.getShareableKey?.();
258
+ if (shareableKey) {
259
+ const clientId = deps.getClientId?.();
260
+ const credentials = clientId ? globalThis.btoa(`${clientId}:${shareableKey}`) : globalThis.btoa(`:${shareableKey}`);
261
+ headers.set("Authorization", `Basic ${credentials}`);
262
+ return;
263
+ }
264
+ deps.emitError(
265
+ new GoPaySDKError(
266
+ `[GoPaySDK] No access token available. ${reAuth}`,
267
+ { errorCode: GoPayErrorCodes.AUTH_TOKEN_MISSING }
268
+ )
269
+ );
270
+ }
271
+ headers.set("Authorization", `Bearer ${tokens.access_token}`);
272
+ }
273
+ async function fetchAndHandle401(url, init) {
274
+ const { getTimeoutMs, debugLogResponse, store, emitError } = deps;
275
+ const timeoutMs = getTimeoutMs();
276
+ let response = await fetchWithRetry(url, init, timeoutMs);
277
+ debugLogResponse(response);
278
+ if (response.status !== 401 || url.includes(AUTH_PATH)) {
279
+ return response;
280
+ }
281
+ await refresh();
282
+ const fresh = store.get();
283
+ if (!fresh) {
284
+ return response;
285
+ }
286
+ const retryHeaders = new Headers(init.headers);
287
+ retryHeaders.set("Authorization", `Bearer ${fresh.access_token}`);
288
+ response = await fetch(
289
+ new Request(url, {
290
+ ...init,
291
+ headers: retryHeaders,
292
+ signal: AbortSignal.timeout(timeoutMs)
293
+ })
294
+ );
295
+ debugLogResponse(response);
296
+ if (response.status === 401) {
297
+ store.clear();
298
+ emitError(
299
+ new GoPaySDKError(
300
+ "[GoPaySDK] Request unauthorized after token refresh. Check OAuth2 scopes.",
301
+ { errorCode: GoPayErrorCodes.AUTH_UNAUTHORIZED }
302
+ )
303
+ );
304
+ }
305
+ return response;
306
+ }
307
+ async function refresh() {
308
+ if (refreshPromise) {
309
+ return refreshPromise;
310
+ }
311
+ refreshPromise = doRefresh().finally(() => {
312
+ refreshPromise = null;
313
+ });
314
+ return refreshPromise;
315
+ }
316
+ async function doRefresh() {
317
+ const { store, baseUrl, emitError, getTimeoutMs } = deps;
318
+ const clientId = store.getClientId();
319
+ const clientSecret = store.getClientSecret();
320
+ const storedScope = store.getScope();
321
+ if (!clientId || !clientSecret || !storedScope) {
322
+ store.clear();
323
+ return emitError(
324
+ new GoPaySDKError(
325
+ `[GoPaySDK] Access token expired and no client credentials available. ${reAuth}`,
326
+ { errorCode: GoPayErrorCodes.AUTH_CREDENTIALS_MISSING }
327
+ )
328
+ );
329
+ }
330
+ try {
331
+ const url = buildUrl(baseUrl, AUTH_PATH);
332
+ const form = {
333
+ grant_type: "client_credentials",
334
+ scope: storedScope
335
+ };
336
+ const credentials = globalThis.btoa(`${clientId}:${clientSecret}`);
337
+ const headers = new Headers({
338
+ "Content-Type": "application/x-www-form-urlencoded",
339
+ Accept: "application/json",
340
+ Authorization: `Basic ${credentials}`
341
+ });
342
+ const response = await fetch(
343
+ new Request(url, {
344
+ method: "POST",
345
+ headers,
346
+ body: new URLSearchParams(form).toString(),
347
+ signal: AbortSignal.timeout(getTimeoutMs())
348
+ })
349
+ );
350
+ if (!response.ok) {
351
+ throw new GoPayHTTPError(
352
+ response.status,
353
+ await parseBody(response)
354
+ );
355
+ }
356
+ const body = await response.json();
357
+ const { access_token, expires_in } = body;
358
+ if (typeof access_token !== "string" || !access_token || typeof expires_in !== "number") {
359
+ throw new GoPaySDKError(
360
+ "[GoPaySDK] Invalid token response: missing required fields.",
361
+ { errorCode: GoPayErrorCodes.AUTH_INVALID_RESPONSE }
362
+ );
363
+ }
364
+ store.set({
365
+ access_token,
366
+ expires_in,
367
+ token_type: "bearer"
368
+ });
369
+ } catch (cause) {
370
+ store.clear();
371
+ emitError(
372
+ new GoPaySDKError(
373
+ `[GoPaySDK] Token refresh failed. ${reAuth}`,
374
+ { cause, errorCode: GoPayErrorCodes.AUTH_REFRESH_FAILED }
375
+ )
376
+ );
377
+ }
378
+ }
379
+ return { injectAuth, fetchAndHandle401, refresh };
380
+ }
381
+ function createTokenStore() {
382
+ let tokens = null;
383
+ let clientId = null;
384
+ let clientSecret = null;
385
+ let scope = null;
386
+ return {
387
+ get() {
388
+ return tokens;
389
+ },
390
+ getClientId() {
391
+ return clientId;
392
+ },
393
+ getClientSecret() {
394
+ return clientSecret;
395
+ },
396
+ getScope() {
397
+ return scope;
398
+ },
399
+ setClientSecret(id, secret, tokenScope) {
400
+ clientId = id;
401
+ clientSecret = secret;
402
+ scope = tokenScope ?? null;
403
+ tokens = null;
404
+ },
405
+ setClientId(id) {
406
+ clientId = id;
407
+ clientSecret = null;
408
+ scope = null;
409
+ tokens = null;
410
+ },
411
+ set(pair) {
412
+ tokens = { ...pair, issued_at: Date.now() };
413
+ },
414
+ clear() {
415
+ tokens = null;
416
+ clientId = null;
417
+ clientSecret = null;
418
+ scope = null;
419
+ },
420
+ hasAccessToken() {
421
+ return tokens !== null;
422
+ },
423
+ isExpiringSoon(bufferSeconds = 30) {
424
+ if (!tokens) {
425
+ return false;
426
+ }
427
+ const expiresAt = tokens.issued_at + tokens.expires_in * 1e3;
428
+ return Date.now() >= expiresAt - bufferSeconds * 1e3;
429
+ }
430
+ };
431
+ }
432
+ function createHttpClient(config, reAuthAction) {
433
+ const baseUrl = resolveBaseUrl(config);
434
+ const tokenStore = createTokenStore();
435
+ let shareableKey = config.shareableKey;
436
+ const auth = createAuthHandler({
437
+ store: tokenStore,
438
+ baseUrl,
439
+ emitError: (e) => emitError(e),
440
+ getTimeoutMs: () => timeoutMs(),
441
+ debugLogResponse: (r) => debugLogResponse(r),
442
+ getShareableKey: () => shareableKey,
443
+ getClientId: () => tokenStore.getClientId(),
444
+ reAuthAction
445
+ });
446
+ function timeoutMs() {
447
+ return config.requestTimeoutMs ?? 1e4;
448
+ }
449
+ function debugLogRequest(method, url) {
450
+ if (config.debugLoggingEnabled) {
451
+ console.debug("[GoPaySDK] \u2192", method, url);
452
+ }
453
+ }
454
+ function debugLogResponse(response) {
455
+ if (config.debugLoggingEnabled) {
456
+ console.debug("[GoPaySDK] \u2190", response.status, response.url);
457
+ }
458
+ }
459
+ function emitError(error) {
460
+ config.onError?.(error);
461
+ throw error;
462
+ }
463
+ function handleError(err) {
464
+ if (err instanceof GoPaySDKError) {
465
+ throw err;
466
+ }
467
+ if (err instanceof GoPayHTTPError) {
468
+ throw err;
469
+ }
470
+ if (err instanceof Error && err.name === "TimeoutError") {
471
+ return emitError(
472
+ new GoPaySDKError("[GoPaySDK] Request timed out.", {
473
+ errorCode: GoPayErrorCodes.NETWORK_TIMEOUT
474
+ })
475
+ );
476
+ }
477
+ if (err instanceof Error) {
478
+ return emitError(
479
+ new GoPaySDKError(`[GoPaySDK] Network error: ${err.message}`, {
480
+ cause: err,
481
+ errorCode: GoPayErrorCodes.NETWORK_ERROR
482
+ })
483
+ );
484
+ }
485
+ throw err;
486
+ }
487
+ async function throwIfNotOk(response) {
488
+ if (response.ok) {
489
+ return;
490
+ }
491
+ const body = await parseBody(response);
492
+ emitError(new GoPayHTTPError(response.status, body));
493
+ }
494
+ return {
495
+ baseUrl,
496
+ tokenStore,
497
+ setToken(pair) {
498
+ tokenStore.set(pair);
499
+ },
500
+ setClientId(clientId) {
501
+ tokenStore.setClientId(clientId);
502
+ },
503
+ setClientCredentials(clientId, clientSecret, scope) {
504
+ tokenStore.setClientSecret(clientId, clientSecret, scope);
505
+ },
506
+ getClientId() {
507
+ return tokenStore.getClientId();
508
+ },
509
+ getShareableKey() {
510
+ return shareableKey;
511
+ },
512
+ setShareableKey(key) {
513
+ shareableKey = key;
514
+ },
515
+ getClientCredentials() {
516
+ const clientId = tokenStore.getClientId();
517
+ const clientSecret = tokenStore.getClientSecret();
518
+ if (!clientId || !clientSecret) {
519
+ return null;
520
+ }
521
+ return { clientId, clientSecret };
522
+ },
523
+ isAuthenticated() {
524
+ return tokenStore.hasAccessToken();
525
+ },
526
+ getTokens() {
527
+ return tokenStore.get();
528
+ },
529
+ getEnvironment() {
530
+ return config.environment ?? "sandbox";
531
+ },
532
+ clearTokens() {
533
+ tokenStore.clear();
534
+ },
535
+ emitError,
536
+ async get(path, options) {
537
+ try {
538
+ const url = buildUrl(baseUrl, path);
539
+ const headers = new Headers({ Accept: "application/json" });
540
+ await auth.injectAuth(headers, url, options);
541
+ debugLogRequest("GET", url);
542
+ const response = await auth.fetchAndHandle401(url, {
543
+ method: "GET",
544
+ headers
545
+ });
546
+ await throwIfNotOk(response);
547
+ return await response.json();
548
+ } catch (err) {
549
+ return handleError(err);
550
+ }
551
+ },
552
+ async post(path, body, options) {
553
+ try {
554
+ const url = buildUrl(baseUrl, path);
555
+ const headers = new Headers({
556
+ Accept: "application/json",
557
+ "Content-Type": "application/json"
558
+ });
559
+ await auth.injectAuth(headers, url, options);
560
+ debugLogRequest("POST", url);
561
+ const response = await auth.fetchAndHandle401(url, {
562
+ method: "POST",
563
+ headers,
564
+ body: JSON.stringify(body)
565
+ });
566
+ await throwIfNotOk(response);
567
+ return await response.json();
568
+ } catch (err) {
569
+ return handleError(err);
570
+ }
571
+ },
572
+ async delete(path, options) {
573
+ try {
574
+ const url = buildUrl(baseUrl, path);
575
+ const headers = new Headers();
576
+ await auth.injectAuth(headers, url, options);
577
+ debugLogRequest("DELETE", url);
578
+ const response = await auth.fetchAndHandle401(url, {
579
+ method: "DELETE",
580
+ headers
581
+ });
582
+ await throwIfNotOk(response);
583
+ } catch (err) {
584
+ return handleError(err);
585
+ }
586
+ },
587
+ async postForm(path, form, options) {
588
+ try {
589
+ const url = buildUrl(baseUrl, path);
590
+ const headers = new Headers({
591
+ "Content-Type": "application/x-www-form-urlencoded",
592
+ Accept: "application/json"
593
+ });
594
+ if (options?.headers) {
595
+ for (const [k, v] of Object.entries(options.headers)) {
596
+ headers.set(k, v);
597
+ }
598
+ }
599
+ await auth.injectAuth(headers, url, options);
600
+ debugLogRequest("POST", url);
601
+ const bodyStr = new URLSearchParams(form).toString();
602
+ const response = await fetch(
603
+ new Request(url, {
604
+ method: "POST",
605
+ headers,
606
+ body: bodyStr,
607
+ signal: AbortSignal.timeout(timeoutMs())
608
+ })
609
+ );
610
+ debugLogResponse(response);
611
+ await throwIfNotOk(response);
612
+ return await response.json();
613
+ } catch (err) {
614
+ return handleError(err);
615
+ }
616
+ }
617
+ };
618
+ }
619
+ function requireNonEmptyString(value, field) {
620
+ if (typeof value !== "string" || !value.trim()) {
621
+ throw new GoPaySDKError(`[GoPaySDK] ${field} is required`, {
622
+ errorCode: GoPayErrorCodes.INVALID_ARGUMENT
623
+ });
624
+ }
625
+ return value.trim();
626
+ }
627
+ function assertHttpsOrigin(origin, errorPrefix) {
628
+ let parsed;
629
+ try {
630
+ parsed = new URL(origin);
631
+ } catch {
632
+ throw new GoPaySDKError(`${errorPrefix}: invalid origin "${origin}"`, {
633
+ errorCode: GoPayErrorCodes.INVALID_ARGUMENT
634
+ });
635
+ }
636
+ if (parsed.protocol !== "https:" || parsed.origin !== origin) {
637
+ throw new GoPaySDKError(
638
+ `${errorPrefix}: origin must be an https: origin. Got "${origin}"`,
639
+ { errorCode: GoPayErrorCodes.INVALID_ARGUMENT }
640
+ );
641
+ }
642
+ }
643
+
644
+ // src/modules/auth/auth.module.ts
645
+ function createAuthApi(client) {
646
+ return {
647
+ /**
648
+ * Authenticate the server-side SDK instance using client credentials.
649
+ *
650
+ * Stores the resulting access token internally. All subsequent API calls
651
+ * will attach the Bearer token automatically.
652
+ *
653
+ * The token is intentionally **not** returned — tokens must remain
654
+ * server-side only and must never be exposed to callers or logged.
655
+ * Use `isAuthenticated()` to confirm the SDK is ready.
656
+ *
657
+ * POST /oauth2/token (`client_credentials` grant)
658
+ *
659
+ * @throws {@link GoPaySDKError} with `AUTH_INVALID_RESPONSE` if the token
660
+ * response is missing required fields.
661
+ */
662
+ async authenticate(params) {
663
+ const form = {
664
+ grant_type: params.grant_type,
665
+ scope: params.scope
666
+ };
667
+ const raw = `${params.client_id}:${params.client_secret}`;
668
+ const headers = {
669
+ Authorization: `Basic ${globalThis.btoa(raw)}`
670
+ };
671
+ client.setClientCredentials(
672
+ params.client_id,
673
+ params.client_secret,
674
+ params.scope
675
+ );
676
+ const tokenPair = await client.postForm(
677
+ "/oauth2/token",
678
+ form,
679
+ { headers }
680
+ );
681
+ if (!tokenPair.access_token || tokenPair.expires_in === void 0) {
682
+ throw client.emitError(
683
+ new GoPaySDKError(
684
+ "[GoPaySDK] Invalid token response: missing required fields.",
685
+ { errorCode: GoPayErrorCodes.AUTH_INVALID_RESPONSE }
686
+ )
687
+ );
688
+ }
689
+ client.setToken({
690
+ access_token: tokenPair.access_token,
691
+ expires_in: tokenPair.expires_in,
692
+ token_type: "bearer"
693
+ });
694
+ },
695
+ /**
696
+ * Returns `true` if a token pair is currently stored (the SDK is
697
+ * authenticated). Does not check expiry — expired tokens are refreshed
698
+ * transparently on the next API call.
699
+ */
700
+ isAuthenticated() {
701
+ return client.isAuthenticated();
702
+ },
703
+ /**
704
+ * Clear all stored tokens and credentials.
705
+ * After calling this, all API calls will throw until the SDK is
706
+ * re-authenticated via `authenticate()`.
707
+ */
708
+ logout() {
709
+ client.clearTokens();
710
+ },
711
+ /**
712
+ * Store the shareable key on the SDK instance.
713
+ * Useful when the key is obtained separately from the SDK config
714
+ * (e.g. entered at runtime in a dev tool or fetched from an admin API).
715
+ */
716
+ setShareableKey(key) {
717
+ client.setShareableKey(key);
718
+ },
719
+ getBrowserKeys() {
720
+ const shareableKey = client.getShareableKey();
721
+ const clientId = client.getClientId();
722
+ if (!shareableKey || !clientId) {
723
+ throw client.emitError(
724
+ new GoPaySDKError(
725
+ "[GoPaySDK] getBrowserKeys() requires shareableKey in config and a prior authenticate() call.",
726
+ { errorCode: GoPayErrorCodes.AUTH_CREDENTIALS_MISSING }
727
+ )
728
+ );
729
+ }
730
+ return { shareable_key: shareableKey, client_id: clientId };
731
+ }
732
+ };
733
+ }
734
+
735
+ // src/modules/cards/cards.module.ts
736
+ function createCardsApi(client) {
737
+ return {
738
+ /**
739
+ * Retrieve details of a stored permanent card token.
740
+ * Requires the `card:read` OAuth2 scope.
741
+ *
742
+ * GET /cards/tokens/{card_id}
743
+ *
744
+ * @param cardId - Unique identifier of the stored card token
745
+ */
746
+ async getCardDetails(cardId) {
747
+ const cid = requireNonEmptyString(cardId, "cardId");
748
+ return client.get(`/cards/tokens/${cid}`);
749
+ },
750
+ /**
751
+ * Delete a stored permanent card token.
752
+ *
753
+ * DELETE /cards/tokens/{card_id}
754
+ *
755
+ * @param cardId - Unique identifier of the stored card token
756
+ */
757
+ async deleteCard(cardId) {
758
+ const cid = requireNonEmptyString(cardId, "cardId");
759
+ return client.delete(`/cards/tokens/${cid}`);
760
+ },
761
+ /**
762
+ * Tokenize an encrypted card payload received from the browser
763
+ * (via `mountCardForm` flow: `'return-payload'`).
764
+ * Requires the `card:write` OAuth2 scope.
765
+ *
766
+ * The `payload` is a JWE compact serialization string produced by the
767
+ * GoPay-hosted card form iframe. It must be forwarded from the browser
768
+ * to your server without modification.
769
+ *
770
+ * POST /cards/tokens
771
+ *
772
+ * @param payload - JWE compact serialization string from the card form
773
+ */
774
+ async tokenizeEncryptedCard(payload) {
775
+ const validPayload = requireNonEmptyString(payload, "payload");
776
+ const body = { payload: validPayload };
777
+ return client.post("/cards/tokens", body);
778
+ }
779
+ };
780
+ }
781
+
782
+ // src/modules/links/links.module.ts
783
+ function createLinksApi(client) {
784
+ return {
785
+ /**
786
+ * Create a payment link.
787
+ * Requires the `payment:write` OAuth2 scope.
788
+ *
789
+ * POST /eshops/{goid}/links
790
+ *
791
+ * @param goid - Merchant's GoPay ID (eshop identifier)
792
+ * @param params - Link creation parameters including payment data, expiry, and reusability
793
+ */
794
+ async createPaymentLink(goid, params) {
795
+ return client.post(`/eshops/${goid}/links`, params);
796
+ },
797
+ /**
798
+ * Link status.
799
+ * Requires the `payment:read` OAuth2 scope.
800
+ *
801
+ * GET /links/{link_id}
802
+ *
803
+ * @param linkId - Link ID returned by {@link createPaymentLink}
804
+ */
805
+ async linkStatus(linkId) {
806
+ const lid = requireNonEmptyString(linkId, "linkId");
807
+ return client.get(`/links/${lid}`);
808
+ },
809
+ /**
810
+ * Disable a link.
811
+ * Requires the `payment:write` OAuth2 scope.
812
+ *
813
+ * DELETE /links/{link_id}
814
+ *
815
+ * @param linkId - Link ID returned by {@link createPaymentLink}
816
+ */
817
+ async disableLink(linkId) {
818
+ const lid = requireNonEmptyString(linkId, "linkId");
819
+ return client.delete(`/links/${lid}`);
820
+ }
821
+ };
822
+ }
823
+
824
+ // src/modules/payments/payments.module.ts
825
+ function createPaymentsApi(client) {
826
+ return {
827
+ /**
828
+ * Retrieve the current status of an existing payment.
829
+ *
830
+ * GET /payments/{payment_id}
831
+ *
832
+ * @param paymentId - Payment session ID returned by {@link createPayment}
833
+ */
834
+ async getPaymentStatus(paymentId) {
835
+ const pid = requireNonEmptyString(paymentId, "paymentId");
836
+ return client.get(`/payments/${pid}`);
837
+ },
838
+ /**
839
+ * Create a new payment session.
840
+ *
841
+ * POST /eshops/{goid}/payments
842
+ *
843
+ * The response includes a `gw_url` field — **ignore it**. It exists only for
844
+ * backward compatibility with pre-SDK redirect-based integrations. This SDK's
845
+ * flow is always: create → charge (via card token, Apple Pay, or Google Pay).
846
+ *
847
+ * @param goid - Merchant's GoPay ID (eshop identifier)
848
+ * @param params - Payment creation parameters
849
+ */
850
+ async createPayment(goid, params) {
851
+ return client.post(
852
+ `/eshops/${goid}/payments`,
853
+ params
854
+ );
855
+ },
856
+ /**
857
+ * Charge a payment using a payment instrument.
858
+ *
859
+ * POST /payments/{payment_id}/charge
860
+ *
861
+ * @param paymentId - Payment session ID returned by {@link createPayment}
862
+ * @param params - Charge parameters including payment instrument details
863
+ */
864
+ async chargePayment(paymentId, params) {
865
+ const pid = requireNonEmptyString(paymentId, "paymentId");
866
+ return client.post(
867
+ `/payments/${pid}/charge`,
868
+ params
869
+ );
870
+ },
871
+ /**
872
+ * Retrieve the current state of a payment charge.
873
+ *
874
+ * GET /payments/{payment_id}/charge
875
+ *
876
+ * @param paymentId - Payment session ID returned by {@link createPayment}
877
+ */
878
+ async getChargeState(paymentId) {
879
+ const pid = requireNonEmptyString(paymentId, "paymentId");
880
+ return client.get(
881
+ `/payments/${pid}/charge`
882
+ );
883
+ },
884
+ /**
885
+ * Retrieve Google Pay configuration for this payment.
886
+ *
887
+ * GET /payments/{payment_id}/google-pay/info
888
+ *
889
+ * @param paymentId - Payment session ID
890
+ */
891
+ async getGooglePayInfo(paymentId) {
892
+ const pid = requireNonEmptyString(paymentId, "paymentId");
893
+ return client.get(
894
+ `/payments/${pid}/google-pay/info`
895
+ );
896
+ },
897
+ /**
898
+ * Retrieve Apple Pay configuration for this payment.
899
+ *
900
+ * GET /payments/{payment_id}/apple-pay/info
901
+ *
902
+ * @param paymentId - Payment session ID
903
+ */
904
+ async getApplePayInfo(paymentId) {
905
+ const pid = requireNonEmptyString(paymentId, "paymentId");
906
+ return client.get(
907
+ `/payments/${pid}/apple-pay/info`
908
+ );
909
+ },
910
+ /**
911
+ * Wire merchant validation onto an ApplePaySession and begin it.
912
+ * Handles the onvalidatemerchant callback via POST /payments/{payment_id}/apple-pay/validate.
913
+ *
914
+ * @param paymentId - Payment session ID
915
+ * @param session - ApplePaySession instance
916
+ * @param origin - Merchant origin (https:); defaults to current page origin
917
+ * @param callbacks - Optional lifecycle callbacks
918
+ */
919
+ startApplePaySession(paymentId, session, origin = globalThis.location?.origin ?? "", callbacks) {
920
+ const pid = requireNonEmptyString(paymentId, "paymentId");
921
+ if (origin) {
922
+ try {
923
+ assertHttpsOrigin(
924
+ origin,
925
+ "[GoPaySDK] startApplePaySession"
926
+ );
927
+ } catch (e) {
928
+ throw client.emitError(e);
929
+ }
930
+ }
931
+ session.onvalidatemerchant = (event) => {
932
+ const validationURL = event != null && typeof event === "object" && "validationURL" in event && typeof event.validationURL === "string" ? event.validationURL : void 0;
933
+ const headers = origin ? { Origin: origin } : {};
934
+ const body = validationURL ? { validationUrl: validationURL } : void 0;
935
+ client.post(
936
+ `/payments/${pid}/apple-pay/validate`,
937
+ body,
938
+ { headers }
939
+ ).then(
940
+ (merchantSession) => session.completeMerchantValidation(merchantSession)
941
+ ).catch(() => session.abort());
942
+ };
943
+ session.oncancel = (event) => {
944
+ callbacks?.oncancel?.(event);
945
+ };
946
+ session.begin();
947
+ },
948
+ /**
949
+ * Retrieve QR payment info for this payment.
950
+ * Returns recipient details and base64-encoded QR code image(s).
951
+ *
952
+ * GET /payments/{payment_id}/qr-payment/info
953
+ *
954
+ * @param paymentId - Payment session ID
955
+ * @param format - Image format of the QR code: 'png' (default) or 'svg'
956
+ */
957
+ async getQRPaymentInfo(paymentId, format) {
958
+ const pid = requireNonEmptyString(paymentId, "paymentId");
959
+ const path = format ? `/payments/${pid}/qr-payment/info?format=${format}` : `/payments/${pid}/qr-payment/info`;
960
+ return client.get(path);
961
+ },
962
+ /**
963
+ * Poll the charge state until a terminal outcome.
964
+ *
965
+ * Resolves on `SUCCEEDED`. Rejects with `CHARGE_FAILED` on `FAILED`,
966
+ * or `CHARGE_TIMEOUT` if the charge does not leave `REQUESTED`/
967
+ * `PROCESSING` within `initialTimeoutMs` (default 30 s).
968
+ *
969
+ * Use `options.onActionRequired` to handle 3DS redirects
970
+ * (e.g. redirect the customer or open a popup).
971
+ *
972
+ * @param paymentId - Payment session ID
973
+ * @param options - Polling configuration and callbacks
974
+ */
975
+ awaitChargeState(paymentId, options) {
976
+ const pid = requireNonEmptyString(paymentId, "paymentId");
977
+ return awaitCharge(
978
+ () => client.get(
979
+ `/payments/${pid}/charge`
980
+ ),
981
+ options
982
+ );
983
+ }
984
+ };
985
+ }
986
+
987
+ // src/modules/recurrences/recurrences.module.ts
988
+ function createRecurrencesApi(client) {
989
+ return {
990
+ /**
991
+ * Create a recurrence.
992
+ * Requires the `payment:write` OAuth2 scope.
993
+ *
994
+ * POST /eshops/{goid}/recurrences
995
+ *
996
+ * @param goid - Merchant's GoPay ID (eshop identifier)
997
+ * @param params - Recurrence creation parameters including type, schedule, and payment data
998
+ */
999
+ async createRecurrence(goid, params) {
1000
+ return client.post(
1001
+ `/eshops/${goid}/recurrences`,
1002
+ params
1003
+ );
1004
+ },
1005
+ /**
1006
+ * Recurrence status.
1007
+ * Requires the `payment:read` OAuth2 scope.
1008
+ *
1009
+ * GET /recurrences/{rec_id}
1010
+ *
1011
+ * @param recId - Recurrence ID returned by {@link createRecurrence}
1012
+ */
1013
+ async recurrenceStatus(recId) {
1014
+ const rid = requireNonEmptyString(recId, "recId");
1015
+ return client.get(`/recurrences/${rid}`);
1016
+ },
1017
+ /**
1018
+ * Stop a recurrence.
1019
+ * Requires the `payment:write` OAuth2 scope.
1020
+ *
1021
+ * DELETE /recurrences/{rec_id}
1022
+ *
1023
+ * @param recId - Recurrence ID returned by {@link createRecurrence}
1024
+ */
1025
+ async stopRecurrence(recId) {
1026
+ const rid = requireNonEmptyString(recId, "recId");
1027
+ return client.delete(`/recurrences/${rid}`);
1028
+ },
1029
+ /**
1030
+ * Start a recurrence.
1031
+ * Triggers the first charge of a recurrence that is in the `NEW` state.
1032
+ * Requires the `payment:write` OAuth2 scope.
1033
+ *
1034
+ * POST /recurrences/{rec_id}/start
1035
+ *
1036
+ * @param recId - Recurrence ID returned by {@link createRecurrence}
1037
+ * @param params - Optional payment overrides (amount, order_number, callback, etc.)
1038
+ */
1039
+ async startRecurrence(recId, params) {
1040
+ const rid = requireNonEmptyString(recId, "recId");
1041
+ return client.post(
1042
+ `/recurrences/${rid}/start`,
1043
+ params
1044
+ );
1045
+ },
1046
+ /**
1047
+ * Create a next payment for a recurrence.
1048
+ * Charges the next instalment for a recurrence that is already `STARTED`.
1049
+ * Requires the `payment:write` OAuth2 scope.
1050
+ *
1051
+ * POST /recurrences/{rec_id}/next
1052
+ *
1053
+ * @param recId - Recurrence ID returned by {@link createRecurrence}
1054
+ * @param params - Optional payment overrides (amount, order_number, callback, etc.)
1055
+ */
1056
+ async recurrenceNext(recId, params) {
1057
+ const rid = requireNonEmptyString(recId, "recId");
1058
+ return client.post(
1059
+ `/recurrences/${rid}/next`,
1060
+ params
1061
+ );
1062
+ }
1063
+ };
1064
+ }
1065
+
1066
+ // src/modules/refunds/refunds.module.ts
1067
+ function createRefundsApi(client) {
1068
+ return {
1069
+ /**
1070
+ * Refund a payment (fully or partially).
1071
+ * Requires the `payment:write` OAuth2 scope.
1072
+ *
1073
+ * POST /payments/{payment_id}/refunds
1074
+ *
1075
+ * @param paymentId - Payment session ID returned by {@link createPayment}
1076
+ * @param params - Refund parameters, including the amount in cents
1077
+ */
1078
+ async refundPayment(paymentId, params) {
1079
+ const pid = requireNonEmptyString(paymentId, "paymentId");
1080
+ return client.post(
1081
+ `/payments/${pid}/refunds`,
1082
+ params
1083
+ );
1084
+ },
1085
+ /**
1086
+ * List all refunds for a payment.
1087
+ * Requires the `payment:read` OAuth2 scope.
1088
+ *
1089
+ * GET /payments/{payment_id}/refunds
1090
+ *
1091
+ * @param paymentId - Payment session ID returned by {@link createPayment}
1092
+ */
1093
+ async listRefunds(paymentId) {
1094
+ const pid = requireNonEmptyString(paymentId, "paymentId");
1095
+ return client.get(`/payments/${pid}/refunds`);
1096
+ },
1097
+ /**
1098
+ * Retrieve details of a single refund.
1099
+ * Requires the `payment:read` OAuth2 scope.
1100
+ *
1101
+ * GET /refunds/{refund_id}
1102
+ *
1103
+ * @param refundId - Refund ID returned by {@link refundPayment}
1104
+ */
1105
+ async getRefund(refundId) {
1106
+ const rid = requireNonEmptyString(refundId, "refundId");
1107
+ return client.get(`/refunds/${rid}`);
1108
+ }
1109
+ };
1110
+ }
1111
+
1112
+ // src/version.ts
1113
+ var SDK_VERSION = "1.6.6";
1114
+
1115
+ // src/gopay-sdk.ts
1116
+ function createGoPaySDK(config = {}) {
1117
+ const client = createHttpClient(config);
1118
+ return {
1119
+ version: SDK_VERSION,
1120
+ ...createAuthApi(client),
1121
+ ...createPaymentsApi(client),
1122
+ ...createCardsApi(client),
1123
+ ...createRecurrencesApi(client),
1124
+ ...createRefundsApi(client),
1125
+ ...createLinksApi(client)
1126
+ };
1127
+ }
1128
+ export {
1129
+ GoPayErrorCodes,
1130
+ GoPayHTTPError,
1131
+ GoPaySDKError,
1132
+ SDK_VERSION,
1133
+ createGoPaySDK
1134
+ };
1135
+ //# sourceMappingURL=index.js.map