@youidian/sdk 3.0.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/dist/client.cjs +263 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +103 -0
- package/dist/client.d.ts +103 -0
- package/dist/client.js +237 -0
- package/dist/client.js.map +1 -0
- package/dist/hosted-modal-BZmYmXTU.d.cts +20 -0
- package/dist/hosted-modal-BZmYmXTU.d.ts +20 -0
- package/dist/index.cjs +823 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +784 -0
- package/dist/index.js.map +1 -0
- package/dist/login.cjs +358 -0
- package/dist/login.cjs.map +1 -0
- package/dist/login.d.cts +62 -0
- package/dist/login.d.ts +62 -0
- package/dist/login.js +332 -0
- package/dist/login.js.map +1 -0
- package/dist/server.cjs +279 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +385 -0
- package/dist/server.d.ts +385 -0
- package/dist/server.js +246 -0
- package/dist/server.js.map +1 -0
- package/package.json +57 -0
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
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 __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
21
|
+
|
|
22
|
+
// src/client.ts
|
|
23
|
+
var client_exports = {};
|
|
24
|
+
__export(client_exports, {
|
|
25
|
+
PaymentUI: () => PaymentUI,
|
|
26
|
+
createPaymentUI: () => createPaymentUI
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(client_exports);
|
|
29
|
+
|
|
30
|
+
// src/hosted-modal.ts
|
|
31
|
+
function applyLocaleToUrl(urlValue, locale) {
|
|
32
|
+
if (!locale) return urlValue;
|
|
33
|
+
try {
|
|
34
|
+
const url = new URL(urlValue);
|
|
35
|
+
const localePrefix = `/${locale}`;
|
|
36
|
+
if (!url.pathname.startsWith(`${localePrefix}/`) && url.pathname !== localePrefix) {
|
|
37
|
+
url.pathname = `${localePrefix}${url.pathname}`;
|
|
38
|
+
}
|
|
39
|
+
return url.toString();
|
|
40
|
+
} catch (_error) {
|
|
41
|
+
const localePrefix = `/${locale}`;
|
|
42
|
+
if (!urlValue.startsWith(`${localePrefix}/`) && urlValue !== localePrefix) {
|
|
43
|
+
return `${localePrefix}${urlValue.startsWith("/") ? "" : "/"}${urlValue}`;
|
|
44
|
+
}
|
|
45
|
+
return urlValue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
var HostedFrameModal = class {
|
|
49
|
+
constructor() {
|
|
50
|
+
__publicField(this, "iframe", null);
|
|
51
|
+
__publicField(this, "modal", null);
|
|
52
|
+
__publicField(this, "messageHandler", null);
|
|
53
|
+
}
|
|
54
|
+
openHostedFrame(url, options) {
|
|
55
|
+
if (typeof document === "undefined") return;
|
|
56
|
+
if (this.modal) return;
|
|
57
|
+
this.modal = document.createElement("div");
|
|
58
|
+
Object.assign(this.modal.style, {
|
|
59
|
+
position: "fixed",
|
|
60
|
+
top: "0",
|
|
61
|
+
left: "0",
|
|
62
|
+
width: "100%",
|
|
63
|
+
height: "100%",
|
|
64
|
+
backgroundColor: "rgba(15,23,42,0.52)",
|
|
65
|
+
display: "flex",
|
|
66
|
+
alignItems: "center",
|
|
67
|
+
justifyContent: "center",
|
|
68
|
+
zIndex: "9999",
|
|
69
|
+
transition: "opacity 0.3s ease",
|
|
70
|
+
backdropFilter: "blur(14px)",
|
|
71
|
+
padding: "16px"
|
|
72
|
+
});
|
|
73
|
+
const container = document.createElement("div");
|
|
74
|
+
Object.assign(container.style, {
|
|
75
|
+
width: options.width || "450px",
|
|
76
|
+
height: options.height || "min(600px, 90vh)",
|
|
77
|
+
backgroundColor: "transparent",
|
|
78
|
+
borderRadius: "28px",
|
|
79
|
+
overflow: "visible",
|
|
80
|
+
position: "relative",
|
|
81
|
+
boxShadow: "none",
|
|
82
|
+
maxWidth: "calc(100vw - 32px)",
|
|
83
|
+
maxHeight: "calc(100vh - 32px)",
|
|
84
|
+
transition: "height 180ms ease",
|
|
85
|
+
willChange: "height"
|
|
86
|
+
});
|
|
87
|
+
const closeBtn = document.createElement("button");
|
|
88
|
+
closeBtn.innerHTML = "\xD7";
|
|
89
|
+
Object.assign(closeBtn.style, {
|
|
90
|
+
position: "absolute",
|
|
91
|
+
right: "-14px",
|
|
92
|
+
top: "-14px",
|
|
93
|
+
fontSize: "20px",
|
|
94
|
+
width: "36px",
|
|
95
|
+
height: "36px",
|
|
96
|
+
borderRadius: "9999px",
|
|
97
|
+
border: "1px solid rgba(255,255,255,0.5)",
|
|
98
|
+
background: "rgba(255,255,255,0.9)",
|
|
99
|
+
cursor: "pointer",
|
|
100
|
+
color: "#475569",
|
|
101
|
+
zIndex: "2",
|
|
102
|
+
boxShadow: "0 10px 30px rgba(15,23,42,0.16)"
|
|
103
|
+
});
|
|
104
|
+
closeBtn.onclick = () => {
|
|
105
|
+
this.close();
|
|
106
|
+
options.onCloseButton?.();
|
|
107
|
+
};
|
|
108
|
+
this.iframe = document.createElement("iframe");
|
|
109
|
+
this.iframe.src = url;
|
|
110
|
+
Object.assign(this.iframe.style, {
|
|
111
|
+
width: "100%",
|
|
112
|
+
height: "100%",
|
|
113
|
+
border: "none",
|
|
114
|
+
borderRadius: "28px",
|
|
115
|
+
background: "transparent",
|
|
116
|
+
display: "block"
|
|
117
|
+
});
|
|
118
|
+
container.appendChild(closeBtn);
|
|
119
|
+
container.appendChild(this.iframe);
|
|
120
|
+
this.modal.appendChild(container);
|
|
121
|
+
document.body.appendChild(this.modal);
|
|
122
|
+
this.messageHandler = (event) => {
|
|
123
|
+
if (options.allowedOrigin && options.allowedOrigin !== "*") {
|
|
124
|
+
if (event.origin !== options.allowedOrigin) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const data = event.data;
|
|
129
|
+
if (!data || typeof data !== "object" || !data.type) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
options.onMessage(data, container);
|
|
133
|
+
};
|
|
134
|
+
window.addEventListener("message", this.messageHandler);
|
|
135
|
+
}
|
|
136
|
+
close() {
|
|
137
|
+
if (typeof window === "undefined") return;
|
|
138
|
+
if (this.messageHandler) {
|
|
139
|
+
window.removeEventListener("message", this.messageHandler);
|
|
140
|
+
this.messageHandler = null;
|
|
141
|
+
}
|
|
142
|
+
if (this.modal?.parentNode) {
|
|
143
|
+
this.modal.parentNode.removeChild(this.modal);
|
|
144
|
+
}
|
|
145
|
+
this.modal = null;
|
|
146
|
+
this.iframe = null;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// src/client.ts
|
|
151
|
+
var PaymentUI = class extends HostedFrameModal {
|
|
152
|
+
/**
|
|
153
|
+
* Opens the payment checkout page in an iframe modal.
|
|
154
|
+
* @param urlOrParams - The checkout page URL or payment parameters
|
|
155
|
+
* @param options - UI options
|
|
156
|
+
*/
|
|
157
|
+
openPayment(urlOrParams, options) {
|
|
158
|
+
if (typeof document === "undefined") return;
|
|
159
|
+
if (this.modal) return;
|
|
160
|
+
let checkoutUrl;
|
|
161
|
+
if (typeof urlOrParams === "string") {
|
|
162
|
+
checkoutUrl = urlOrParams;
|
|
163
|
+
} else {
|
|
164
|
+
const {
|
|
165
|
+
appId,
|
|
166
|
+
productId,
|
|
167
|
+
priceId,
|
|
168
|
+
productCode,
|
|
169
|
+
userId,
|
|
170
|
+
checkoutUrl: checkoutUrlParam,
|
|
171
|
+
baseUrl = "https://pay.imgto.link"
|
|
172
|
+
} = urlOrParams;
|
|
173
|
+
const base = (checkoutUrlParam || baseUrl).replace(/\/$/, "");
|
|
174
|
+
if (productCode) {
|
|
175
|
+
checkoutUrl = `${base}/checkout/${appId}/code/${productCode}?userId=${encodeURIComponent(userId)}`;
|
|
176
|
+
} else if (productId && priceId) {
|
|
177
|
+
checkoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?userId=${encodeURIComponent(userId)}`;
|
|
178
|
+
} else {
|
|
179
|
+
throw new Error(
|
|
180
|
+
"Either productCode or both productId and priceId are required"
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const finalUrl = applyLocaleToUrl(checkoutUrl, options?.locale);
|
|
185
|
+
this.openHostedFrame(finalUrl, {
|
|
186
|
+
allowedOrigin: options?.allowedOrigin,
|
|
187
|
+
onCloseButton: () => options?.onCancel?.(),
|
|
188
|
+
onMessage: (data, container) => {
|
|
189
|
+
switch (data.type) {
|
|
190
|
+
case "PAYMENT_SUCCESS":
|
|
191
|
+
options?.onSuccess?.(data.orderId);
|
|
192
|
+
break;
|
|
193
|
+
case "PAYMENT_CANCELLED":
|
|
194
|
+
options?.onCancel?.(data.orderId);
|
|
195
|
+
break;
|
|
196
|
+
case "PAYMENT_RESIZE":
|
|
197
|
+
if (data.height) {
|
|
198
|
+
const maxHeight = window.innerHeight * 0.9;
|
|
199
|
+
const newHeight = Math.min(data.height, maxHeight);
|
|
200
|
+
container.style.height = `${newHeight}px`;
|
|
201
|
+
}
|
|
202
|
+
break;
|
|
203
|
+
case "PAYMENT_CLOSE":
|
|
204
|
+
this.close();
|
|
205
|
+
options?.onClose?.();
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Poll order status from integrator's API endpoint
|
|
213
|
+
* @param statusUrl - The integrator's API endpoint to check order status
|
|
214
|
+
* @param options - Polling options
|
|
215
|
+
* @returns Promise that resolves when order is paid or rejects on timeout/failure
|
|
216
|
+
*/
|
|
217
|
+
async pollOrderStatus(statusUrl, options) {
|
|
218
|
+
const interval = options?.interval || 3e3;
|
|
219
|
+
const timeout = options?.timeout || 3e5;
|
|
220
|
+
const startTime = Date.now();
|
|
221
|
+
return new Promise((resolve, reject) => {
|
|
222
|
+
const poll = async () => {
|
|
223
|
+
try {
|
|
224
|
+
const response = await fetch(statusUrl);
|
|
225
|
+
if (!response.ok) {
|
|
226
|
+
throw new Error(`Status check failed: ${response.status}`);
|
|
227
|
+
}
|
|
228
|
+
const status = await response.json();
|
|
229
|
+
options?.onStatusChange?.(status);
|
|
230
|
+
if (status.status === "PAID") {
|
|
231
|
+
resolve(status);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (status.status === "CANCELLED" || status.status === "FAILED") {
|
|
235
|
+
reject(new Error(`Order ${status.status.toLowerCase()}`));
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (Date.now() - startTime > timeout) {
|
|
239
|
+
reject(new Error("Polling timeout"));
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
setTimeout(poll, interval);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
if (Date.now() - startTime > timeout) {
|
|
245
|
+
reject(error);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
setTimeout(poll, interval);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
poll();
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
function createPaymentUI() {
|
|
256
|
+
return new PaymentUI();
|
|
257
|
+
}
|
|
258
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
259
|
+
0 && (module.exports = {
|
|
260
|
+
PaymentUI,
|
|
261
|
+
createPaymentUI
|
|
262
|
+
});
|
|
263
|
+
//# sourceMappingURL=client.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/hosted-modal.ts"],"sourcesContent":["/**\n * Youidian Payment SDK - Client Module\n * 用于浏览器端集成,包含支付弹窗、状态轮询等功能\n * 不依赖 Node.js crypto 模块\n */\n\nimport { applyLocaleToUrl, HostedFrameModal } from \"./hosted-modal\"\n\n/**\n * Payment event types from checkout pages\n */\nexport type PaymentEventType =\n\t| \"PAYMENT_SUCCESS\"\n\t| \"PAYMENT_CANCELLED\"\n\t| \"PAYMENT_CLOSE\"\n\t| \"PAYMENT_RESIZE\"\n\n/**\n * Payment event data from postMessage\n */\nexport interface PaymentEventData {\n\ttype: PaymentEventType\n\torderId?: string\n\theight?: number\n}\n\n/**\n * Order status response\n */\nexport interface OrderStatus {\n\torderId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\n/**\n * Payment UI Options\n */\nexport interface PaymentUIOptions {\n\tlocale?: string\n\tonSuccess?: (orderId?: string) => void\n\tonCancel?: (orderId?: string) => void\n\tonClose?: () => void\n\t/** Origin to validate postMessage (defaults to '*', set for security) */\n\tallowedOrigin?: string\n}\n\n/**\n * Poll Options\n */\nexport interface PollOptions {\n\t/** Polling interval in ms (default: 3000) */\n\tinterval?: number\n\t/** Timeout in ms (default: 300000 = 5 minutes) */\n\ttimeout?: number\n\t/** Callback on each status check */\n\tonStatusChange?: (status: OrderStatus) => void\n}\n\n/**\n * Client-side Payment UI Helper\n * 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态\n */\n/**\n * Params for opening payment directly without manual URL construction\n */\nexport interface PaymentParams {\n\tappId: string\n\tuserId: string\n\t/** Product ID - use with priceId for direct ID-based payment */\n\tproductId?: string\n\t/** Price ID - use with productId for direct ID-based payment */\n\tpriceId?: string\n\t/** Product code - use with locale for code-based payment (alternative to productId/priceId) */\n\tproductCode?: string\n\n\t/**\n\t * @deprecated Use checkoutUrl instead\n\t * Defaults to https://pay.imgto.link\n\t */\n\tbaseUrl?: string\n\n\t/**\n\t * Checkout page URL (e.g. https://pay.youidian.com)\n\t * Defaults to https://pay.imgto.link\n\t */\n\tcheckoutUrl?: string\n}\n\n/**\n * Client-side Payment UI Helper\n * 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态\n */\nexport class PaymentUI extends HostedFrameModal<PaymentEventData> {\n\t/**\n\t * Opens the payment checkout page in an iframe modal.\n\t * @param urlOrParams - The checkout page URL or payment parameters\n\t * @param options - UI options\n\t */\n\topenPayment(urlOrParams: string | PaymentParams, options?: PaymentUIOptions) {\n\t\tif (typeof document === \"undefined\") return // Server-side guard\n\t\tif (this.modal) return // Prevent multiple modals\n\n\t\tlet checkoutUrl: string\n\t\tif (typeof urlOrParams === \"string\") {\n\t\t\tcheckoutUrl = urlOrParams\n\t\t} else {\n\t\t\tconst {\n\t\t\t\tappId,\n\t\t\t\tproductId,\n\t\t\t\tpriceId,\n\t\t\t\tproductCode,\n\t\t\t\tuserId,\n\t\t\t\tcheckoutUrl: checkoutUrlParam,\n\t\t\t\tbaseUrl = \"https://pay.imgto.link\",\n\t\t\t} = urlOrParams\n\n\t\t\t// 优先使用 checkoutUrl,其次 baseUrl,默认 https://pay.imgto.link\n\t\t\tconst base = (checkoutUrlParam || baseUrl).replace(/\\/$/, \"\")\n\n\t\t\tif (productCode) {\n\t\t\t\t// Use product code route\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/code/${productCode}?userId=${encodeURIComponent(userId)}`\n\t\t\t} else if (productId && priceId) {\n\t\t\t\t// Use ID-based route\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?userId=${encodeURIComponent(userId)}`\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Either productCode or both productId and priceId are required\",\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconst finalUrl = applyLocaleToUrl(checkoutUrl, options?.locale)\n\n\t\tthis.openHostedFrame(finalUrl, {\n\t\t\tallowedOrigin: options?.allowedOrigin,\n\t\t\tonCloseButton: () => options?.onCancel?.(),\n\t\t\tonMessage: (data, container) => {\n\t\t\t\tswitch (data.type) {\n\t\t\t\t\tcase \"PAYMENT_SUCCESS\":\n\t\t\t\t\t\toptions?.onSuccess?.(data.orderId)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_CANCELLED\":\n\t\t\t\t\t\toptions?.onCancel?.(data.orderId)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_RESIZE\":\n\t\t\t\t\t\tif (data.height) {\n\t\t\t\t\t\t\tconst maxHeight = window.innerHeight * 0.9\n\t\t\t\t\t\t\tconst newHeight = Math.min(data.height, maxHeight)\n\t\t\t\t\t\t\tcontainer.style.height = `${newHeight}px`\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_CLOSE\":\n\t\t\t\t\t\tthis.close()\n\t\t\t\t\t\toptions?.onClose?.()\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t}\n\n\t/**\n\t * Poll order status from integrator's API endpoint\n\t * @param statusUrl - The integrator's API endpoint to check order status\n\t * @param options - Polling options\n\t * @returns Promise that resolves when order is paid or rejects on timeout/failure\n\t */\n\tasync pollOrderStatus(\n\t\tstatusUrl: string,\n\t\toptions?: PollOptions,\n\t): Promise<OrderStatus> {\n\t\tconst interval = options?.interval || 3000\n\t\tconst timeout = options?.timeout || 300000\n\t\tconst startTime = Date.now()\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst poll = async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst response = await fetch(statusUrl)\n\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\tthrow new Error(`Status check failed: ${response.status}`)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst status: OrderStatus = await response.json()\n\t\t\t\t\toptions?.onStatusChange?.(status)\n\n\t\t\t\t\tif (status.status === \"PAID\") {\n\t\t\t\t\t\tresolve(status)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tif (status.status === \"CANCELLED\" || status.status === \"FAILED\") {\n\t\t\t\t\t\treject(new Error(`Order ${status.status.toLowerCase()}`))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(new Error(\"Polling timeout\"))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Continue polling\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// On network error, continue polling unless timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(error)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpoll()\n\t\t})\n\t}\n}\n\n/**\n * Convenience function to create a PaymentUI instance\n */\nexport function createPaymentUI(): PaymentUI {\n\treturn new PaymentUI()\n}\n","export interface HostedFrameMessage {\n\ttype: string\n\theight?: number\n}\n\ntype HostedFrameOptions<TData extends HostedFrameMessage> = {\n\tallowedOrigin?: string\n\theight?: string\n\tonCloseButton?: () => void\n\tonMessage: (data: TData, container: HTMLDivElement) => void\n\twidth?: string\n}\n\nconst SDK_SUPPORTED_LOCALES = [\n\t\"en\",\n\t\"zh-CN\",\n\t\"zh-Hant\",\n\t\"fr\",\n\t\"de\",\n\t\"ja\",\n\t\"es\",\n\t\"ko\",\n\t\"nl\",\n\t\"it\",\n\t\"pt\",\n] as const\n\nconst SDK_DEFAULT_LOCALE = \"zh-CN\"\n\nconst SDK_LOCALE_ALIASES: Record<string, string> = {\n\ten: \"en\",\n\t\"en-us\": \"en\",\n\t\"en-gb\": \"en\",\n\tzh: \"zh-CN\",\n\t\"zh-cn\": \"zh-CN\",\n\t\"zh-tw\": \"zh-Hant\",\n\t\"zh-hk\": \"zh-Hant\",\n\t\"zh-hant\": \"zh-Hant\",\n\t\"zh-hans\": \"zh-CN\",\n\tfr: \"fr\",\n\tde: \"de\",\n\tja: \"ja\",\n\tes: \"es\",\n\tko: \"ko\",\n\tnl: \"nl\",\n\tit: \"it\",\n\tpt: \"pt\",\n}\n\nfunction matchSupportedBaseLocale(locale: string): string | undefined {\n\tconst base = locale.toLowerCase().split(\"-\")[0]\n\treturn SDK_SUPPORTED_LOCALES.find((item) => item.toLowerCase() === base)\n}\n\nexport function normalizeSdkLocale(locale?: string): string | undefined {\n\tif (!locale) return\n\n\tconst sanitized = locale.trim().replace(/_/g, \"-\")\n\tif (!sanitized) return\n\n\tconst lower = sanitized.toLowerCase()\n\tif (SDK_LOCALE_ALIASES[lower]) {\n\t\treturn SDK_LOCALE_ALIASES[lower]\n\t}\n\n\tlet canonical: string | undefined\n\ttry {\n\t\tcanonical = Intl.getCanonicalLocales(sanitized)[0]\n\t} catch {\n\t\tcanonical = undefined\n\t}\n\n\tconst candidates = [canonical, sanitized].filter(Boolean) as string[]\n\n\tfor (const candidate of candidates) {\n\t\tconst candidateLower = candidate.toLowerCase()\n\n\t\tif (SDK_LOCALE_ALIASES[candidateLower]) {\n\t\t\treturn SDK_LOCALE_ALIASES[candidateLower]\n\t\t}\n\t\tif ((SDK_SUPPORTED_LOCALES as readonly string[]).includes(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\n\t\tconst baseMatch = matchSupportedBaseLocale(candidate)\n\t\tif (baseMatch) {\n\t\t\treturn baseMatch\n\t\t}\n\t}\n}\n\nexport function getBrowserLocale(): string | undefined {\n\tif (typeof navigator === \"undefined\") return\n\n\tfor (const candidate of navigator.languages || []) {\n\t\tconst normalized = normalizeSdkLocale(candidate)\n\t\tif (normalized) return normalized\n\t}\n\n\treturn normalizeSdkLocale(navigator.language)\n}\n\nexport function getAutoResolvedLocale(locale?: string): string {\n\treturn normalizeSdkLocale(locale) || getBrowserLocale() || SDK_DEFAULT_LOCALE\n}\n\nexport function applyLocaleToUrl(urlValue: string, locale?: string): string {\n\tif (!locale) return urlValue\n\n\ttry {\n\t\tconst url = new URL(urlValue)\n\t\tconst localePrefix = `/${locale}`\n\t\tif (\n\t\t\t!url.pathname.startsWith(`${localePrefix}/`) &&\n\t\t\turl.pathname !== localePrefix\n\t\t) {\n\t\t\turl.pathname = `${localePrefix}${url.pathname}`\n\t\t}\n\t\treturn url.toString()\n\t} catch (_error) {\n\t\tconst localePrefix = `/${locale}`\n\t\tif (!urlValue.startsWith(`${localePrefix}/`) && urlValue !== localePrefix) {\n\t\t\treturn `${localePrefix}${urlValue.startsWith(\"/\") ? \"\" : \"/\"}${urlValue}`\n\t\t}\n\t\treturn urlValue\n\t}\n}\n\nexport class HostedFrameModal<TData extends HostedFrameMessage> {\n\tprotected iframe: HTMLIFrameElement | null = null\n\tprotected modal: HTMLDivElement | null = null\n\tprotected messageHandler: ((event: MessageEvent) => void) | null = null\n\n\tprotected openHostedFrame(\n\t\turl: string,\n\t\toptions: HostedFrameOptions<TData>,\n\t): void {\n\t\tif (typeof document === \"undefined\") return\n\t\tif (this.modal) return\n\n\t\tthis.modal = document.createElement(\"div\")\n\t\tObject.assign(this.modal.style, {\n\t\t\tposition: \"fixed\",\n\t\t\ttop: \"0\",\n\t\t\tleft: \"0\",\n\t\t\twidth: \"100%\",\n\t\t\theight: \"100%\",\n\t\t\tbackgroundColor: \"rgba(15,23,42,0.52)\",\n\t\t\tdisplay: \"flex\",\n\t\t\talignItems: \"center\",\n\t\t\tjustifyContent: \"center\",\n\t\t\tzIndex: \"9999\",\n\t\t\ttransition: \"opacity 0.3s ease\",\n\t\t\tbackdropFilter: \"blur(14px)\",\n\t\t\tpadding: \"16px\",\n\t\t})\n\n\t\tconst container = document.createElement(\"div\")\n\t\tObject.assign(container.style, {\n\t\t\twidth: options.width || \"450px\",\n\t\t\theight: options.height || \"min(600px, 90vh)\",\n\t\t\tbackgroundColor: \"transparent\",\n\t\t\tborderRadius: \"28px\",\n\t\t\toverflow: \"visible\",\n\t\t\tposition: \"relative\",\n\t\t\tboxShadow: \"none\",\n\t\t\tmaxWidth: \"calc(100vw - 32px)\",\n\t\t\tmaxHeight: \"calc(100vh - 32px)\",\n\t\t\ttransition: \"height 180ms ease\",\n\t\t\twillChange: \"height\",\n\t\t})\n\n\t\tconst closeBtn = document.createElement(\"button\")\n\t\tcloseBtn.innerHTML = \"×\"\n\t\tObject.assign(closeBtn.style, {\n\t\t\tposition: \"absolute\",\n\t\t\tright: \"-14px\",\n\t\t\ttop: \"-14px\",\n\t\t\tfontSize: \"20px\",\n\t\t\twidth: \"36px\",\n\t\t\theight: \"36px\",\n\t\t\tborderRadius: \"9999px\",\n\t\t\tborder: \"1px solid rgba(255,255,255,0.5)\",\n\t\t\tbackground: \"rgba(255,255,255,0.9)\",\n\t\t\tcursor: \"pointer\",\n\t\t\tcolor: \"#475569\",\n\t\t\tzIndex: \"2\",\n\t\t\tboxShadow: \"0 10px 30px rgba(15,23,42,0.16)\",\n\t\t})\n\t\tcloseBtn.onclick = () => {\n\t\t\tthis.close()\n\t\t\toptions.onCloseButton?.()\n\t\t}\n\n\t\tthis.iframe = document.createElement(\"iframe\")\n\t\tthis.iframe.src = url\n\t\tObject.assign(this.iframe.style, {\n\t\t\twidth: \"100%\",\n\t\t\theight: \"100%\",\n\t\t\tborder: \"none\",\n\t\t\tborderRadius: \"28px\",\n\t\t\tbackground: \"transparent\",\n\t\t\tdisplay: \"block\",\n\t\t})\n\n\t\tcontainer.appendChild(closeBtn)\n\t\tcontainer.appendChild(this.iframe)\n\t\tthis.modal.appendChild(container)\n\t\tdocument.body.appendChild(this.modal)\n\n\t\tthis.messageHandler = (event: MessageEvent) => {\n\t\t\tif (options.allowedOrigin && options.allowedOrigin !== \"*\") {\n\t\t\t\tif (event.origin !== options.allowedOrigin) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst data = event.data as TData\n\t\t\tif (!data || typeof data !== \"object\" || !data.type) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\toptions.onMessage(data, container)\n\t\t}\n\n\t\twindow.addEventListener(\"message\", this.messageHandler)\n\t}\n\n\tclose() {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tif (this.messageHandler) {\n\t\t\twindow.removeEventListener(\"message\", this.messageHandler)\n\t\t\tthis.messageHandler = null\n\t\t}\n\n\t\tif (this.modal?.parentNode) {\n\t\t\tthis.modal.parentNode.removeChild(this.modal)\n\t\t}\n\n\t\tthis.modal = null\n\t\tthis.iframe = null\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { H as HostedFrameModal } from './hosted-modal-BZmYmXTU.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Youidian Payment SDK - Client Module
|
|
5
|
+
* 用于浏览器端集成,包含支付弹窗、状态轮询等功能
|
|
6
|
+
* 不依赖 Node.js crypto 模块
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Payment event types from checkout pages
|
|
11
|
+
*/
|
|
12
|
+
type PaymentEventType = "PAYMENT_SUCCESS" | "PAYMENT_CANCELLED" | "PAYMENT_CLOSE" | "PAYMENT_RESIZE";
|
|
13
|
+
/**
|
|
14
|
+
* Payment event data from postMessage
|
|
15
|
+
*/
|
|
16
|
+
interface PaymentEventData {
|
|
17
|
+
type: PaymentEventType;
|
|
18
|
+
orderId?: string;
|
|
19
|
+
height?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Order status response
|
|
23
|
+
*/
|
|
24
|
+
interface OrderStatus {
|
|
25
|
+
orderId: string;
|
|
26
|
+
status: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
|
|
27
|
+
paidAt?: string;
|
|
28
|
+
channelTransactionId?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Payment UI Options
|
|
32
|
+
*/
|
|
33
|
+
interface PaymentUIOptions {
|
|
34
|
+
locale?: string;
|
|
35
|
+
onSuccess?: (orderId?: string) => void;
|
|
36
|
+
onCancel?: (orderId?: string) => void;
|
|
37
|
+
onClose?: () => void;
|
|
38
|
+
/** Origin to validate postMessage (defaults to '*', set for security) */
|
|
39
|
+
allowedOrigin?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Poll Options
|
|
43
|
+
*/
|
|
44
|
+
interface PollOptions {
|
|
45
|
+
/** Polling interval in ms (default: 3000) */
|
|
46
|
+
interval?: number;
|
|
47
|
+
/** Timeout in ms (default: 300000 = 5 minutes) */
|
|
48
|
+
timeout?: number;
|
|
49
|
+
/** Callback on each status check */
|
|
50
|
+
onStatusChange?: (status: OrderStatus) => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Client-side Payment UI Helper
|
|
54
|
+
* 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* Params for opening payment directly without manual URL construction
|
|
58
|
+
*/
|
|
59
|
+
interface PaymentParams {
|
|
60
|
+
appId: string;
|
|
61
|
+
userId: string;
|
|
62
|
+
/** Product ID - use with priceId for direct ID-based payment */
|
|
63
|
+
productId?: string;
|
|
64
|
+
/** Price ID - use with productId for direct ID-based payment */
|
|
65
|
+
priceId?: string;
|
|
66
|
+
/** Product code - use with locale for code-based payment (alternative to productId/priceId) */
|
|
67
|
+
productCode?: string;
|
|
68
|
+
/**
|
|
69
|
+
* @deprecated Use checkoutUrl instead
|
|
70
|
+
* Defaults to https://pay.imgto.link
|
|
71
|
+
*/
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Checkout page URL (e.g. https://pay.youidian.com)
|
|
75
|
+
* Defaults to https://pay.imgto.link
|
|
76
|
+
*/
|
|
77
|
+
checkoutUrl?: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Client-side Payment UI Helper
|
|
81
|
+
* 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态
|
|
82
|
+
*/
|
|
83
|
+
declare class PaymentUI extends HostedFrameModal<PaymentEventData> {
|
|
84
|
+
/**
|
|
85
|
+
* Opens the payment checkout page in an iframe modal.
|
|
86
|
+
* @param urlOrParams - The checkout page URL or payment parameters
|
|
87
|
+
* @param options - UI options
|
|
88
|
+
*/
|
|
89
|
+
openPayment(urlOrParams: string | PaymentParams, options?: PaymentUIOptions): void;
|
|
90
|
+
/**
|
|
91
|
+
* Poll order status from integrator's API endpoint
|
|
92
|
+
* @param statusUrl - The integrator's API endpoint to check order status
|
|
93
|
+
* @param options - Polling options
|
|
94
|
+
* @returns Promise that resolves when order is paid or rejects on timeout/failure
|
|
95
|
+
*/
|
|
96
|
+
pollOrderStatus(statusUrl: string, options?: PollOptions): Promise<OrderStatus>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Convenience function to create a PaymentUI instance
|
|
100
|
+
*/
|
|
101
|
+
declare function createPaymentUI(): PaymentUI;
|
|
102
|
+
|
|
103
|
+
export { type OrderStatus, type PaymentEventData, type PaymentEventType, type PaymentParams, PaymentUI, type PaymentUIOptions, type PollOptions, createPaymentUI };
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { H as HostedFrameModal } from './hosted-modal-BZmYmXTU.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Youidian Payment SDK - Client Module
|
|
5
|
+
* 用于浏览器端集成,包含支付弹窗、状态轮询等功能
|
|
6
|
+
* 不依赖 Node.js crypto 模块
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Payment event types from checkout pages
|
|
11
|
+
*/
|
|
12
|
+
type PaymentEventType = "PAYMENT_SUCCESS" | "PAYMENT_CANCELLED" | "PAYMENT_CLOSE" | "PAYMENT_RESIZE";
|
|
13
|
+
/**
|
|
14
|
+
* Payment event data from postMessage
|
|
15
|
+
*/
|
|
16
|
+
interface PaymentEventData {
|
|
17
|
+
type: PaymentEventType;
|
|
18
|
+
orderId?: string;
|
|
19
|
+
height?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Order status response
|
|
23
|
+
*/
|
|
24
|
+
interface OrderStatus {
|
|
25
|
+
orderId: string;
|
|
26
|
+
status: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
|
|
27
|
+
paidAt?: string;
|
|
28
|
+
channelTransactionId?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Payment UI Options
|
|
32
|
+
*/
|
|
33
|
+
interface PaymentUIOptions {
|
|
34
|
+
locale?: string;
|
|
35
|
+
onSuccess?: (orderId?: string) => void;
|
|
36
|
+
onCancel?: (orderId?: string) => void;
|
|
37
|
+
onClose?: () => void;
|
|
38
|
+
/** Origin to validate postMessage (defaults to '*', set for security) */
|
|
39
|
+
allowedOrigin?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Poll Options
|
|
43
|
+
*/
|
|
44
|
+
interface PollOptions {
|
|
45
|
+
/** Polling interval in ms (default: 3000) */
|
|
46
|
+
interval?: number;
|
|
47
|
+
/** Timeout in ms (default: 300000 = 5 minutes) */
|
|
48
|
+
timeout?: number;
|
|
49
|
+
/** Callback on each status check */
|
|
50
|
+
onStatusChange?: (status: OrderStatus) => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Client-side Payment UI Helper
|
|
54
|
+
* 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* Params for opening payment directly without manual URL construction
|
|
58
|
+
*/
|
|
59
|
+
interface PaymentParams {
|
|
60
|
+
appId: string;
|
|
61
|
+
userId: string;
|
|
62
|
+
/** Product ID - use with priceId for direct ID-based payment */
|
|
63
|
+
productId?: string;
|
|
64
|
+
/** Price ID - use with productId for direct ID-based payment */
|
|
65
|
+
priceId?: string;
|
|
66
|
+
/** Product code - use with locale for code-based payment (alternative to productId/priceId) */
|
|
67
|
+
productCode?: string;
|
|
68
|
+
/**
|
|
69
|
+
* @deprecated Use checkoutUrl instead
|
|
70
|
+
* Defaults to https://pay.imgto.link
|
|
71
|
+
*/
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Checkout page URL (e.g. https://pay.youidian.com)
|
|
75
|
+
* Defaults to https://pay.imgto.link
|
|
76
|
+
*/
|
|
77
|
+
checkoutUrl?: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Client-side Payment UI Helper
|
|
81
|
+
* 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态
|
|
82
|
+
*/
|
|
83
|
+
declare class PaymentUI extends HostedFrameModal<PaymentEventData> {
|
|
84
|
+
/**
|
|
85
|
+
* Opens the payment checkout page in an iframe modal.
|
|
86
|
+
* @param urlOrParams - The checkout page URL or payment parameters
|
|
87
|
+
* @param options - UI options
|
|
88
|
+
*/
|
|
89
|
+
openPayment(urlOrParams: string | PaymentParams, options?: PaymentUIOptions): void;
|
|
90
|
+
/**
|
|
91
|
+
* Poll order status from integrator's API endpoint
|
|
92
|
+
* @param statusUrl - The integrator's API endpoint to check order status
|
|
93
|
+
* @param options - Polling options
|
|
94
|
+
* @returns Promise that resolves when order is paid or rejects on timeout/failure
|
|
95
|
+
*/
|
|
96
|
+
pollOrderStatus(statusUrl: string, options?: PollOptions): Promise<OrderStatus>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Convenience function to create a PaymentUI instance
|
|
100
|
+
*/
|
|
101
|
+
declare function createPaymentUI(): PaymentUI;
|
|
102
|
+
|
|
103
|
+
export { type OrderStatus, type PaymentEventData, type PaymentEventType, type PaymentParams, PaymentUI, type PaymentUIOptions, type PollOptions, createPaymentUI };
|