@superlogic/spree-pay 0.1.42 → 0.2.1
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/build/CryptoComTab-WWW23OV5.js +169 -0
- package/build/CryptoTab-HISSGXAC.js +838 -0
- package/build/chunk-2V675UEC.js +56 -0
- package/build/chunk-FGNS5H2Q.js +278 -0
- package/build/chunk-RQX2IOTB.js +795 -0
- package/build/index.cjs +4374 -3869
- package/build/index.css +60 -21
- package/build/index.js +1507 -3510
- package/package.json +1 -1
|
@@ -0,0 +1,795 @@
|
|
|
1
|
+
// src/types/payments.ts
|
|
2
|
+
var PaymentType = /* @__PURE__ */ ((PaymentType2) => {
|
|
3
|
+
PaymentType2["CREDIT_CARD"] = "CREDIT_CARD";
|
|
4
|
+
PaymentType2["CRYPTO"] = "CRYPTO";
|
|
5
|
+
PaymentType2["CDC"] = "CDC";
|
|
6
|
+
PaymentType2["CREDIT_CARD_SPLIT"] = "SPLIT";
|
|
7
|
+
PaymentType2["POINTS"] = "POINTS";
|
|
8
|
+
return PaymentType2;
|
|
9
|
+
})(PaymentType || {});
|
|
10
|
+
|
|
11
|
+
// package.json
|
|
12
|
+
var version = "0.2.1";
|
|
13
|
+
|
|
14
|
+
// src/utils/logger.ts
|
|
15
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
16
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
17
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
18
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
19
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
20
|
+
LogLevel2[LogLevel2["NONE"] = 4] = "NONE";
|
|
21
|
+
return LogLevel2;
|
|
22
|
+
})(LogLevel || {});
|
|
23
|
+
var Logger = class _Logger {
|
|
24
|
+
config;
|
|
25
|
+
constructor(config2 = {}) {
|
|
26
|
+
this.config = {
|
|
27
|
+
minLevel: this.getDefaultLogLevel(config2.environment),
|
|
28
|
+
prefix: "[spree-pay]",
|
|
29
|
+
...config2
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Determines default log level based on environment
|
|
34
|
+
* - Production: Only ERROR and version info
|
|
35
|
+
* - Development/Staging: All logs
|
|
36
|
+
*/
|
|
37
|
+
getDefaultLogLevel(environment) {
|
|
38
|
+
if (typeof window === "undefined") return 1 /* INFO */;
|
|
39
|
+
if (environment) {
|
|
40
|
+
return environment === "prod" ? 3 /* ERROR */ : 0 /* DEBUG */;
|
|
41
|
+
}
|
|
42
|
+
return 3 /* ERROR */;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Set the environment and update log level accordingly
|
|
46
|
+
*/
|
|
47
|
+
setEnvironment(environment) {
|
|
48
|
+
this.config.environment = environment;
|
|
49
|
+
this.config.minLevel = this.getDefaultLogLevel(environment);
|
|
50
|
+
}
|
|
51
|
+
shouldLog(level) {
|
|
52
|
+
return level >= this.config.minLevel;
|
|
53
|
+
}
|
|
54
|
+
formatMessage(level, message, context) {
|
|
55
|
+
const levelName = LogLevel[level];
|
|
56
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
57
|
+
const contextStr = context && Object.keys(context).length > 0 ? ` ${JSON.stringify(context)}` : "";
|
|
58
|
+
return `${this.config.prefix} [${levelName}] ${timestamp} - ${message}${contextStr}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Log debug information (only in dev/stg)
|
|
62
|
+
*/
|
|
63
|
+
debug(message, context) {
|
|
64
|
+
if (!this.shouldLog(0 /* DEBUG */)) return;
|
|
65
|
+
console.log(this.formatMessage(0 /* DEBUG */, message, context));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Log informational messages (only in dev/stg)
|
|
69
|
+
*/
|
|
70
|
+
info(message, context) {
|
|
71
|
+
if (!this.shouldLog(1 /* INFO */)) return;
|
|
72
|
+
console.log(this.formatMessage(1 /* INFO */, message, context));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Log warnings (only in dev/stg)
|
|
76
|
+
*/
|
|
77
|
+
warn(message, context) {
|
|
78
|
+
if (!this.shouldLog(2 /* WARN */)) return;
|
|
79
|
+
console.warn(this.formatMessage(2 /* WARN */, message, context));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Log errors (shows in all environments)
|
|
83
|
+
*/
|
|
84
|
+
error(message, error, context) {
|
|
85
|
+
if (!this.shouldLog(3 /* ERROR */)) return;
|
|
86
|
+
const errorContext = {
|
|
87
|
+
...context,
|
|
88
|
+
...error instanceof Error ? {
|
|
89
|
+
errorName: error.name,
|
|
90
|
+
errorMessage: error.message,
|
|
91
|
+
errorStack: error.stack
|
|
92
|
+
} : { error }
|
|
93
|
+
};
|
|
94
|
+
console.error(this.formatMessage(3 /* ERROR */, message, errorContext));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Always logs the version, regardless of environment
|
|
98
|
+
*/
|
|
99
|
+
logVersion() {
|
|
100
|
+
console.log(`${this.config.prefix} v${version} - ${this.config.environment}`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Creates a child logger with additional context
|
|
104
|
+
* Useful for component-specific logging
|
|
105
|
+
*/
|
|
106
|
+
child(prefix) {
|
|
107
|
+
return new _Logger({
|
|
108
|
+
...this.config,
|
|
109
|
+
prefix: `${this.config.prefix}:${prefix}`
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Override log level (useful for testing or debugging)
|
|
114
|
+
*/
|
|
115
|
+
setLogLevel(level) {
|
|
116
|
+
this.config.minLevel = level;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var logger = new Logger();
|
|
120
|
+
var configureLogger = (config2) => {
|
|
121
|
+
if (config2.environment) {
|
|
122
|
+
logger.setEnvironment(config2.environment);
|
|
123
|
+
}
|
|
124
|
+
const { environment, ...restConfig } = config2;
|
|
125
|
+
Object.assign(logger["config"], restConfig);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// src/context/SpreePayActionsContext.tsx
|
|
129
|
+
import { createContext, useCallback, useContext, useRef, useState } from "react";
|
|
130
|
+
|
|
131
|
+
// src/types/errors.ts
|
|
132
|
+
var PaymentError = class extends Error {
|
|
133
|
+
status;
|
|
134
|
+
details;
|
|
135
|
+
constructor(message, status, details) {
|
|
136
|
+
super(message);
|
|
137
|
+
this.name = "PaymentError";
|
|
138
|
+
this.status = status;
|
|
139
|
+
this.details = details;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/context/SpreePayActionsContext.tsx
|
|
144
|
+
import { jsx } from "react/jsx-runtime";
|
|
145
|
+
var processLogger = logger.child("process");
|
|
146
|
+
var SpreePayActionsContext = createContext(void 0);
|
|
147
|
+
var SpreePayProvider = ({ children, env }) => {
|
|
148
|
+
const processRef = useRef(null);
|
|
149
|
+
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState({
|
|
150
|
+
type: "CREDIT_CARD" /* CREDIT_CARD */,
|
|
151
|
+
method: null
|
|
152
|
+
});
|
|
153
|
+
const [isInternalProcessing, setInternalProcessing] = useState(false);
|
|
154
|
+
const register = useCallback((fn) => {
|
|
155
|
+
processRef.current = fn;
|
|
156
|
+
}, []);
|
|
157
|
+
const process = useCallback(
|
|
158
|
+
async (data) => {
|
|
159
|
+
if (!processRef.current) {
|
|
160
|
+
const error = new Error("SpreePay process function not registered");
|
|
161
|
+
processLogger.error("Process function not registered", error);
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
processLogger.info("Payment process started", {
|
|
165
|
+
hash: data.hash,
|
|
166
|
+
capture: data.capture,
|
|
167
|
+
hasMetadata: Boolean(data.metadata),
|
|
168
|
+
paymentType: selectedPaymentMethod.type
|
|
169
|
+
});
|
|
170
|
+
setInternalProcessing(true);
|
|
171
|
+
try {
|
|
172
|
+
const result = await processRef.current(data);
|
|
173
|
+
processLogger.info("Payment process completed", {
|
|
174
|
+
status: result.status,
|
|
175
|
+
paymentId: result.paymentId,
|
|
176
|
+
paymentType: result.paymentType,
|
|
177
|
+
txHash: result.txHash
|
|
178
|
+
});
|
|
179
|
+
return result;
|
|
180
|
+
} catch (e) {
|
|
181
|
+
processLogger.error("Payment process failed", e instanceof Error ? e : void 0, {
|
|
182
|
+
hash: data.hash,
|
|
183
|
+
paymentType: selectedPaymentMethod.type,
|
|
184
|
+
errorMessage: e instanceof Error ? e.message : String(e)
|
|
185
|
+
});
|
|
186
|
+
if (e instanceof Error) throw e;
|
|
187
|
+
throw new PaymentError("Payment failed", "FAILED" /* FAILED */, e);
|
|
188
|
+
} finally {
|
|
189
|
+
setInternalProcessing(false);
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
[selectedPaymentMethod.type]
|
|
193
|
+
);
|
|
194
|
+
const value = {
|
|
195
|
+
// Set default to true for web3 points to backward compatibility
|
|
196
|
+
env: { ...env, useWeb3Points: env.useWeb3Points ?? true },
|
|
197
|
+
enabled: Boolean(selectedPaymentMethod.method),
|
|
198
|
+
isInternalProcessing,
|
|
199
|
+
process,
|
|
200
|
+
register,
|
|
201
|
+
selectedPaymentMethod,
|
|
202
|
+
setSelectedPaymentMethod
|
|
203
|
+
};
|
|
204
|
+
return /* @__PURE__ */ jsx(SpreePayActionsContext.Provider, { value, children });
|
|
205
|
+
};
|
|
206
|
+
var useSpreePay = () => {
|
|
207
|
+
const ctx = useContext(SpreePayActionsContext);
|
|
208
|
+
if (!ctx) throw new Error("useSpreePay must be used within a SpreePayProvider");
|
|
209
|
+
return {
|
|
210
|
+
process: ctx.process,
|
|
211
|
+
isProcessing: ctx.isInternalProcessing,
|
|
212
|
+
enabled: ctx.enabled,
|
|
213
|
+
selectedPaymentMethod: ctx.selectedPaymentMethod
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
var useSpreePaymentMethod = () => {
|
|
217
|
+
const ctx = useContext(SpreePayActionsContext);
|
|
218
|
+
if (!ctx) throw new Error("useSpreePay must be used within a SpreePayProvider");
|
|
219
|
+
return {
|
|
220
|
+
setSelectedPaymentMethod: ctx.setSelectedPaymentMethod,
|
|
221
|
+
selectedPaymentMethod: ctx.selectedPaymentMethod,
|
|
222
|
+
isInternalProcessing: ctx.isInternalProcessing
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
var useSpreePayEnv = () => {
|
|
226
|
+
const ctx = useContext(SpreePayActionsContext);
|
|
227
|
+
if (!ctx) throw new Error("useSpreePay must be used within a SpreePayProvider");
|
|
228
|
+
return { env: ctx.env };
|
|
229
|
+
};
|
|
230
|
+
var useSpreePayRegister = () => {
|
|
231
|
+
const ctx = useContext(SpreePayActionsContext);
|
|
232
|
+
if (!ctx) throw new Error("useSpreePayRegister must be used within a SpreePayProvider");
|
|
233
|
+
return { register: ctx.register };
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// src/context/StaticConfigContext.tsx
|
|
237
|
+
import { createContext as createContext2, useContext as useContext2, useEffect, useMemo, useState as useState2 } from "react";
|
|
238
|
+
|
|
239
|
+
// src/context/config.ts
|
|
240
|
+
var config = {
|
|
241
|
+
dev: {
|
|
242
|
+
bookit: {
|
|
243
|
+
slapiUrl: "https://slapi.dev.superlogic.com",
|
|
244
|
+
keycloakUrl: "https://auth.dev.join.bookit.com",
|
|
245
|
+
keycloakClientId: "oneof-next"
|
|
246
|
+
},
|
|
247
|
+
moca: {
|
|
248
|
+
slapiUrl: "https://slapi.dev.air.shop",
|
|
249
|
+
keycloakUrl: "https://login.dev.air.shop",
|
|
250
|
+
keycloakClientId: "oneof-next"
|
|
251
|
+
},
|
|
252
|
+
qiibee: {
|
|
253
|
+
slapiUrl: "https://slapi.dev.superlogic.com",
|
|
254
|
+
keycloakUrl: "https://sso.dev.tickets.qiibeefoundation.org",
|
|
255
|
+
keycloakClientId: "oneof-next"
|
|
256
|
+
},
|
|
257
|
+
umhp: {
|
|
258
|
+
slapiUrl: "https://slapi.dev.umusicpassport.com",
|
|
259
|
+
keycloakUrl: "https://auth.dev.umusicpassport.com",
|
|
260
|
+
keycloakClientId: "oneof-next"
|
|
261
|
+
},
|
|
262
|
+
cdc: {
|
|
263
|
+
slapiUrl: "https://slapi.dev.superlogic.com",
|
|
264
|
+
keycloakUrl: "https://auth.dev02.superlogic.com",
|
|
265
|
+
keycloakClientId: "oneof-next"
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
stg: {
|
|
269
|
+
bookit: {
|
|
270
|
+
slapiUrl: "https://slapi.stg.superlogic.com",
|
|
271
|
+
keycloakUrl: "https://auth.stg.join.bookit.com",
|
|
272
|
+
keycloakClientId: "oneof-next"
|
|
273
|
+
},
|
|
274
|
+
moca: {
|
|
275
|
+
slapiUrl: "https://slapi.stg.air.shop",
|
|
276
|
+
keycloakUrl: "https://login.stg.air.shop",
|
|
277
|
+
keycloakClientId: "oneof-next"
|
|
278
|
+
},
|
|
279
|
+
qiibee: {
|
|
280
|
+
slapiUrl: "https://slapi.stg.tickets.qiibeefoundation.org",
|
|
281
|
+
keycloakUrl: "https://sso.stg.tickets.qiibeefoundation.org",
|
|
282
|
+
keycloakClientId: "oneof-next"
|
|
283
|
+
},
|
|
284
|
+
umhp: {
|
|
285
|
+
slapiUrl: "https://slapi.stg.umusicpassport.com",
|
|
286
|
+
keycloakUrl: "https://auth.stg.umusicpassport.com",
|
|
287
|
+
keycloakClientId: "oneof-next"
|
|
288
|
+
},
|
|
289
|
+
cdc: {
|
|
290
|
+
slapiUrl: "https://slapi.stg.superlogic.com",
|
|
291
|
+
keycloakUrl: "https://auth.stg02.superlogic.com",
|
|
292
|
+
keycloakClientId: "oneof-next"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
prod: {
|
|
296
|
+
bookit: {
|
|
297
|
+
slapiUrl: "https://slapi.superlogic.com",
|
|
298
|
+
keycloakUrl: "https://auth.join.bookit.com",
|
|
299
|
+
keycloakClientId: "oneof-next"
|
|
300
|
+
},
|
|
301
|
+
moca: {
|
|
302
|
+
slapiUrl: "https://slapi.air.shop",
|
|
303
|
+
keycloakUrl: "https://login.air.shop",
|
|
304
|
+
keycloakClientId: "oneof-next"
|
|
305
|
+
},
|
|
306
|
+
qiibee: {
|
|
307
|
+
slapiUrl: "https://slapi.tickets.qiibeefoundation.org",
|
|
308
|
+
keycloakUrl: "https://sso.tickets.qiibeefoundation.org",
|
|
309
|
+
keycloakClientId: "oneof-next"
|
|
310
|
+
},
|
|
311
|
+
umhp: {
|
|
312
|
+
slapiUrl: "https://slapi.umusicpassport.com",
|
|
313
|
+
keycloakUrl: "https://auth.umusicpassport.com",
|
|
314
|
+
keycloakClientId: "oneof-next"
|
|
315
|
+
},
|
|
316
|
+
cdc: {
|
|
317
|
+
slapiUrl: "https://slapi.superlogic.com",
|
|
318
|
+
keycloakUrl: "https://auth.superlogic.com",
|
|
319
|
+
keycloakClientId: "oneof-next"
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/context/StaticConfigContext.tsx
|
|
325
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
326
|
+
var StaticConfigContext = createContext2(null);
|
|
327
|
+
var StaticConfigProvider = ({ children, props }) => {
|
|
328
|
+
const { env } = useSpreePayEnv();
|
|
329
|
+
const [appProps, setAppProps] = useState2(props);
|
|
330
|
+
useEffect(() => {
|
|
331
|
+
setAppProps(props);
|
|
332
|
+
}, [props]);
|
|
333
|
+
const staticConfig = useMemo(() => {
|
|
334
|
+
const envConfig = config[env.environment];
|
|
335
|
+
const isKnownTenant = env.tenantId in envConfig;
|
|
336
|
+
if (!isKnownTenant) {
|
|
337
|
+
logger.warn(`Unknown tenantId "${env.tenantId}", falling back to "moca"`, {
|
|
338
|
+
tenantId: env.tenantId,
|
|
339
|
+
environment: env.environment
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
const appKey = isKnownTenant ? env.tenantId : "moca";
|
|
343
|
+
return envConfig[appKey];
|
|
344
|
+
}, [env.environment, env.tenantId]);
|
|
345
|
+
return /* @__PURE__ */ jsx2(StaticConfigContext.Provider, { value: { staticConfig, appProps }, children });
|
|
346
|
+
};
|
|
347
|
+
var useStaticConfig = () => {
|
|
348
|
+
const ctx = useContext2(StaticConfigContext);
|
|
349
|
+
if (!ctx) throw new Error("useStaticConfig must be used within StaticConfigProvider");
|
|
350
|
+
return ctx;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// src/lib/utils.ts
|
|
354
|
+
import { clsx } from "clsx";
|
|
355
|
+
import { twMerge } from "tailwind-merge";
|
|
356
|
+
function cn(...inputs) {
|
|
357
|
+
return twMerge(clsx(inputs));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/ui/portal.ts
|
|
361
|
+
import React from "react";
|
|
362
|
+
var PortalContainerContext = React.createContext({ container: null });
|
|
363
|
+
function PortalContainerProvider({
|
|
364
|
+
container,
|
|
365
|
+
children
|
|
366
|
+
}) {
|
|
367
|
+
return React.createElement(PortalContainerContext.Provider, { value: { container } }, children);
|
|
368
|
+
}
|
|
369
|
+
function usePortalContainer() {
|
|
370
|
+
return React.useContext(PortalContainerContext).container;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/fetcher/client.ts
|
|
374
|
+
var cfg = { baseUrl: void 0, accessToken: void 0, tenantId: void 0 };
|
|
375
|
+
var buildUrl = (key) => {
|
|
376
|
+
if (!cfg.baseUrl) throw new Error("Missing SLAPI baseUrl. Call registerApi(...) first.");
|
|
377
|
+
if (typeof key === "string") return cfg.baseUrl + key;
|
|
378
|
+
const { url, params = {} } = key;
|
|
379
|
+
const usp = new URLSearchParams();
|
|
380
|
+
Object.entries(params).forEach(([k, v]) => {
|
|
381
|
+
if (v === void 0 || v === null) return;
|
|
382
|
+
usp.append(k, String(v));
|
|
383
|
+
});
|
|
384
|
+
const qs = usp.toString();
|
|
385
|
+
return cfg.baseUrl + url + (qs ? `?${qs}` : "");
|
|
386
|
+
};
|
|
387
|
+
var request = async (method, url, body) => {
|
|
388
|
+
if (!cfg.accessToken) throw new Error("Missing SLAPI accessToken. Call registerApi(...) first.");
|
|
389
|
+
if (!cfg.tenantId) throw new Error("Missing SLAPI tenantId. Call registerApi(...) first.");
|
|
390
|
+
const headers = {
|
|
391
|
+
Accept: "application/json",
|
|
392
|
+
Authorization: `Bearer ${cfg.accessToken}`,
|
|
393
|
+
["X-Tenant-ID"]: cfg.tenantId
|
|
394
|
+
};
|
|
395
|
+
let payload;
|
|
396
|
+
if (method !== "GET" && method !== "DELETE" && body !== void 0) {
|
|
397
|
+
if (typeof FormData !== "undefined" && body instanceof FormData) {
|
|
398
|
+
payload = body;
|
|
399
|
+
} else if (body instanceof Blob) {
|
|
400
|
+
payload = body;
|
|
401
|
+
} else {
|
|
402
|
+
headers["Content-Type"] = "application/json";
|
|
403
|
+
payload = JSON.stringify(body);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const res = await fetch(url, {
|
|
407
|
+
method,
|
|
408
|
+
headers,
|
|
409
|
+
body: payload,
|
|
410
|
+
cache: "no-store"
|
|
411
|
+
});
|
|
412
|
+
if (!res.ok) {
|
|
413
|
+
const text = await res.text().catch(() => "");
|
|
414
|
+
throw new Error(text || `Request failed: ${res.status}`);
|
|
415
|
+
}
|
|
416
|
+
const contentType = res.headers.get("content-type") || "";
|
|
417
|
+
if (!contentType.includes("application/json")) {
|
|
418
|
+
return await res.text();
|
|
419
|
+
}
|
|
420
|
+
return await res.json();
|
|
421
|
+
};
|
|
422
|
+
var slapiApi = {
|
|
423
|
+
get: async () => {
|
|
424
|
+
throw new Error("slapiApi is not configured. Call registerApi(...) first.");
|
|
425
|
+
},
|
|
426
|
+
post: async () => {
|
|
427
|
+
throw new Error("slapiApi is not configured. Call registerApi(...) first.");
|
|
428
|
+
},
|
|
429
|
+
put: async () => {
|
|
430
|
+
throw new Error("slapiApi is not configured. Call registerApi(...) first.");
|
|
431
|
+
},
|
|
432
|
+
patch: async () => {
|
|
433
|
+
throw new Error("slapiApi is not configured. Call registerApi(...) first.");
|
|
434
|
+
},
|
|
435
|
+
delete: async () => {
|
|
436
|
+
throw new Error("slapiApi is not configured. Call registerApi(...) first.");
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
var registerApi = (config2) => {
|
|
440
|
+
cfg.baseUrl = config2.baseUrl;
|
|
441
|
+
cfg.accessToken = config2.accessToken;
|
|
442
|
+
cfg.tenantId = config2.tenantId;
|
|
443
|
+
slapiApi = {
|
|
444
|
+
get: async (key) => {
|
|
445
|
+
const url = buildUrl(key);
|
|
446
|
+
return request("GET", url);
|
|
447
|
+
},
|
|
448
|
+
post: async (key, body) => {
|
|
449
|
+
const url = buildUrl(key);
|
|
450
|
+
return request("POST", url, body);
|
|
451
|
+
},
|
|
452
|
+
put: async (key, body) => {
|
|
453
|
+
const url = buildUrl(key);
|
|
454
|
+
return request("PUT", url, body);
|
|
455
|
+
},
|
|
456
|
+
patch: async (key, body) => {
|
|
457
|
+
const url = buildUrl(key);
|
|
458
|
+
return request("PATCH", url, body);
|
|
459
|
+
},
|
|
460
|
+
delete: async (key) => {
|
|
461
|
+
const url = buildUrl(key);
|
|
462
|
+
return request("DELETE", url);
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
return (key) => slapiApi.get(key);
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// src/hooks/useSpreePayConfig.ts
|
|
469
|
+
import useSWR from "swr";
|
|
470
|
+
var useSpreePayConfig = () => {
|
|
471
|
+
const { data, isLoading } = useSWR("/v1/tenants/configs/spree-pay");
|
|
472
|
+
return {
|
|
473
|
+
spreePayConfig: data ? {
|
|
474
|
+
...data,
|
|
475
|
+
rainbowProjectId: data.rainbowProjectId ?? "3fdcd5ff50cb84917cd05e40146975d8",
|
|
476
|
+
rainbowAppName: data.rainbowAppName ?? "AIR Shop",
|
|
477
|
+
pointsTitle: data.pointsTitle ?? "AIR SP",
|
|
478
|
+
pointsConversionRatio: data.pointsConversionRatio ?? 0.01,
|
|
479
|
+
crypto: {
|
|
480
|
+
...data.crypto,
|
|
481
|
+
oneInchAggregationRouter: data.crypto?.oneInchAggregationRouter || "0x111111125421ca6dc452d289314280a0f8842a65"
|
|
482
|
+
}
|
|
483
|
+
} : null,
|
|
484
|
+
configIsLoading: isLoading
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// src/components/common/InfoBanner.tsx
|
|
489
|
+
import xss from "xss";
|
|
490
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
491
|
+
var InfoBanner = (props) => {
|
|
492
|
+
const { type = "info", message } = props;
|
|
493
|
+
if (!message) return null;
|
|
494
|
+
return /* @__PURE__ */ jsxs(
|
|
495
|
+
"div",
|
|
496
|
+
{
|
|
497
|
+
className: cn("flex w-full gap-1.5 rounded-md p-2", {
|
|
498
|
+
"border border-(--b-secondary)": type === "info",
|
|
499
|
+
"bg-(--s-warning)/10": type === "warning"
|
|
500
|
+
}),
|
|
501
|
+
children: [
|
|
502
|
+
type === "info" && /* @__PURE__ */ jsx3(
|
|
503
|
+
"svg",
|
|
504
|
+
{
|
|
505
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
506
|
+
fill: "none",
|
|
507
|
+
viewBox: "0 0 20 20",
|
|
508
|
+
className: "size-5 shrink-0 text-(--positive)",
|
|
509
|
+
children: /* @__PURE__ */ jsx3(
|
|
510
|
+
"path",
|
|
511
|
+
{
|
|
512
|
+
fill: "currentColor",
|
|
513
|
+
d: "M10 17.92a2.2 2.2 0 0 1-1.59-.66 4 4 0 0 0-1.07-.81q-.45-.2-1.35-.2-.94 0-1.6-.65a2.2 2.2 0 0 1-.65-1.59q0-.9-.19-1.34a4 4 0 0 0-.8-1.08 2.2 2.2 0 0 1-.5-2.44q.17-.41.5-.74.6-.62.8-1.07t.2-1.35q0-.94.65-1.6.65-.65 1.59-.65.9 0 1.34-.19.46-.2 1.08-.81A2.2 2.2 0 0 1 10 2.08a2.3 2.3 0 0 1 1.59.66q.62.62 1.07.81t1.35.2q.94 0 1.6.65.65.64.65 1.59 0 .9.19 1.34.2.46.81 1.08a2.2 2.2 0 0 1 .66 1.59 2.2 2.2 0 0 1-.66 1.59q-.61.63-.81 1.07t-.2 1.35q0 .94-.65 1.6-.64.65-1.59.65-.9 0-1.34.19-.45.2-1.08.8a2.2 2.2 0 0 1-1.59.67m0-1.25q.2 0 .39-.08a1 1 0 0 0 .31-.21q.8-.8 1.5-1.09.7-.28 1.81-.28.42 0 .71-.29.3-.29.29-.7 0-1.13.28-1.82.3-.7 1.08-1.5.3-.3.3-.7t-.3-.7a5 5 0 0 1-1.08-1.5 5 5 0 0 1-.28-1.8q0-.42-.29-.71a1 1 0 0 0-.7-.29q-1.14 0-1.83-.28a5 5 0 0 1-1.5-1.08 1 1 0 0 0-.69-.3 1 1 0 0 0-.7.3q-.8.8-1.5 1.08T6 4.99q-.42 0-.71.29a1 1 0 0 0-.29.7q0 1.14-.28 1.83t-1.09 1.5q-.29.28-.29.69t.3.7q.8.8 1.08 1.5T5 14.01q0 .42.29.71.29.3.7.29 1.14 0 1.83.28t1.5 1.09a1 1 0 0 0 .7.29m2.03-3.62q.43 0 .73-.3t.3-.72a1 1 0 0 0-.3-.73 1 1 0 0 0-.73-.3 1 1 0 0 0-.73.3 1 1 0 0 0-.3.73q0 .43.3.73t.73.3m-4.53-.54q.18.18.43.18a.6.6 0 0 0 .43-.18l4.14-4.12a.6.6 0 0 0 .2-.44.6.6 0 0 0-.2-.45.6.6 0 0 0-.44-.2.6.6 0 0 0-.45.2l-4.12 4.14a.6.6 0 0 0-.18.43q0 .25.19.44M7.97 9a1 1 0 0 0 .74-.3 1 1 0 0 0 .3-.74q0-.43-.3-.73a1 1 0 0 0-.74-.3q-.43 0-.73.3t-.3.73.3.73.73.3"
|
|
514
|
+
}
|
|
515
|
+
)
|
|
516
|
+
}
|
|
517
|
+
),
|
|
518
|
+
type === "warning" && /* @__PURE__ */ jsx3(
|
|
519
|
+
"svg",
|
|
520
|
+
{
|
|
521
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
522
|
+
fill: "none",
|
|
523
|
+
viewBox: "0 0 20 20",
|
|
524
|
+
className: "size-5 shrink-0 text-(--warning)",
|
|
525
|
+
children: /* @__PURE__ */ jsx3(
|
|
526
|
+
"path",
|
|
527
|
+
{
|
|
528
|
+
fill: "currentColor",
|
|
529
|
+
d: "M10 13.96a.6.6 0 0 0 .44-.18.6.6 0 0 0 .18-.45V9.8a.6.6 0 0 0-.18-.44.6.6 0 0 0-.44-.18.6.6 0 0 0-.45.18.6.6 0 0 0-.18.44v3.54q0 .27.18.45a.6.6 0 0 0 .45.18m0-6.22q.29 0 .48-.2.2-.18.2-.47 0-.3-.2-.48a.7.7 0 0 0-.48-.2q-.3 0-.48.2a.7.7 0 0 0-.2.48q0 .29.2.48.2.2.48.19m0 10.18q-1.64 0-3.09-.63a8 8 0 0 1-4.2-4.2 8 8 0 0 1-.63-3.1q0-1.64.63-3.09a8 8 0 0 1 4.2-4.2q1.45-.63 3.09-.63 1.65 0 3.08.63a8 8 0 0 1 4.21 4.2q.63 1.45.63 3.09t-.63 3.09a8 8 0 0 1-4.2 4.2q-1.46.63-3.09.63m0-1.25q2.8 0 4.73-1.94A6.4 6.4 0 0 0 16.67 10q0-2.8-1.94-4.73A6.4 6.4 0 0 0 10 3.33q-2.8 0-4.73 1.94A6.4 6.4 0 0 0 3.33 10q0 2.8 1.94 4.73A6.4 6.4 0 0 0 10 16.67"
|
|
530
|
+
}
|
|
531
|
+
)
|
|
532
|
+
}
|
|
533
|
+
),
|
|
534
|
+
/* @__PURE__ */ jsx3(
|
|
535
|
+
"p",
|
|
536
|
+
{
|
|
537
|
+
className: "text-[14px] leading-5 text-(--primary) [&_a]:underline",
|
|
538
|
+
dangerouslySetInnerHTML: { __html: xss(message) }
|
|
539
|
+
}
|
|
540
|
+
)
|
|
541
|
+
]
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
// src/components/common/Legal.tsx
|
|
547
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
548
|
+
var Legal = () => {
|
|
549
|
+
const { spreePayConfig } = useSpreePayConfig();
|
|
550
|
+
return /* @__PURE__ */ jsxs2("p", { className: "text-center text-xs leading-5 font-medium text-(--secondary)", children: [
|
|
551
|
+
"By clicking on the button below I acknowledge that I have read and accepted the",
|
|
552
|
+
" ",
|
|
553
|
+
/* @__PURE__ */ jsx4("a", { className: "underline", href: spreePayConfig?.termsConditionsUrl, target: "_blank", rel: "noreferrer", children: "Terms and Conditions" }),
|
|
554
|
+
"."
|
|
555
|
+
] });
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
// src/services/slapi.ts
|
|
559
|
+
var slapiLogger = logger.child("slapi");
|
|
560
|
+
var SlapiPaymentService = {
|
|
561
|
+
createPayment: async ({ capture = false, ...rest }) => {
|
|
562
|
+
slapiLogger.debug("Creating payment", {
|
|
563
|
+
type: rest.type,
|
|
564
|
+
hash: rest.hash,
|
|
565
|
+
capture
|
|
566
|
+
});
|
|
567
|
+
try {
|
|
568
|
+
const data = await slapiApi.post("/v1/payments", { ...rest, capture });
|
|
569
|
+
slapiLogger.info("Payment created successfully", {
|
|
570
|
+
paymentId: data.id,
|
|
571
|
+
status: data.status,
|
|
572
|
+
txId: data.txId
|
|
573
|
+
});
|
|
574
|
+
return { data };
|
|
575
|
+
} catch (error) {
|
|
576
|
+
slapiLogger.error("Failed to create payment", error, {
|
|
577
|
+
type: rest.type,
|
|
578
|
+
hash: rest.hash
|
|
579
|
+
});
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
baseVerify: async ({ id, txHash }) => {
|
|
584
|
+
slapiLogger.debug("Verifying base transaction", { id, txHash });
|
|
585
|
+
try {
|
|
586
|
+
const result = await slapiApi.post(`/v1/base-transactions/transactions/${id}/verify`, {
|
|
587
|
+
txHash
|
|
588
|
+
});
|
|
589
|
+
slapiLogger.info("Base transaction verified", {
|
|
590
|
+
id,
|
|
591
|
+
txHash,
|
|
592
|
+
verified: result.verified
|
|
593
|
+
});
|
|
594
|
+
return result;
|
|
595
|
+
} catch (error) {
|
|
596
|
+
slapiLogger.error("Base transaction verification failed", error, {
|
|
597
|
+
id,
|
|
598
|
+
txHash
|
|
599
|
+
});
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
addCard: async ({ source, hash }) => {
|
|
604
|
+
slapiLogger.debug("Adding card", { hash, sourcePrefix: source.substring(0, 10) });
|
|
605
|
+
try {
|
|
606
|
+
const data = await slapiApi.post("/v1/payments/cards", { hash, source });
|
|
607
|
+
slapiLogger.info("Card added successfully", { cardId: data.id, hash });
|
|
608
|
+
return { data };
|
|
609
|
+
} catch (error) {
|
|
610
|
+
slapiLogger.error("Failed to add card", error, { hash });
|
|
611
|
+
throw error;
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
validate3DS: async ({ paymentId }) => {
|
|
615
|
+
slapiLogger.debug("Validating 3DS", { paymentId });
|
|
616
|
+
try {
|
|
617
|
+
const data = await slapiApi.post("/v1/payments/validate", {
|
|
618
|
+
paymentId,
|
|
619
|
+
type: "CREDIT_CARD" /* CREDIT_CARD */
|
|
620
|
+
});
|
|
621
|
+
slapiLogger.info("3DS validated successfully", {
|
|
622
|
+
paymentId,
|
|
623
|
+
status: data.status
|
|
624
|
+
});
|
|
625
|
+
return { data };
|
|
626
|
+
} catch (error) {
|
|
627
|
+
slapiLogger.error("3DS validation failed", error, { paymentId });
|
|
628
|
+
throw error;
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
validateCDC: async ({ paymentId }) => {
|
|
632
|
+
slapiLogger.debug("Validating CDC payment", { paymentId });
|
|
633
|
+
try {
|
|
634
|
+
const data = await slapiApi.post("/v1/payments/validate", {
|
|
635
|
+
paymentId,
|
|
636
|
+
type: "CDC" /* CDC */
|
|
637
|
+
});
|
|
638
|
+
slapiLogger.info("CDC payment validated successfully", {
|
|
639
|
+
paymentId,
|
|
640
|
+
status: data.status
|
|
641
|
+
});
|
|
642
|
+
return { data };
|
|
643
|
+
} catch (error) {
|
|
644
|
+
slapiLogger.error("CDC payment validation failed", error, {
|
|
645
|
+
paymentId
|
|
646
|
+
});
|
|
647
|
+
throw error;
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
validatePoints: async ({ paymentId, txHash }) => {
|
|
651
|
+
slapiLogger.debug("Validating points payment", { paymentId, txHash });
|
|
652
|
+
try {
|
|
653
|
+
const data = await slapiApi.post("/v1/payments/validate", {
|
|
654
|
+
txHash,
|
|
655
|
+
paymentId,
|
|
656
|
+
type: "POINTS" /* POINTS */
|
|
657
|
+
});
|
|
658
|
+
slapiLogger.info("Points payment validated successfully", {
|
|
659
|
+
paymentId,
|
|
660
|
+
status: data.status,
|
|
661
|
+
txHash
|
|
662
|
+
});
|
|
663
|
+
return { data };
|
|
664
|
+
} catch (error) {
|
|
665
|
+
slapiLogger.error("Points payment validation failed", error, {
|
|
666
|
+
paymentId,
|
|
667
|
+
txHash
|
|
668
|
+
});
|
|
669
|
+
throw error;
|
|
670
|
+
}
|
|
671
|
+
},
|
|
672
|
+
getStatus: async (paymentId) => {
|
|
673
|
+
slapiLogger.debug("Getting payment status", { paymentId });
|
|
674
|
+
try {
|
|
675
|
+
const result = await slapiApi.get(`/v1/payments/${paymentId}/status`);
|
|
676
|
+
slapiLogger.debug("Payment status retrieved", {
|
|
677
|
+
paymentId,
|
|
678
|
+
status: result.detail.status
|
|
679
|
+
});
|
|
680
|
+
return result;
|
|
681
|
+
} catch (error) {
|
|
682
|
+
slapiLogger.error("Failed to get payment status", error, {
|
|
683
|
+
paymentId
|
|
684
|
+
});
|
|
685
|
+
throw error;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
// src/ui/dialog.tsx
|
|
691
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
692
|
+
import { XIcon } from "lucide-react";
|
|
693
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
694
|
+
function Dialog({ ...props }) {
|
|
695
|
+
return /* @__PURE__ */ jsx5(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
696
|
+
}
|
|
697
|
+
function DialogPortal({ ...props }) {
|
|
698
|
+
const container = usePortalContainer();
|
|
699
|
+
const safeContainer = container && document.body.contains(container) ? container : void 0;
|
|
700
|
+
return /* @__PURE__ */ jsx5(DialogPrimitive.Portal, { container: safeContainer, "data-slot": "dialog-portal", ...props });
|
|
701
|
+
}
|
|
702
|
+
function DialogOverlay({ className, ...props }) {
|
|
703
|
+
return /* @__PURE__ */ jsx5(
|
|
704
|
+
DialogPrimitive.Overlay,
|
|
705
|
+
{
|
|
706
|
+
"data-slot": "dialog-overlay",
|
|
707
|
+
className: cn(
|
|
708
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-(--overlay)",
|
|
709
|
+
className
|
|
710
|
+
),
|
|
711
|
+
...props
|
|
712
|
+
}
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
function DialogContent({
|
|
716
|
+
className,
|
|
717
|
+
children,
|
|
718
|
+
showCloseButton = true,
|
|
719
|
+
...props
|
|
720
|
+
}) {
|
|
721
|
+
return /* @__PURE__ */ jsxs3(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
722
|
+
/* @__PURE__ */ jsx5(DialogOverlay, {}),
|
|
723
|
+
/* @__PURE__ */ jsxs3(
|
|
724
|
+
DialogPrimitive.Content,
|
|
725
|
+
{
|
|
726
|
+
"data-slot": "dialog-content",
|
|
727
|
+
className: cn(
|
|
728
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-(--border-component-specific-card) bg-(--surface-component-specific-card-default-card) p-6 shadow-lg duration-200 sm:max-w-lg",
|
|
729
|
+
className
|
|
730
|
+
),
|
|
731
|
+
...props,
|
|
732
|
+
children: [
|
|
733
|
+
children,
|
|
734
|
+
showCloseButton && /* @__PURE__ */ jsxs3(
|
|
735
|
+
DialogPrimitive.Close,
|
|
736
|
+
{
|
|
737
|
+
"data-slot": "dialog-close",
|
|
738
|
+
className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-(--accent) data-[state=open]:text-(--secondary) [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
739
|
+
children: [
|
|
740
|
+
/* @__PURE__ */ jsx5(XIcon, {}),
|
|
741
|
+
/* @__PURE__ */ jsx5("span", { className: "sr-only", children: "Close" })
|
|
742
|
+
]
|
|
743
|
+
}
|
|
744
|
+
)
|
|
745
|
+
]
|
|
746
|
+
}
|
|
747
|
+
)
|
|
748
|
+
] });
|
|
749
|
+
}
|
|
750
|
+
function DialogTitle({ className, ...props }) {
|
|
751
|
+
return /* @__PURE__ */ jsx5(
|
|
752
|
+
DialogPrimitive.Title,
|
|
753
|
+
{
|
|
754
|
+
"data-slot": "dialog-title",
|
|
755
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
756
|
+
...props
|
|
757
|
+
}
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
function DialogDescription({ className, ...props }) {
|
|
761
|
+
return /* @__PURE__ */ jsx5(
|
|
762
|
+
DialogPrimitive.Description,
|
|
763
|
+
{
|
|
764
|
+
"data-slot": "dialog-description",
|
|
765
|
+
className: cn("text-sm text-(--secondary)", className),
|
|
766
|
+
...props
|
|
767
|
+
}
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
export {
|
|
772
|
+
PaymentError,
|
|
773
|
+
PaymentType,
|
|
774
|
+
LogLevel,
|
|
775
|
+
logger,
|
|
776
|
+
configureLogger,
|
|
777
|
+
SpreePayProvider,
|
|
778
|
+
useSpreePay,
|
|
779
|
+
useSpreePaymentMethod,
|
|
780
|
+
useSpreePayEnv,
|
|
781
|
+
useSpreePayRegister,
|
|
782
|
+
StaticConfigProvider,
|
|
783
|
+
useStaticConfig,
|
|
784
|
+
cn,
|
|
785
|
+
PortalContainerProvider,
|
|
786
|
+
Dialog,
|
|
787
|
+
DialogContent,
|
|
788
|
+
DialogTitle,
|
|
789
|
+
DialogDescription,
|
|
790
|
+
registerApi,
|
|
791
|
+
SlapiPaymentService,
|
|
792
|
+
useSpreePayConfig,
|
|
793
|
+
InfoBanner,
|
|
794
|
+
Legal
|
|
795
|
+
};
|