@tineon/t9n 0.1.7 → 0.1.9
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.d.ts +3 -0
- package/dist/index.js +125 -42
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -6,10 +6,12 @@ export declare class T9nCheckout {
|
|
|
6
6
|
private sessionId;
|
|
7
7
|
private intervalId?;
|
|
8
8
|
private statusPollId?;
|
|
9
|
+
private closeTimeoutId?;
|
|
9
10
|
private expiresAt?;
|
|
10
11
|
private isOpen;
|
|
11
12
|
private lastResultFailed;
|
|
12
13
|
private hasAttemptedConfirm;
|
|
14
|
+
private skipCloseMark;
|
|
13
15
|
private successNotified;
|
|
14
16
|
private failureNotified;
|
|
15
17
|
constructor(config: CheckoutConfig);
|
|
@@ -29,6 +31,7 @@ export declare class T9nCheckout {
|
|
|
29
31
|
private assertSecureConfig;
|
|
30
32
|
private applyButtonStyle;
|
|
31
33
|
private applyButtonTheme;
|
|
34
|
+
private scheduleAutoClose;
|
|
32
35
|
private normalizeStatus;
|
|
33
36
|
private markFailed;
|
|
34
37
|
private markClosed;
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export class T9nCheckout {
|
|
|
8
8
|
this.isOpen = false;
|
|
9
9
|
this.lastResultFailed = false;
|
|
10
10
|
this.hasAttemptedConfirm = false;
|
|
11
|
+
this.skipCloseMark = false;
|
|
11
12
|
this.successNotified = false;
|
|
12
13
|
this.failureNotified = false;
|
|
13
14
|
this.cfg = checkoutConfigSchema.parse(config);
|
|
@@ -73,16 +74,23 @@ export class T9nCheckout {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
close() {
|
|
77
|
+
if (this.closeTimeoutId) {
|
|
78
|
+
window.clearTimeout(this.closeTimeoutId);
|
|
79
|
+
this.closeTimeoutId = undefined;
|
|
80
|
+
}
|
|
76
81
|
if (this.intervalId)
|
|
77
82
|
window.clearInterval(this.intervalId);
|
|
78
83
|
if (this.statusPollId)
|
|
79
84
|
window.clearInterval(this.statusPollId);
|
|
80
|
-
if (this.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
if (!this.skipCloseMark) {
|
|
86
|
+
if (this.lastResultFailed && this.sessionId) {
|
|
87
|
+
void this.markFailed();
|
|
88
|
+
}
|
|
89
|
+
else if (!this.hasAttemptedConfirm && this.sessionId) {
|
|
90
|
+
void this.markClosed();
|
|
91
|
+
}
|
|
85
92
|
}
|
|
93
|
+
this.skipCloseMark = false;
|
|
86
94
|
this.modal?.close();
|
|
87
95
|
this.modal = undefined;
|
|
88
96
|
this.sessionId = "";
|
|
@@ -177,48 +185,95 @@ export class T9nCheckout {
|
|
|
177
185
|
}
|
|
178
186
|
async confirmPayment() {
|
|
179
187
|
this.hasAttemptedConfirm = true;
|
|
188
|
+
console.log("[T9N] confirmPayment: start", { sessionId: this.sessionId });
|
|
180
189
|
this.modal?.setConfirmPending(true);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
try {
|
|
191
|
+
const res = await this.fetchWithTimeout(`${this.getApiBaseUrl()}/api/merchant/checkout/sessions/${this.sessionId}/confirm-payment`, {
|
|
192
|
+
method: "POST",
|
|
193
|
+
headers: {
|
|
194
|
+
"Content-Type": "application/json",
|
|
195
|
+
"x-public-key": this.cfg.publicKey,
|
|
196
|
+
},
|
|
197
|
+
body: "{}",
|
|
198
|
+
});
|
|
199
|
+
if (!res.ok) {
|
|
200
|
+
console.log("[T9N] confirmPayment: non-ok response", { status: res.status, sessionId: this.sessionId });
|
|
201
|
+
this.modal?.setConfirmPending(false);
|
|
202
|
+
this.modal?.showResult("failed", "Verification failed. Please try again.");
|
|
203
|
+
this.lastResultFailed = true;
|
|
204
|
+
this.modal?.setConfirmLabel("Retry check");
|
|
205
|
+
this.emitStatus("failed");
|
|
206
|
+
this.emitFailOnce({ sessionId: this.sessionId || undefined, error: "confirm request failed" });
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
let payload = {};
|
|
210
|
+
try {
|
|
211
|
+
payload = (await res.json());
|
|
212
|
+
console.log("[T9N] confirmPayment: response payload", { payload, sessionId: this.sessionId });
|
|
213
|
+
}
|
|
214
|
+
catch (_) {
|
|
215
|
+
console.log("[T9N] confirmPayment: invalid json response", { sessionId: this.sessionId });
|
|
216
|
+
this.modal?.setConfirmPending(false);
|
|
217
|
+
this.modal?.showResult("failed", "Verification failed. Please try again.");
|
|
218
|
+
this.lastResultFailed = true;
|
|
219
|
+
this.modal?.setConfirmLabel("Retry check");
|
|
220
|
+
this.emitStatus("failed");
|
|
221
|
+
this.emitFailOnce({ sessionId: this.sessionId || undefined, error: "invalid confirm response" });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
190
224
|
this.modal?.setConfirmPending(false);
|
|
191
|
-
|
|
192
|
-
this.
|
|
193
|
-
this.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
225
|
+
const normalized = this.normalizeStatus(payload.status || "");
|
|
226
|
+
console.log("[T9N] confirmPayment: normalized status", { status: payload.status, normalized, sessionId: this.sessionId });
|
|
227
|
+
this.emitStatus(normalized);
|
|
228
|
+
if (normalized === "settled") {
|
|
229
|
+
console.log("[T9N] confirmPayment: showing success", { sessionId: this.sessionId });
|
|
230
|
+
this.modal?.setConfirmLabel("I have made the payment");
|
|
231
|
+
this.modal?.showResult("success", "Payment received successfully.");
|
|
232
|
+
this.lastResultFailed = false;
|
|
233
|
+
this.emitSuccessOnce({ sessionId: this.sessionId, status: payload.status || "settled" });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (normalized === "expired") {
|
|
237
|
+
console.log("[T9N] confirmPayment: showing expired", { sessionId: this.sessionId });
|
|
238
|
+
this.modal?.showResult("failed", "This session has expired.");
|
|
239
|
+
this.lastResultFailed = false;
|
|
240
|
+
this.emitFailOnce({ sessionId: this.sessionId, error: "checkout expired" });
|
|
241
|
+
this.scheduleAutoClose();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (normalized === "failed") {
|
|
245
|
+
console.log("[T9N] confirmPayment: showing failed", { sessionId: this.sessionId });
|
|
246
|
+
this.modal?.showResult("failed", "Payment failed. Please try again.");
|
|
247
|
+
this.lastResultFailed = true;
|
|
248
|
+
this.modal?.setConfirmLabel("Retry check");
|
|
249
|
+
this.emitFailOnce({ sessionId: this.sessionId || undefined, error: "checkout failed" });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (normalized === "closed") {
|
|
253
|
+
console.log("[T9N] confirmPayment: showing closed", { sessionId: this.sessionId });
|
|
254
|
+
this.modal?.showResult("failed", "Checkout was closed. Please try again.");
|
|
255
|
+
this.lastResultFailed = true;
|
|
256
|
+
this.modal?.setConfirmLabel("Retry check");
|
|
257
|
+
this.emitFailOnce({ sessionId: this.sessionId || undefined, error: "checkout closed" });
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
console.log("[T9N] confirmPayment: showing no-funds retry", { sessionId: this.sessionId });
|
|
206
261
|
this.modal?.showResult("failed", "No payment detected yet. Please try again.");
|
|
207
262
|
this.lastResultFailed = true;
|
|
208
263
|
this.modal?.setConfirmLabel("Retry check");
|
|
209
264
|
this.emitFailOnce({ sessionId: this.sessionId || undefined, error: "payment not detected" });
|
|
210
|
-
return;
|
|
211
265
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
this.modal?.
|
|
215
|
-
this.
|
|
216
|
-
this.emitSuccessOnce({ sessionId: this.sessionId, status: payload.status });
|
|
217
|
-
}
|
|
218
|
-
if (payload.status === "expired") {
|
|
219
|
-
this.modal?.showResult("failed", "This session has expired.");
|
|
266
|
+
catch (err) {
|
|
267
|
+
console.log("[T9N] confirmPayment: error", { error: err?.message || err, sessionId: this.sessionId });
|
|
268
|
+
this.modal?.setConfirmPending(false);
|
|
269
|
+
this.modal?.showResult("failed", "Verification failed. Please try again.");
|
|
220
270
|
this.lastResultFailed = true;
|
|
221
|
-
this.
|
|
271
|
+
this.modal?.setConfirmLabel("Retry check");
|
|
272
|
+
this.emitStatus("failed");
|
|
273
|
+
this.emitFailOnce({
|
|
274
|
+
sessionId: this.sessionId || undefined,
|
|
275
|
+
error: err?.message || "confirm request failed",
|
|
276
|
+
});
|
|
222
277
|
}
|
|
223
278
|
}
|
|
224
279
|
startTimer() {
|
|
@@ -228,8 +283,14 @@ export class T9nCheckout {
|
|
|
228
283
|
const ms = this.expiresAt.getTime() - Date.now();
|
|
229
284
|
if (ms <= 0) {
|
|
230
285
|
this.modal?.setTimer("00:00");
|
|
231
|
-
this.
|
|
232
|
-
|
|
286
|
+
if (this.intervalId)
|
|
287
|
+
window.clearInterval(this.intervalId);
|
|
288
|
+
if (this.statusPollId)
|
|
289
|
+
window.clearInterval(this.statusPollId);
|
|
290
|
+
this.modal?.showResult("failed", "This session has expired.");
|
|
291
|
+
this.lastResultFailed = false;
|
|
292
|
+
this.emitFailOnce({ sessionId: this.sessionId || undefined, error: "checkout expired" });
|
|
293
|
+
this.scheduleAutoClose();
|
|
233
294
|
return;
|
|
234
295
|
}
|
|
235
296
|
const minutes = Math.floor(ms / 60000)
|
|
@@ -255,8 +316,10 @@ export class T9nCheckout {
|
|
|
255
316
|
const payload = (await res.json());
|
|
256
317
|
if (payload.status) {
|
|
257
318
|
const normalized = this.normalizeStatus(payload.status);
|
|
319
|
+
console.log("[T9N] poll: status", { status: payload.status, normalized, sessionId: this.sessionId });
|
|
258
320
|
this.emitStatus(normalized);
|
|
259
321
|
if (normalized === "settled") {
|
|
322
|
+
console.log("[T9N] poll: showing success", { sessionId: this.sessionId });
|
|
260
323
|
this.modal?.showResult("success", "Payment received successfully.");
|
|
261
324
|
this.lastResultFailed = false;
|
|
262
325
|
if (this.intervalId)
|
|
@@ -267,6 +330,7 @@ export class T9nCheckout {
|
|
|
267
330
|
}
|
|
268
331
|
if (normalized === "failed") {
|
|
269
332
|
if (this.hasAttemptedConfirm) {
|
|
333
|
+
console.log("[T9N] poll: showing failed", { sessionId: this.sessionId });
|
|
270
334
|
this.modal?.showResult("failed", "No payment detected yet. Please try again.");
|
|
271
335
|
this.lastResultFailed = true;
|
|
272
336
|
this.emitFailOnce({ sessionId: this.sessionId, error: "checkout failed" });
|
|
@@ -274,6 +338,7 @@ export class T9nCheckout {
|
|
|
274
338
|
}
|
|
275
339
|
if (normalized === "pending_confirmation" || normalized === "awaiting_payment") {
|
|
276
340
|
if (this.hasAttemptedConfirm) {
|
|
341
|
+
console.log("[T9N] poll: showing pending no-funds", { sessionId: this.sessionId });
|
|
277
342
|
this.modal?.showResult("failed", "No payment detected yet. Please try again.");
|
|
278
343
|
this.lastResultFailed = true;
|
|
279
344
|
this.emitFailOnce({ sessionId: this.sessionId || undefined, error: "payment not detected" });
|
|
@@ -281,13 +346,15 @@ export class T9nCheckout {
|
|
|
281
346
|
}
|
|
282
347
|
}
|
|
283
348
|
if (payload.status === "expired") {
|
|
349
|
+
console.log("[T9N] poll: showing expired", { sessionId: this.sessionId });
|
|
284
350
|
this.modal?.showResult("failed", "This session has expired.");
|
|
285
|
-
this.lastResultFailed =
|
|
351
|
+
this.lastResultFailed = false;
|
|
286
352
|
if (this.intervalId)
|
|
287
353
|
window.clearInterval(this.intervalId);
|
|
288
354
|
if (this.statusPollId)
|
|
289
355
|
window.clearInterval(this.statusPollId);
|
|
290
356
|
this.emitFailOnce({ sessionId: this.sessionId, error: "checkout expired" });
|
|
357
|
+
this.scheduleAutoClose();
|
|
291
358
|
}
|
|
292
359
|
}
|
|
293
360
|
catch (_) {
|
|
@@ -399,6 +466,16 @@ export class T9nCheckout {
|
|
|
399
466
|
break;
|
|
400
467
|
}
|
|
401
468
|
}
|
|
469
|
+
scheduleAutoClose(delayMs = 1200) {
|
|
470
|
+
this.skipCloseMark = true;
|
|
471
|
+
if (this.closeTimeoutId) {
|
|
472
|
+
window.clearTimeout(this.closeTimeoutId);
|
|
473
|
+
}
|
|
474
|
+
this.closeTimeoutId = window.setTimeout(() => {
|
|
475
|
+
if (this.isOpen)
|
|
476
|
+
this.close();
|
|
477
|
+
}, delayMs);
|
|
478
|
+
}
|
|
402
479
|
normalizeStatus(value) {
|
|
403
480
|
switch (value) {
|
|
404
481
|
case "created":
|
|
@@ -406,6 +483,10 @@ export class T9nCheckout {
|
|
|
406
483
|
return "awaiting_payment";
|
|
407
484
|
case "awaiting_payment":
|
|
408
485
|
case "pending_confirmation":
|
|
486
|
+
return value;
|
|
487
|
+
case "pending":
|
|
488
|
+
case "processing":
|
|
489
|
+
return "pending_confirmation";
|
|
409
490
|
case "closed":
|
|
410
491
|
case "expired":
|
|
411
492
|
case "settled":
|
|
@@ -452,12 +533,14 @@ export class T9nCheckout {
|
|
|
452
533
|
if (this.successNotified)
|
|
453
534
|
return;
|
|
454
535
|
this.successNotified = true;
|
|
536
|
+
console.log("[T9N] onSuccess", payload);
|
|
455
537
|
this.cfg.hooks?.onSuccess?.(payload);
|
|
456
538
|
}
|
|
457
539
|
emitFailOnce(payload) {
|
|
458
540
|
if (this.successNotified || this.failureNotified)
|
|
459
541
|
return;
|
|
460
542
|
this.failureNotified = true;
|
|
543
|
+
console.log("[T9N] onFail", payload);
|
|
461
544
|
this.cfg.hooks?.onFail?.(payload);
|
|
462
545
|
}
|
|
463
546
|
getApiBaseUrl() {
|