@whalet/payment-core 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.
@@ -0,0 +1,131 @@
1
+ /**
2
+ * 复制到剪贴板:优先 Async Clipboard API,失败或非安全上下文时用 execCommand 回退
3
+ * (HTTP、部分 iframe / Permissions-Policy 下 clipboard.writeText 不可用)
4
+ */
5
+ declare function copyTextToClipboard(text: string): Promise<boolean>;
6
+
7
+ /**
8
+ * 与 UI 对齐的最小错误码表(仅保留当前 SDK 使用项)。
9
+ */
10
+ declare const PaymentErrorCodes: {
11
+ /** 网关拒绝 / mock 失败 */
12
+ readonly DECLINED: "DECLINED";
13
+ /** 网关订单与宿主入参不一致 */
14
+ readonly ORDER_VALIDATION_MISMATCH: "ORDER_VALIDATION_MISMATCH";
15
+ /** 会话支付方式不含所选 id */
16
+ readonly METHOD_NOT_AVAILABLE: "METHOD_NOT_AVAILABLE";
17
+ /** 需要 clientIp 但公网 IP 探测失败(网络、拦截、超时等) */
18
+ readonly CLIENT_IP_UNAVAILABLE: "CLIENT_IP_UNAVAILABLE";
19
+ };
20
+ type PaymentErrorCode = (typeof PaymentErrorCodes)[keyof typeof PaymentErrorCodes];
21
+ /**
22
+ * 可序列化、可展示给 UI / 日志的错误载体(不含堆栈)。
23
+ */
24
+ interface PaymentError {
25
+ code: string;
26
+ message: string;
27
+ details?: Record<string, unknown>;
28
+ }
29
+ declare function createPaymentError(code: string, message: string, details?: Record<string, unknown>): PaymentError;
30
+
31
+ /**
32
+ * 跨模块共享的领域类型:环境、会话与支付结果。
33
+ * 刻意不包含密钥、卡号等敏感字段;敏感逻辑应在服务端完成。
34
+ */
35
+
36
+ /** 运行环境:本地/联调(dev)、沙箱(test)、生产(prod)。 */
37
+ type PaymentEnvironment = 'dev' | 'test' | 'prod';
38
+ /**
39
+ * 收银台 UI 的粗粒度状态机,供组件绑定 loading / 禁用 / 成功页等。
40
+ * 字符串值需保持稳定,便于持久化调试与埋点。
41
+ */
42
+ declare enum PaymentFlowState {
43
+ Idle = "idle",
44
+ Loading = "loading",
45
+ Ready = "ready",
46
+ /** 非 `open/sdk/payment` 接口 HTTP 成功但业务 `status` 非 success */
47
+ Error = "error",
48
+ Completed = "completed"
49
+ }
50
+ /**
51
+ * 商户创建支付会话后下发给前端的会话锚点。
52
+ * `sessionData` 为网关签名密文(常见为 Base64),SDK **不得解析**,支付请求须原样回传。
53
+ */
54
+ interface PaymentSdkSession {
55
+ /** 会话主键(与网关订单/会话对齐)。 */
56
+ id: string;
57
+ /** 网关生成的签名密文;含 amount、userId 等,由网关校验。 */
58
+ sessionData: string;
59
+ }
60
+ /**
61
+ * 会话结果:仅含可在浏览器侧持有的安全字段。
62
+ * `paymentMethodIds` 为网关/会话下发的可用方式 id;展示名由 UI 与 `paymentMethodCopy` 等决定。
63
+ */
64
+ interface PaymentSession {
65
+ id: string;
66
+ /**
67
+ * 与 {@link PaymentSdkSession.sessionData} 一致;支付提交时须随请求原样携带。
68
+ */
69
+ sessionData: string;
70
+ clientKey: string;
71
+ environment: PaymentEnvironment;
72
+ /** 当前会话可用的支付方式 id 列表。 */
73
+ paymentMethodIds: string[];
74
+ /** ISO 8601 等格式的过期时间,若网关返回则透传。 */
75
+ expiresAt?: string;
76
+ /** 网关侧订单唯一标识(与 checkout detail / 支付接口约定一致)。 */
77
+ tradeUniId?: string;
78
+ /** 网关订单金额,用于与宿主初始化 `amount` 交叉校验。 */
79
+ orderAmount?: {
80
+ value: number;
81
+ currency: string;
82
+ };
83
+ /** 网关订单地区/国家码,用于与宿主 `countryCode` 交叉校验。 */
84
+ orderRegion?: string;
85
+ /**
86
+ * Raw `info.paymentMethodList` entries from sessions (e.g. `paymentMethodCode`),
87
+ * for host display or passthrough on submit; same source as {@link paymentMethodIds}, different shape.
88
+ */
89
+ paymentMethodList?: unknown[];
90
+ /** Sessions `info.locale` (e.g. `auto`), independent of UI `locale`. */
91
+ checkoutLocale?: string;
92
+ /**
93
+ * `sessions.info.customerEmail`: default source for card submit `email`.
94
+ */
95
+ customerEmail?: string;
96
+ /**
97
+ * 对齐 whalet-checkout `acquiringInfo.addressMode`:是否展示/透传账单地址。
98
+ */
99
+ addressMode?: 'Display_Transmission' | 'Transmission' | 'Not_Transmission';
100
+ /**
101
+ * 服务端预填账单(`Display_Transmission` 回显)。
102
+ */
103
+ serverBillingAddress?: Record<string, unknown>;
104
+ /** 收货地址(若网关下发)。 */
105
+ shippingAddress?: Record<string, unknown>;
106
+ }
107
+ /**
108
+ * 用户完成一次支付尝试后的联合结果。
109
+ * - success:网关确认成功,带交易号
110
+ * - failure:业务或网关拒绝,带 {@link PaymentError}
111
+ * - pending:需后续动作(如 3DS),当前 SDK 为占位
112
+ */
113
+ type PaymentCompletedResult = {
114
+ status: 'success';
115
+ transactionId: string;
116
+ } | {
117
+ status: 'failure';
118
+ error: PaymentError;
119
+ } | {
120
+ status: 'pending';
121
+ action?: string;
122
+ };
123
+ /**
124
+ * open-checkout POST 请求体中与网关约定的少量公共字段(由 UI 层 HTTP 输入合并)。
125
+ */
126
+ interface CheckoutDetailExtras {
127
+ /** 与网关 `linkUniId` 对齐;常见与 `clientKey` 相同 */
128
+ linkUniId?: string;
129
+ }
130
+
131
+ export { type CheckoutDetailExtras, type PaymentCompletedResult, type PaymentEnvironment, type PaymentError, type PaymentErrorCode, PaymentErrorCodes, PaymentFlowState, type PaymentSdkSession, type PaymentSession, copyTextToClipboard, createPaymentError };
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ // src/utils/copyTextToClipboard.ts
2
+ async function copyTextToClipboard(text) {
3
+ if (typeof document === "undefined") return false;
4
+ if (typeof navigator !== "undefined" && window.isSecureContext && navigator.clipboard?.writeText) {
5
+ try {
6
+ await navigator.clipboard.writeText(text);
7
+ return true;
8
+ } catch {
9
+ }
10
+ }
11
+ try {
12
+ const ta = document.createElement("textarea");
13
+ ta.value = text;
14
+ ta.setAttribute("readonly", "");
15
+ ta.style.position = "fixed";
16
+ ta.style.left = "-9999px";
17
+ ta.style.top = "0";
18
+ ta.setAttribute("aria-hidden", "true");
19
+ document.body.appendChild(ta);
20
+ ta.focus();
21
+ ta.select();
22
+ ta.setSelectionRange(0, text.length);
23
+ const ok = document.execCommand("copy");
24
+ document.body.removeChild(ta);
25
+ return ok;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ // src/types/paymentError.ts
32
+ var PaymentErrorCodes = {
33
+ /** 网关拒绝 / mock 失败 */
34
+ DECLINED: "DECLINED",
35
+ /** 网关订单与宿主入参不一致 */
36
+ ORDER_VALIDATION_MISMATCH: "ORDER_VALIDATION_MISMATCH",
37
+ /** 会话支付方式不含所选 id */
38
+ METHOD_NOT_AVAILABLE: "METHOD_NOT_AVAILABLE",
39
+ /** 需要 clientIp 但公网 IP 探测失败(网络、拦截、超时等) */
40
+ CLIENT_IP_UNAVAILABLE: "CLIENT_IP_UNAVAILABLE"
41
+ };
42
+ function createPaymentError(code, message, details) {
43
+ return { code, message, details };
44
+ }
45
+
46
+ // src/types/types.ts
47
+ var PaymentFlowState = /* @__PURE__ */ ((PaymentFlowState2) => {
48
+ PaymentFlowState2["Idle"] = "idle";
49
+ PaymentFlowState2["Loading"] = "loading";
50
+ PaymentFlowState2["Ready"] = "ready";
51
+ PaymentFlowState2["Error"] = "error";
52
+ PaymentFlowState2["Completed"] = "completed";
53
+ return PaymentFlowState2;
54
+ })(PaymentFlowState || {});
55
+ export {
56
+ PaymentErrorCodes,
57
+ PaymentFlowState,
58
+ copyTextToClipboard,
59
+ createPaymentError
60
+ };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@whalet/payment-core",
3
+ "description": "支付域核心:领域类型、最小错误码与通用工具(无 HTTP 适配器)。",
4
+ "version": "0.1.0",
5
+ "private": false,
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "license": "MIT",
11
+ "sideEffects": false,
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup src/index.ts --format esm --dts --clean --outDir dist",
26
+ "lint": "eslint src --max-warnings 0",
27
+ "typecheck": "tsc --noEmit",
28
+ "test": "vitest run",
29
+ "test:coverage": "vitest run --coverage"
30
+ },
31
+ "devDependencies": {
32
+ "@vitest/coverage-v8": "4.1.8",
33
+ "tsup": "8.5.1",
34
+ "typescript": "5.6.3",
35
+ "vitest": "4.1.8"
36
+ }
37
+ }