@tickean/checkout-js 0.1.0
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/README.md +5 -0
- package/dist/index.d.mts +168 -0
- package/dist/index.d.ts +168 -0
- package/dist/index.js +398 -0
- package/dist/index.mjs +370 -0
- package/package.json +30 -0
package/README.md
ADDED
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
type TickeanErrorPayload = {
|
|
2
|
+
code: string;
|
|
3
|
+
message: string;
|
|
4
|
+
details?: Record<string, unknown>;
|
|
5
|
+
};
|
|
6
|
+
declare class TickeanError extends Error {
|
|
7
|
+
readonly code: string;
|
|
8
|
+
readonly details?: Record<string, unknown>;
|
|
9
|
+
readonly status?: number;
|
|
10
|
+
constructor(payload: TickeanErrorPayload, status?: number);
|
|
11
|
+
}
|
|
12
|
+
type CreateTickeanOptions = {
|
|
13
|
+
publishableKey: string;
|
|
14
|
+
apiBaseUrl?: string;
|
|
15
|
+
/** When true, uses an in-memory mock adapter (no network). */
|
|
16
|
+
demo?: boolean;
|
|
17
|
+
fetchImpl?: typeof fetch;
|
|
18
|
+
};
|
|
19
|
+
type CheckoutSession = {
|
|
20
|
+
sessionId: string;
|
|
21
|
+
sessionToken: string;
|
|
22
|
+
expiresAt: string;
|
|
23
|
+
event: PublicEvent;
|
|
24
|
+
capabilities: Record<string, boolean>;
|
|
25
|
+
};
|
|
26
|
+
type PublicShowOption = {
|
|
27
|
+
id: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
price: number;
|
|
31
|
+
currency?: string;
|
|
32
|
+
stock?: number;
|
|
33
|
+
maxPerPurchase?: number;
|
|
34
|
+
optionType?: string;
|
|
35
|
+
accessScope?: string;
|
|
36
|
+
coveredShowIds?: string[];
|
|
37
|
+
passIssuanceMode?: "PER_DAY" | "SINGLE_PASS";
|
|
38
|
+
catalogVisibility?: "PUBLIC" | "PROMO_GATED";
|
|
39
|
+
promotionNxM?: unknown;
|
|
40
|
+
quantityDiscount?: unknown;
|
|
41
|
+
status?: string;
|
|
42
|
+
};
|
|
43
|
+
type PublicShow = {
|
|
44
|
+
id: string;
|
|
45
|
+
title?: string;
|
|
46
|
+
date?: string;
|
|
47
|
+
endDate?: string;
|
|
48
|
+
showOptions: PublicShowOption[];
|
|
49
|
+
};
|
|
50
|
+
type PublicEvent = {
|
|
51
|
+
id: string;
|
|
52
|
+
slug: string;
|
|
53
|
+
title: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
images?: unknown[];
|
|
56
|
+
location?: unknown;
|
|
57
|
+
availablePaymentMethods?: string[];
|
|
58
|
+
organization?: {
|
|
59
|
+
id?: string;
|
|
60
|
+
slug?: string;
|
|
61
|
+
name?: string;
|
|
62
|
+
logo?: string | null;
|
|
63
|
+
} | null;
|
|
64
|
+
shows: PublicShow[];
|
|
65
|
+
};
|
|
66
|
+
type CartItem = {
|
|
67
|
+
showOptionId: string;
|
|
68
|
+
amount: number;
|
|
69
|
+
};
|
|
70
|
+
type QuoteResult = {
|
|
71
|
+
valid: boolean;
|
|
72
|
+
totalPrice: number;
|
|
73
|
+
pricingBreakdown?: unknown;
|
|
74
|
+
discountCode?: unknown;
|
|
75
|
+
unlockedShowOptionIds?: string[];
|
|
76
|
+
unlockedShowOptions?: PublicShowOption[];
|
|
77
|
+
};
|
|
78
|
+
type Buyer = {
|
|
79
|
+
id: string;
|
|
80
|
+
phone: string;
|
|
81
|
+
name?: string;
|
|
82
|
+
email?: string;
|
|
83
|
+
};
|
|
84
|
+
type PurchaseResult = {
|
|
85
|
+
purchase: {
|
|
86
|
+
id: string;
|
|
87
|
+
status: string;
|
|
88
|
+
totalPrice: number;
|
|
89
|
+
currency: string;
|
|
90
|
+
shoppingCartReference: string;
|
|
91
|
+
paymentMethod?: string;
|
|
92
|
+
};
|
|
93
|
+
shoppingCartReference: string;
|
|
94
|
+
cartSessionToken: string;
|
|
95
|
+
};
|
|
96
|
+
type PaymentResult = {
|
|
97
|
+
id: string;
|
|
98
|
+
paymentStatus?: string;
|
|
99
|
+
paymentMethod?: string;
|
|
100
|
+
paymentInstructions?: unknown;
|
|
101
|
+
redirectUrl?: string;
|
|
102
|
+
initPoint?: string;
|
|
103
|
+
returnUrl?: string | null;
|
|
104
|
+
stripe?: unknown;
|
|
105
|
+
fintocWidget?: unknown;
|
|
106
|
+
dlocalGo?: unknown;
|
|
107
|
+
airwallex?: unknown;
|
|
108
|
+
};
|
|
109
|
+
type PaymentStatusResult = {
|
|
110
|
+
status: string;
|
|
111
|
+
purchase?: PurchaseResult["purchase"] | null;
|
|
112
|
+
};
|
|
113
|
+
interface CheckoutTransport {
|
|
114
|
+
request<T>(path: string, init: {
|
|
115
|
+
method?: string;
|
|
116
|
+
body?: unknown;
|
|
117
|
+
sessionToken?: string | null;
|
|
118
|
+
}): Promise<T>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type TickeanClient = ReturnType<typeof createTickean>;
|
|
122
|
+
declare function createTickean(options: CreateTickeanOptions): {
|
|
123
|
+
readonly session: CheckoutSession | null;
|
|
124
|
+
createSession(params: {
|
|
125
|
+
eventSlug: string;
|
|
126
|
+
returnUrl?: string;
|
|
127
|
+
}): Promise<CheckoutSession>;
|
|
128
|
+
getCatalog(): Promise<PublicEvent>;
|
|
129
|
+
quote(params: {
|
|
130
|
+
items: CartItem[];
|
|
131
|
+
discountCode?: string;
|
|
132
|
+
showId?: string;
|
|
133
|
+
}): Promise<QuoteResult>;
|
|
134
|
+
sendOtp(params: {
|
|
135
|
+
phone: string;
|
|
136
|
+
channel?: string;
|
|
137
|
+
}): Promise<unknown>;
|
|
138
|
+
verifyOtp(params: {
|
|
139
|
+
phone: string;
|
|
140
|
+
code: string;
|
|
141
|
+
name?: string;
|
|
142
|
+
email?: string;
|
|
143
|
+
}): Promise<unknown>;
|
|
144
|
+
createPurchase(params: {
|
|
145
|
+
items: CartItem[];
|
|
146
|
+
paymentMethod: string;
|
|
147
|
+
currency: string;
|
|
148
|
+
showId?: string;
|
|
149
|
+
discountCode?: string;
|
|
150
|
+
expectedTotal?: number;
|
|
151
|
+
shoppingCartReference?: string;
|
|
152
|
+
idempotencyKey?: string;
|
|
153
|
+
}): Promise<PurchaseResult>;
|
|
154
|
+
createPayment(params: {
|
|
155
|
+
orderId: string;
|
|
156
|
+
paymentMethod: string;
|
|
157
|
+
currency: string;
|
|
158
|
+
amount: number;
|
|
159
|
+
}): Promise<PaymentResult>;
|
|
160
|
+
getPaymentStatus(): Promise<PaymentStatusResult>;
|
|
161
|
+
watchPayment(options?: {
|
|
162
|
+
intervalMs?: number;
|
|
163
|
+
timeoutMs?: number;
|
|
164
|
+
signal?: AbortSignal;
|
|
165
|
+
}): Promise<PaymentStatusResult>;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export { type Buyer, type CartItem, type CheckoutSession, type CheckoutTransport, type CreateTickeanOptions, type PaymentResult, type PaymentStatusResult, type PublicEvent, type PublicShow, type PublicShowOption, type PurchaseResult, type QuoteResult, type TickeanClient, TickeanError, type TickeanErrorPayload, createTickean };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
type TickeanErrorPayload = {
|
|
2
|
+
code: string;
|
|
3
|
+
message: string;
|
|
4
|
+
details?: Record<string, unknown>;
|
|
5
|
+
};
|
|
6
|
+
declare class TickeanError extends Error {
|
|
7
|
+
readonly code: string;
|
|
8
|
+
readonly details?: Record<string, unknown>;
|
|
9
|
+
readonly status?: number;
|
|
10
|
+
constructor(payload: TickeanErrorPayload, status?: number);
|
|
11
|
+
}
|
|
12
|
+
type CreateTickeanOptions = {
|
|
13
|
+
publishableKey: string;
|
|
14
|
+
apiBaseUrl?: string;
|
|
15
|
+
/** When true, uses an in-memory mock adapter (no network). */
|
|
16
|
+
demo?: boolean;
|
|
17
|
+
fetchImpl?: typeof fetch;
|
|
18
|
+
};
|
|
19
|
+
type CheckoutSession = {
|
|
20
|
+
sessionId: string;
|
|
21
|
+
sessionToken: string;
|
|
22
|
+
expiresAt: string;
|
|
23
|
+
event: PublicEvent;
|
|
24
|
+
capabilities: Record<string, boolean>;
|
|
25
|
+
};
|
|
26
|
+
type PublicShowOption = {
|
|
27
|
+
id: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
price: number;
|
|
31
|
+
currency?: string;
|
|
32
|
+
stock?: number;
|
|
33
|
+
maxPerPurchase?: number;
|
|
34
|
+
optionType?: string;
|
|
35
|
+
accessScope?: string;
|
|
36
|
+
coveredShowIds?: string[];
|
|
37
|
+
passIssuanceMode?: "PER_DAY" | "SINGLE_PASS";
|
|
38
|
+
catalogVisibility?: "PUBLIC" | "PROMO_GATED";
|
|
39
|
+
promotionNxM?: unknown;
|
|
40
|
+
quantityDiscount?: unknown;
|
|
41
|
+
status?: string;
|
|
42
|
+
};
|
|
43
|
+
type PublicShow = {
|
|
44
|
+
id: string;
|
|
45
|
+
title?: string;
|
|
46
|
+
date?: string;
|
|
47
|
+
endDate?: string;
|
|
48
|
+
showOptions: PublicShowOption[];
|
|
49
|
+
};
|
|
50
|
+
type PublicEvent = {
|
|
51
|
+
id: string;
|
|
52
|
+
slug: string;
|
|
53
|
+
title: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
images?: unknown[];
|
|
56
|
+
location?: unknown;
|
|
57
|
+
availablePaymentMethods?: string[];
|
|
58
|
+
organization?: {
|
|
59
|
+
id?: string;
|
|
60
|
+
slug?: string;
|
|
61
|
+
name?: string;
|
|
62
|
+
logo?: string | null;
|
|
63
|
+
} | null;
|
|
64
|
+
shows: PublicShow[];
|
|
65
|
+
};
|
|
66
|
+
type CartItem = {
|
|
67
|
+
showOptionId: string;
|
|
68
|
+
amount: number;
|
|
69
|
+
};
|
|
70
|
+
type QuoteResult = {
|
|
71
|
+
valid: boolean;
|
|
72
|
+
totalPrice: number;
|
|
73
|
+
pricingBreakdown?: unknown;
|
|
74
|
+
discountCode?: unknown;
|
|
75
|
+
unlockedShowOptionIds?: string[];
|
|
76
|
+
unlockedShowOptions?: PublicShowOption[];
|
|
77
|
+
};
|
|
78
|
+
type Buyer = {
|
|
79
|
+
id: string;
|
|
80
|
+
phone: string;
|
|
81
|
+
name?: string;
|
|
82
|
+
email?: string;
|
|
83
|
+
};
|
|
84
|
+
type PurchaseResult = {
|
|
85
|
+
purchase: {
|
|
86
|
+
id: string;
|
|
87
|
+
status: string;
|
|
88
|
+
totalPrice: number;
|
|
89
|
+
currency: string;
|
|
90
|
+
shoppingCartReference: string;
|
|
91
|
+
paymentMethod?: string;
|
|
92
|
+
};
|
|
93
|
+
shoppingCartReference: string;
|
|
94
|
+
cartSessionToken: string;
|
|
95
|
+
};
|
|
96
|
+
type PaymentResult = {
|
|
97
|
+
id: string;
|
|
98
|
+
paymentStatus?: string;
|
|
99
|
+
paymentMethod?: string;
|
|
100
|
+
paymentInstructions?: unknown;
|
|
101
|
+
redirectUrl?: string;
|
|
102
|
+
initPoint?: string;
|
|
103
|
+
returnUrl?: string | null;
|
|
104
|
+
stripe?: unknown;
|
|
105
|
+
fintocWidget?: unknown;
|
|
106
|
+
dlocalGo?: unknown;
|
|
107
|
+
airwallex?: unknown;
|
|
108
|
+
};
|
|
109
|
+
type PaymentStatusResult = {
|
|
110
|
+
status: string;
|
|
111
|
+
purchase?: PurchaseResult["purchase"] | null;
|
|
112
|
+
};
|
|
113
|
+
interface CheckoutTransport {
|
|
114
|
+
request<T>(path: string, init: {
|
|
115
|
+
method?: string;
|
|
116
|
+
body?: unknown;
|
|
117
|
+
sessionToken?: string | null;
|
|
118
|
+
}): Promise<T>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type TickeanClient = ReturnType<typeof createTickean>;
|
|
122
|
+
declare function createTickean(options: CreateTickeanOptions): {
|
|
123
|
+
readonly session: CheckoutSession | null;
|
|
124
|
+
createSession(params: {
|
|
125
|
+
eventSlug: string;
|
|
126
|
+
returnUrl?: string;
|
|
127
|
+
}): Promise<CheckoutSession>;
|
|
128
|
+
getCatalog(): Promise<PublicEvent>;
|
|
129
|
+
quote(params: {
|
|
130
|
+
items: CartItem[];
|
|
131
|
+
discountCode?: string;
|
|
132
|
+
showId?: string;
|
|
133
|
+
}): Promise<QuoteResult>;
|
|
134
|
+
sendOtp(params: {
|
|
135
|
+
phone: string;
|
|
136
|
+
channel?: string;
|
|
137
|
+
}): Promise<unknown>;
|
|
138
|
+
verifyOtp(params: {
|
|
139
|
+
phone: string;
|
|
140
|
+
code: string;
|
|
141
|
+
name?: string;
|
|
142
|
+
email?: string;
|
|
143
|
+
}): Promise<unknown>;
|
|
144
|
+
createPurchase(params: {
|
|
145
|
+
items: CartItem[];
|
|
146
|
+
paymentMethod: string;
|
|
147
|
+
currency: string;
|
|
148
|
+
showId?: string;
|
|
149
|
+
discountCode?: string;
|
|
150
|
+
expectedTotal?: number;
|
|
151
|
+
shoppingCartReference?: string;
|
|
152
|
+
idempotencyKey?: string;
|
|
153
|
+
}): Promise<PurchaseResult>;
|
|
154
|
+
createPayment(params: {
|
|
155
|
+
orderId: string;
|
|
156
|
+
paymentMethod: string;
|
|
157
|
+
currency: string;
|
|
158
|
+
amount: number;
|
|
159
|
+
}): Promise<PaymentResult>;
|
|
160
|
+
getPaymentStatus(): Promise<PaymentStatusResult>;
|
|
161
|
+
watchPayment(options?: {
|
|
162
|
+
intervalMs?: number;
|
|
163
|
+
timeoutMs?: number;
|
|
164
|
+
signal?: AbortSignal;
|
|
165
|
+
}): Promise<PaymentStatusResult>;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export { type Buyer, type CartItem, type CheckoutSession, type CheckoutTransport, type CreateTickeanOptions, type PaymentResult, type PaymentStatusResult, type PublicEvent, type PublicShow, type PublicShowOption, type PurchaseResult, type QuoteResult, type TickeanClient, TickeanError, type TickeanErrorPayload, createTickean };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
TickeanError: () => TickeanError,
|
|
24
|
+
createTickean: () => createTickean
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/demo.ts
|
|
29
|
+
var demoEvent = {
|
|
30
|
+
id: "evt_demo",
|
|
31
|
+
slug: "demo-festival",
|
|
32
|
+
title: "Demo Festival",
|
|
33
|
+
description: "Sample multi-day festival for local SDK demos.",
|
|
34
|
+
availablePaymentMethods: ["TRANSFER", "MERCADOPAGO"],
|
|
35
|
+
organization: {
|
|
36
|
+
id: "org_demo",
|
|
37
|
+
slug: "demo-org",
|
|
38
|
+
name: "Demo Organizer",
|
|
39
|
+
logo: null
|
|
40
|
+
},
|
|
41
|
+
shows: [
|
|
42
|
+
{
|
|
43
|
+
id: "show_sat",
|
|
44
|
+
title: "S\xE1bado",
|
|
45
|
+
date: new Date(Date.now() + 7 * 864e5).toISOString(),
|
|
46
|
+
showOptions: [
|
|
47
|
+
{
|
|
48
|
+
id: "opt_day",
|
|
49
|
+
name: "Entrada general",
|
|
50
|
+
price: 15e3,
|
|
51
|
+
currency: "ARS",
|
|
52
|
+
stock: 100,
|
|
53
|
+
maxPerPurchase: 6,
|
|
54
|
+
optionType: "TICKET",
|
|
55
|
+
accessScope: "SINGLE_SHOW",
|
|
56
|
+
catalogVisibility: "PUBLIC",
|
|
57
|
+
passIssuanceMode: "PER_DAY"
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "show_sun",
|
|
63
|
+
title: "Domingo",
|
|
64
|
+
date: new Date(Date.now() + 8 * 864e5).toISOString(),
|
|
65
|
+
showOptions: [
|
|
66
|
+
{
|
|
67
|
+
id: "opt_pass",
|
|
68
|
+
name: "Abono 2 d\xEDas",
|
|
69
|
+
price: 25e3,
|
|
70
|
+
currency: "ARS",
|
|
71
|
+
stock: 50,
|
|
72
|
+
maxPerPurchase: 4,
|
|
73
|
+
optionType: "TICKET",
|
|
74
|
+
accessScope: "ALL_EVENT_SHOWS",
|
|
75
|
+
coveredShowIds: ["show_sat", "show_sun"],
|
|
76
|
+
passIssuanceMode: "SINGLE_PASS",
|
|
77
|
+
catalogVisibility: "PUBLIC"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "opt_gated",
|
|
81
|
+
name: "Promo 2x1 (c\xF3digo)",
|
|
82
|
+
price: 15e3,
|
|
83
|
+
currency: "ARS",
|
|
84
|
+
stock: 30,
|
|
85
|
+
maxPerPurchase: 4,
|
|
86
|
+
optionType: "TICKET",
|
|
87
|
+
accessScope: "SINGLE_SHOW",
|
|
88
|
+
catalogVisibility: "PROMO_GATED",
|
|
89
|
+
promotionNxM: { enabled: true, buyQty: 2, payQty: 1 }
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
};
|
|
95
|
+
function createDemoTransport() {
|
|
96
|
+
let sessionToken = "demo_session_token";
|
|
97
|
+
let buyer = null;
|
|
98
|
+
let unlocked = [];
|
|
99
|
+
let purchaseId = "purchase_demo";
|
|
100
|
+
let cartRef = "cart_demo";
|
|
101
|
+
return {
|
|
102
|
+
async request(path, init) {
|
|
103
|
+
if (path === "/v1/checkout/sessions" && init.method === "POST") {
|
|
104
|
+
sessionToken = `demo_${Date.now()}`;
|
|
105
|
+
return {
|
|
106
|
+
sessionId: "sess_demo",
|
|
107
|
+
sessionToken,
|
|
108
|
+
expiresAt: new Date(Date.now() + 36e5).toISOString(),
|
|
109
|
+
event: {
|
|
110
|
+
...demoEvent,
|
|
111
|
+
shows: demoEvent.shows.map((show) => ({
|
|
112
|
+
...show,
|
|
113
|
+
showOptions: show.showOptions.filter(
|
|
114
|
+
(o) => o.catalogVisibility !== "PROMO_GATED"
|
|
115
|
+
)
|
|
116
|
+
}))
|
|
117
|
+
},
|
|
118
|
+
capabilities: {
|
|
119
|
+
tickets: true,
|
|
120
|
+
discounts: true,
|
|
121
|
+
transfer: true,
|
|
122
|
+
onlinePayments: true
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (path === "/v1/checkout/catalog") {
|
|
127
|
+
return {
|
|
128
|
+
...demoEvent,
|
|
129
|
+
shows: demoEvent.shows.map((show) => ({
|
|
130
|
+
...show,
|
|
131
|
+
showOptions: [
|
|
132
|
+
...show.showOptions.filter(
|
|
133
|
+
(o) => o.catalogVisibility !== "PROMO_GATED"
|
|
134
|
+
),
|
|
135
|
+
...unlocked.filter(
|
|
136
|
+
(u) => show.showOptions.some((o) => o.id === u.id)
|
|
137
|
+
)
|
|
138
|
+
]
|
|
139
|
+
}))
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (path === "/v1/checkout/quote" && init.method === "POST") {
|
|
143
|
+
const body = init.body;
|
|
144
|
+
if (body.discountCode?.toUpperCase() === "DEMO2X1") {
|
|
145
|
+
unlocked = demoEvent.shows.flatMap((s) => s.showOptions).filter((o) => o.catalogVisibility === "PROMO_GATED");
|
|
146
|
+
}
|
|
147
|
+
const allOptions = demoEvent.shows.flatMap((s) => s.showOptions);
|
|
148
|
+
const total = body.items.reduce((sum, item) => {
|
|
149
|
+
const opt = allOptions.find((o) => o.id === item.showOptionId);
|
|
150
|
+
return sum + Number(opt?.price || 0) * item.amount;
|
|
151
|
+
}, 0);
|
|
152
|
+
return {
|
|
153
|
+
valid: true,
|
|
154
|
+
totalPrice: total,
|
|
155
|
+
pricingBreakdown: { subtotal: total },
|
|
156
|
+
unlockedShowOptionIds: unlocked.map((o) => o.id),
|
|
157
|
+
unlockedShowOptions: unlocked
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (path === "/v1/checkout/otp/send") {
|
|
161
|
+
return { sent: true };
|
|
162
|
+
}
|
|
163
|
+
if (path === "/v1/checkout/otp/verify") {
|
|
164
|
+
const body = init.body;
|
|
165
|
+
buyer = {
|
|
166
|
+
id: "buyer_demo",
|
|
167
|
+
phone: body.phone,
|
|
168
|
+
name: body.name || "Demo Buyer",
|
|
169
|
+
email: body.email
|
|
170
|
+
};
|
|
171
|
+
return { verified: true, buyer };
|
|
172
|
+
}
|
|
173
|
+
if (path === "/v1/checkout/purchases") {
|
|
174
|
+
if (!buyer) {
|
|
175
|
+
throw Object.assign(new Error("OTP required"), {
|
|
176
|
+
code: "checkout_otp_required"
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
const body = init.body;
|
|
180
|
+
const allOptions = demoEvent.shows.flatMap((s) => s.showOptions);
|
|
181
|
+
const total = body.items.reduce((sum, item) => {
|
|
182
|
+
const opt = allOptions.find((o) => o.id === item.showOptionId);
|
|
183
|
+
return sum + Number(opt?.price || 0) * item.amount;
|
|
184
|
+
}, 0);
|
|
185
|
+
purchaseId = `purchase_${Date.now()}`;
|
|
186
|
+
cartRef = `cart_${Date.now()}`;
|
|
187
|
+
return {
|
|
188
|
+
purchase: {
|
|
189
|
+
id: purchaseId,
|
|
190
|
+
status: "PENDING",
|
|
191
|
+
totalPrice: total,
|
|
192
|
+
currency: body.currency,
|
|
193
|
+
shoppingCartReference: cartRef,
|
|
194
|
+
paymentMethod: body.paymentMethod
|
|
195
|
+
},
|
|
196
|
+
shoppingCartReference: cartRef,
|
|
197
|
+
cartSessionToken: "demo_cart_token"
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (path === "/v1/checkout/payments") {
|
|
201
|
+
return {
|
|
202
|
+
id: `pay_${Date.now()}`,
|
|
203
|
+
paymentStatus: "PENDING",
|
|
204
|
+
paymentMethod: init.body?.paymentMethod,
|
|
205
|
+
paymentInstructions: {
|
|
206
|
+
alias: "tickean.demo",
|
|
207
|
+
cvu: "0000003100010000000001",
|
|
208
|
+
amount: init.body?.amount
|
|
209
|
+
},
|
|
210
|
+
redirectUrl: void 0,
|
|
211
|
+
returnUrl: null
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (path === "/v1/checkout/payments/status") {
|
|
215
|
+
return {
|
|
216
|
+
status: "PENDING",
|
|
217
|
+
purchase: {
|
|
218
|
+
id: purchaseId,
|
|
219
|
+
status: "PENDING",
|
|
220
|
+
totalPrice: 0,
|
|
221
|
+
currency: "ARS",
|
|
222
|
+
shoppingCartReference: cartRef
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
throw new Error(`Demo transport: unhandled ${init.method || "GET"} ${path}`);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/types.ts
|
|
232
|
+
var TickeanError = class extends Error {
|
|
233
|
+
constructor(payload, status) {
|
|
234
|
+
super(payload.message);
|
|
235
|
+
this.name = "TickeanError";
|
|
236
|
+
this.code = payload.code;
|
|
237
|
+
this.details = payload.details;
|
|
238
|
+
this.status = status;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// src/http.ts
|
|
243
|
+
function createHttpTransport(options) {
|
|
244
|
+
const fetchImpl = options.fetchImpl || fetch;
|
|
245
|
+
return {
|
|
246
|
+
async request(path, init) {
|
|
247
|
+
const headers = {
|
|
248
|
+
"Content-Type": "application/json",
|
|
249
|
+
"X-Tickean-Key": options.publishableKey
|
|
250
|
+
};
|
|
251
|
+
if (init.sessionToken) {
|
|
252
|
+
headers["X-Tickean-Checkout-Session"] = init.sessionToken;
|
|
253
|
+
}
|
|
254
|
+
const response = await fetchImpl(
|
|
255
|
+
`${options.apiBaseUrl.replace(/\/$/, "")}${path}`,
|
|
256
|
+
{
|
|
257
|
+
method: init.method || "GET",
|
|
258
|
+
headers,
|
|
259
|
+
body: init.body ? JSON.stringify(init.body) : void 0,
|
|
260
|
+
credentials: "omit"
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
const json = await response.json().catch(() => ({}));
|
|
264
|
+
if (!response.ok) {
|
|
265
|
+
const err = json?.error || {};
|
|
266
|
+
throw new TickeanError(
|
|
267
|
+
{
|
|
268
|
+
code: err.code || "checkout_request_failed",
|
|
269
|
+
message: err.message || response.statusText || "Request failed",
|
|
270
|
+
details: err.details
|
|
271
|
+
},
|
|
272
|
+
response.status
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
return json;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/index.ts
|
|
281
|
+
function createTickean(options) {
|
|
282
|
+
if (!options.publishableKey && !options.demo) {
|
|
283
|
+
throw new TickeanError({
|
|
284
|
+
code: "checkout_key_required",
|
|
285
|
+
message: "publishableKey is required unless demo mode is enabled"
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
const transport = options.demo ? createDemoTransport() : createHttpTransport({
|
|
289
|
+
publishableKey: options.publishableKey,
|
|
290
|
+
apiBaseUrl: options.apiBaseUrl || "https://api.tickean.com",
|
|
291
|
+
fetchImpl: options.fetchImpl
|
|
292
|
+
});
|
|
293
|
+
let session = null;
|
|
294
|
+
const requireSession = () => {
|
|
295
|
+
if (!session?.sessionToken) {
|
|
296
|
+
throw new TickeanError({
|
|
297
|
+
code: "checkout_session_required",
|
|
298
|
+
message: "Call createSession() before using checkout methods"
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
return session;
|
|
302
|
+
};
|
|
303
|
+
return {
|
|
304
|
+
get session() {
|
|
305
|
+
return session;
|
|
306
|
+
},
|
|
307
|
+
async createSession(params) {
|
|
308
|
+
session = await transport.request("/v1/checkout/sessions", {
|
|
309
|
+
method: "POST",
|
|
310
|
+
body: params
|
|
311
|
+
});
|
|
312
|
+
return session;
|
|
313
|
+
},
|
|
314
|
+
async getCatalog() {
|
|
315
|
+
const active = requireSession();
|
|
316
|
+
return transport.request("/v1/checkout/catalog", {
|
|
317
|
+
sessionToken: active.sessionToken
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
async quote(params) {
|
|
321
|
+
const active = requireSession();
|
|
322
|
+
return transport.request("/v1/checkout/quote", {
|
|
323
|
+
method: "POST",
|
|
324
|
+
body: params,
|
|
325
|
+
sessionToken: active.sessionToken
|
|
326
|
+
});
|
|
327
|
+
},
|
|
328
|
+
async sendOtp(params) {
|
|
329
|
+
const active = requireSession();
|
|
330
|
+
return transport.request("/v1/checkout/otp/send", {
|
|
331
|
+
method: "POST",
|
|
332
|
+
body: params,
|
|
333
|
+
sessionToken: active.sessionToken
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
async verifyOtp(params) {
|
|
337
|
+
const active = requireSession();
|
|
338
|
+
return transport.request("/v1/checkout/otp/verify", {
|
|
339
|
+
method: "POST",
|
|
340
|
+
body: params,
|
|
341
|
+
sessionToken: active.sessionToken
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
async createPurchase(params) {
|
|
345
|
+
const active = requireSession();
|
|
346
|
+
return transport.request("/v1/checkout/purchases", {
|
|
347
|
+
method: "POST",
|
|
348
|
+
body: params,
|
|
349
|
+
sessionToken: active.sessionToken
|
|
350
|
+
});
|
|
351
|
+
},
|
|
352
|
+
async createPayment(params) {
|
|
353
|
+
const active = requireSession();
|
|
354
|
+
return transport.request("/v1/checkout/payments", {
|
|
355
|
+
method: "POST",
|
|
356
|
+
body: params,
|
|
357
|
+
sessionToken: active.sessionToken
|
|
358
|
+
});
|
|
359
|
+
},
|
|
360
|
+
async getPaymentStatus() {
|
|
361
|
+
const active = requireSession();
|
|
362
|
+
return transport.request("/v1/checkout/payments/status", {
|
|
363
|
+
sessionToken: active.sessionToken
|
|
364
|
+
});
|
|
365
|
+
},
|
|
366
|
+
async watchPayment(options2) {
|
|
367
|
+
const intervalMs = options2?.intervalMs ?? 2500;
|
|
368
|
+
const timeoutMs = options2?.timeoutMs ?? 5 * 60 * 1e3;
|
|
369
|
+
const started = Date.now();
|
|
370
|
+
while (Date.now() - started < timeoutMs) {
|
|
371
|
+
if (options2?.signal?.aborted) {
|
|
372
|
+
throw new TickeanError({
|
|
373
|
+
code: "checkout_aborted",
|
|
374
|
+
message: "Payment watch aborted"
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
const status = await this.getPaymentStatus();
|
|
378
|
+
if (["COMPLETED", "CONFIRMED", "PAID"].includes(
|
|
379
|
+
String(status.status || "").toUpperCase()
|
|
380
|
+
) || ["COMPLETED", "CONFIRMED", "PAID"].includes(
|
|
381
|
+
String(status.purchase?.status || "").toUpperCase()
|
|
382
|
+
)) {
|
|
383
|
+
return status;
|
|
384
|
+
}
|
|
385
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
386
|
+
}
|
|
387
|
+
throw new TickeanError({
|
|
388
|
+
code: "checkout_payment_timeout",
|
|
389
|
+
message: "Timed out waiting for payment confirmation"
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
395
|
+
0 && (module.exports = {
|
|
396
|
+
TickeanError,
|
|
397
|
+
createTickean
|
|
398
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
// src/demo.ts
|
|
2
|
+
var demoEvent = {
|
|
3
|
+
id: "evt_demo",
|
|
4
|
+
slug: "demo-festival",
|
|
5
|
+
title: "Demo Festival",
|
|
6
|
+
description: "Sample multi-day festival for local SDK demos.",
|
|
7
|
+
availablePaymentMethods: ["TRANSFER", "MERCADOPAGO"],
|
|
8
|
+
organization: {
|
|
9
|
+
id: "org_demo",
|
|
10
|
+
slug: "demo-org",
|
|
11
|
+
name: "Demo Organizer",
|
|
12
|
+
logo: null
|
|
13
|
+
},
|
|
14
|
+
shows: [
|
|
15
|
+
{
|
|
16
|
+
id: "show_sat",
|
|
17
|
+
title: "S\xE1bado",
|
|
18
|
+
date: new Date(Date.now() + 7 * 864e5).toISOString(),
|
|
19
|
+
showOptions: [
|
|
20
|
+
{
|
|
21
|
+
id: "opt_day",
|
|
22
|
+
name: "Entrada general",
|
|
23
|
+
price: 15e3,
|
|
24
|
+
currency: "ARS",
|
|
25
|
+
stock: 100,
|
|
26
|
+
maxPerPurchase: 6,
|
|
27
|
+
optionType: "TICKET",
|
|
28
|
+
accessScope: "SINGLE_SHOW",
|
|
29
|
+
catalogVisibility: "PUBLIC",
|
|
30
|
+
passIssuanceMode: "PER_DAY"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "show_sun",
|
|
36
|
+
title: "Domingo",
|
|
37
|
+
date: new Date(Date.now() + 8 * 864e5).toISOString(),
|
|
38
|
+
showOptions: [
|
|
39
|
+
{
|
|
40
|
+
id: "opt_pass",
|
|
41
|
+
name: "Abono 2 d\xEDas",
|
|
42
|
+
price: 25e3,
|
|
43
|
+
currency: "ARS",
|
|
44
|
+
stock: 50,
|
|
45
|
+
maxPerPurchase: 4,
|
|
46
|
+
optionType: "TICKET",
|
|
47
|
+
accessScope: "ALL_EVENT_SHOWS",
|
|
48
|
+
coveredShowIds: ["show_sat", "show_sun"],
|
|
49
|
+
passIssuanceMode: "SINGLE_PASS",
|
|
50
|
+
catalogVisibility: "PUBLIC"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "opt_gated",
|
|
54
|
+
name: "Promo 2x1 (c\xF3digo)",
|
|
55
|
+
price: 15e3,
|
|
56
|
+
currency: "ARS",
|
|
57
|
+
stock: 30,
|
|
58
|
+
maxPerPurchase: 4,
|
|
59
|
+
optionType: "TICKET",
|
|
60
|
+
accessScope: "SINGLE_SHOW",
|
|
61
|
+
catalogVisibility: "PROMO_GATED",
|
|
62
|
+
promotionNxM: { enabled: true, buyQty: 2, payQty: 1 }
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
function createDemoTransport() {
|
|
69
|
+
let sessionToken = "demo_session_token";
|
|
70
|
+
let buyer = null;
|
|
71
|
+
let unlocked = [];
|
|
72
|
+
let purchaseId = "purchase_demo";
|
|
73
|
+
let cartRef = "cart_demo";
|
|
74
|
+
return {
|
|
75
|
+
async request(path, init) {
|
|
76
|
+
if (path === "/v1/checkout/sessions" && init.method === "POST") {
|
|
77
|
+
sessionToken = `demo_${Date.now()}`;
|
|
78
|
+
return {
|
|
79
|
+
sessionId: "sess_demo",
|
|
80
|
+
sessionToken,
|
|
81
|
+
expiresAt: new Date(Date.now() + 36e5).toISOString(),
|
|
82
|
+
event: {
|
|
83
|
+
...demoEvent,
|
|
84
|
+
shows: demoEvent.shows.map((show) => ({
|
|
85
|
+
...show,
|
|
86
|
+
showOptions: show.showOptions.filter(
|
|
87
|
+
(o) => o.catalogVisibility !== "PROMO_GATED"
|
|
88
|
+
)
|
|
89
|
+
}))
|
|
90
|
+
},
|
|
91
|
+
capabilities: {
|
|
92
|
+
tickets: true,
|
|
93
|
+
discounts: true,
|
|
94
|
+
transfer: true,
|
|
95
|
+
onlinePayments: true
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (path === "/v1/checkout/catalog") {
|
|
100
|
+
return {
|
|
101
|
+
...demoEvent,
|
|
102
|
+
shows: demoEvent.shows.map((show) => ({
|
|
103
|
+
...show,
|
|
104
|
+
showOptions: [
|
|
105
|
+
...show.showOptions.filter(
|
|
106
|
+
(o) => o.catalogVisibility !== "PROMO_GATED"
|
|
107
|
+
),
|
|
108
|
+
...unlocked.filter(
|
|
109
|
+
(u) => show.showOptions.some((o) => o.id === u.id)
|
|
110
|
+
)
|
|
111
|
+
]
|
|
112
|
+
}))
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (path === "/v1/checkout/quote" && init.method === "POST") {
|
|
116
|
+
const body = init.body;
|
|
117
|
+
if (body.discountCode?.toUpperCase() === "DEMO2X1") {
|
|
118
|
+
unlocked = demoEvent.shows.flatMap((s) => s.showOptions).filter((o) => o.catalogVisibility === "PROMO_GATED");
|
|
119
|
+
}
|
|
120
|
+
const allOptions = demoEvent.shows.flatMap((s) => s.showOptions);
|
|
121
|
+
const total = body.items.reduce((sum, item) => {
|
|
122
|
+
const opt = allOptions.find((o) => o.id === item.showOptionId);
|
|
123
|
+
return sum + Number(opt?.price || 0) * item.amount;
|
|
124
|
+
}, 0);
|
|
125
|
+
return {
|
|
126
|
+
valid: true,
|
|
127
|
+
totalPrice: total,
|
|
128
|
+
pricingBreakdown: { subtotal: total },
|
|
129
|
+
unlockedShowOptionIds: unlocked.map((o) => o.id),
|
|
130
|
+
unlockedShowOptions: unlocked
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (path === "/v1/checkout/otp/send") {
|
|
134
|
+
return { sent: true };
|
|
135
|
+
}
|
|
136
|
+
if (path === "/v1/checkout/otp/verify") {
|
|
137
|
+
const body = init.body;
|
|
138
|
+
buyer = {
|
|
139
|
+
id: "buyer_demo",
|
|
140
|
+
phone: body.phone,
|
|
141
|
+
name: body.name || "Demo Buyer",
|
|
142
|
+
email: body.email
|
|
143
|
+
};
|
|
144
|
+
return { verified: true, buyer };
|
|
145
|
+
}
|
|
146
|
+
if (path === "/v1/checkout/purchases") {
|
|
147
|
+
if (!buyer) {
|
|
148
|
+
throw Object.assign(new Error("OTP required"), {
|
|
149
|
+
code: "checkout_otp_required"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const body = init.body;
|
|
153
|
+
const allOptions = demoEvent.shows.flatMap((s) => s.showOptions);
|
|
154
|
+
const total = body.items.reduce((sum, item) => {
|
|
155
|
+
const opt = allOptions.find((o) => o.id === item.showOptionId);
|
|
156
|
+
return sum + Number(opt?.price || 0) * item.amount;
|
|
157
|
+
}, 0);
|
|
158
|
+
purchaseId = `purchase_${Date.now()}`;
|
|
159
|
+
cartRef = `cart_${Date.now()}`;
|
|
160
|
+
return {
|
|
161
|
+
purchase: {
|
|
162
|
+
id: purchaseId,
|
|
163
|
+
status: "PENDING",
|
|
164
|
+
totalPrice: total,
|
|
165
|
+
currency: body.currency,
|
|
166
|
+
shoppingCartReference: cartRef,
|
|
167
|
+
paymentMethod: body.paymentMethod
|
|
168
|
+
},
|
|
169
|
+
shoppingCartReference: cartRef,
|
|
170
|
+
cartSessionToken: "demo_cart_token"
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (path === "/v1/checkout/payments") {
|
|
174
|
+
return {
|
|
175
|
+
id: `pay_${Date.now()}`,
|
|
176
|
+
paymentStatus: "PENDING",
|
|
177
|
+
paymentMethod: init.body?.paymentMethod,
|
|
178
|
+
paymentInstructions: {
|
|
179
|
+
alias: "tickean.demo",
|
|
180
|
+
cvu: "0000003100010000000001",
|
|
181
|
+
amount: init.body?.amount
|
|
182
|
+
},
|
|
183
|
+
redirectUrl: void 0,
|
|
184
|
+
returnUrl: null
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (path === "/v1/checkout/payments/status") {
|
|
188
|
+
return {
|
|
189
|
+
status: "PENDING",
|
|
190
|
+
purchase: {
|
|
191
|
+
id: purchaseId,
|
|
192
|
+
status: "PENDING",
|
|
193
|
+
totalPrice: 0,
|
|
194
|
+
currency: "ARS",
|
|
195
|
+
shoppingCartReference: cartRef
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
throw new Error(`Demo transport: unhandled ${init.method || "GET"} ${path}`);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/types.ts
|
|
205
|
+
var TickeanError = class extends Error {
|
|
206
|
+
constructor(payload, status) {
|
|
207
|
+
super(payload.message);
|
|
208
|
+
this.name = "TickeanError";
|
|
209
|
+
this.code = payload.code;
|
|
210
|
+
this.details = payload.details;
|
|
211
|
+
this.status = status;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/http.ts
|
|
216
|
+
function createHttpTransport(options) {
|
|
217
|
+
const fetchImpl = options.fetchImpl || fetch;
|
|
218
|
+
return {
|
|
219
|
+
async request(path, init) {
|
|
220
|
+
const headers = {
|
|
221
|
+
"Content-Type": "application/json",
|
|
222
|
+
"X-Tickean-Key": options.publishableKey
|
|
223
|
+
};
|
|
224
|
+
if (init.sessionToken) {
|
|
225
|
+
headers["X-Tickean-Checkout-Session"] = init.sessionToken;
|
|
226
|
+
}
|
|
227
|
+
const response = await fetchImpl(
|
|
228
|
+
`${options.apiBaseUrl.replace(/\/$/, "")}${path}`,
|
|
229
|
+
{
|
|
230
|
+
method: init.method || "GET",
|
|
231
|
+
headers,
|
|
232
|
+
body: init.body ? JSON.stringify(init.body) : void 0,
|
|
233
|
+
credentials: "omit"
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
const json = await response.json().catch(() => ({}));
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
const err = json?.error || {};
|
|
239
|
+
throw new TickeanError(
|
|
240
|
+
{
|
|
241
|
+
code: err.code || "checkout_request_failed",
|
|
242
|
+
message: err.message || response.statusText || "Request failed",
|
|
243
|
+
details: err.details
|
|
244
|
+
},
|
|
245
|
+
response.status
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return json;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/index.ts
|
|
254
|
+
function createTickean(options) {
|
|
255
|
+
if (!options.publishableKey && !options.demo) {
|
|
256
|
+
throw new TickeanError({
|
|
257
|
+
code: "checkout_key_required",
|
|
258
|
+
message: "publishableKey is required unless demo mode is enabled"
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
const transport = options.demo ? createDemoTransport() : createHttpTransport({
|
|
262
|
+
publishableKey: options.publishableKey,
|
|
263
|
+
apiBaseUrl: options.apiBaseUrl || "https://api.tickean.com",
|
|
264
|
+
fetchImpl: options.fetchImpl
|
|
265
|
+
});
|
|
266
|
+
let session = null;
|
|
267
|
+
const requireSession = () => {
|
|
268
|
+
if (!session?.sessionToken) {
|
|
269
|
+
throw new TickeanError({
|
|
270
|
+
code: "checkout_session_required",
|
|
271
|
+
message: "Call createSession() before using checkout methods"
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return session;
|
|
275
|
+
};
|
|
276
|
+
return {
|
|
277
|
+
get session() {
|
|
278
|
+
return session;
|
|
279
|
+
},
|
|
280
|
+
async createSession(params) {
|
|
281
|
+
session = await transport.request("/v1/checkout/sessions", {
|
|
282
|
+
method: "POST",
|
|
283
|
+
body: params
|
|
284
|
+
});
|
|
285
|
+
return session;
|
|
286
|
+
},
|
|
287
|
+
async getCatalog() {
|
|
288
|
+
const active = requireSession();
|
|
289
|
+
return transport.request("/v1/checkout/catalog", {
|
|
290
|
+
sessionToken: active.sessionToken
|
|
291
|
+
});
|
|
292
|
+
},
|
|
293
|
+
async quote(params) {
|
|
294
|
+
const active = requireSession();
|
|
295
|
+
return transport.request("/v1/checkout/quote", {
|
|
296
|
+
method: "POST",
|
|
297
|
+
body: params,
|
|
298
|
+
sessionToken: active.sessionToken
|
|
299
|
+
});
|
|
300
|
+
},
|
|
301
|
+
async sendOtp(params) {
|
|
302
|
+
const active = requireSession();
|
|
303
|
+
return transport.request("/v1/checkout/otp/send", {
|
|
304
|
+
method: "POST",
|
|
305
|
+
body: params,
|
|
306
|
+
sessionToken: active.sessionToken
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
async verifyOtp(params) {
|
|
310
|
+
const active = requireSession();
|
|
311
|
+
return transport.request("/v1/checkout/otp/verify", {
|
|
312
|
+
method: "POST",
|
|
313
|
+
body: params,
|
|
314
|
+
sessionToken: active.sessionToken
|
|
315
|
+
});
|
|
316
|
+
},
|
|
317
|
+
async createPurchase(params) {
|
|
318
|
+
const active = requireSession();
|
|
319
|
+
return transport.request("/v1/checkout/purchases", {
|
|
320
|
+
method: "POST",
|
|
321
|
+
body: params,
|
|
322
|
+
sessionToken: active.sessionToken
|
|
323
|
+
});
|
|
324
|
+
},
|
|
325
|
+
async createPayment(params) {
|
|
326
|
+
const active = requireSession();
|
|
327
|
+
return transport.request("/v1/checkout/payments", {
|
|
328
|
+
method: "POST",
|
|
329
|
+
body: params,
|
|
330
|
+
sessionToken: active.sessionToken
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
async getPaymentStatus() {
|
|
334
|
+
const active = requireSession();
|
|
335
|
+
return transport.request("/v1/checkout/payments/status", {
|
|
336
|
+
sessionToken: active.sessionToken
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
async watchPayment(options2) {
|
|
340
|
+
const intervalMs = options2?.intervalMs ?? 2500;
|
|
341
|
+
const timeoutMs = options2?.timeoutMs ?? 5 * 60 * 1e3;
|
|
342
|
+
const started = Date.now();
|
|
343
|
+
while (Date.now() - started < timeoutMs) {
|
|
344
|
+
if (options2?.signal?.aborted) {
|
|
345
|
+
throw new TickeanError({
|
|
346
|
+
code: "checkout_aborted",
|
|
347
|
+
message: "Payment watch aborted"
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
const status = await this.getPaymentStatus();
|
|
351
|
+
if (["COMPLETED", "CONFIRMED", "PAID"].includes(
|
|
352
|
+
String(status.status || "").toUpperCase()
|
|
353
|
+
) || ["COMPLETED", "CONFIRMED", "PAID"].includes(
|
|
354
|
+
String(status.purchase?.status || "").toUpperCase()
|
|
355
|
+
)) {
|
|
356
|
+
return status;
|
|
357
|
+
}
|
|
358
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
359
|
+
}
|
|
360
|
+
throw new TickeanError({
|
|
361
|
+
code: "checkout_payment_timeout",
|
|
362
|
+
message: "Timed out waiting for payment confirmation"
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
export {
|
|
368
|
+
TickeanError,
|
|
369
|
+
createTickean
|
|
370
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tickean/checkout-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tickean Headless Checkout TypeScript client",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"tsup": "^8.4.0",
|
|
27
|
+
"typescript": "^5.8.2",
|
|
28
|
+
"vitest": "^3.0.5"
|
|
29
|
+
}
|
|
30
|
+
}
|