@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/CHANGELOG.md +441 -0
- package/README.md +633 -0
- package/dist/index.cjs +1166 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +303 -0
- package/dist/index.d.ts +303 -0
- package/dist/index.js +1135 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/config.ts +4 -0
- package/src/env.d.ts +1 -0
- package/src/errors.ts +6 -0
- package/src/gopay-sdk.ts +34 -0
- package/src/index.ts +12 -0
- package/src/modules/auth/auth.module.ts +105 -0
- package/src/modules/cards/cards.module.ts +55 -0
- package/src/modules/links/links.module.ts +51 -0
- package/src/modules/payments/payments.module.ts +244 -0
- package/src/modules/recurrences/recurrences.module.ts +100 -0
- package/src/modules/refunds/refunds.module.ts +55 -0
- package/src/types/generated.ts +1 -0
- package/src/types/index.ts +10 -0
- package/src/version.ts +1 -0
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
|