@blocklet/payment-vendor 1.20.6
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 +935 -0
- package/examples/usage-example.ts +321 -0
- package/lib/auth.d.ts +58 -0
- package/lib/auth.d.ts.map +1 -0
- package/lib/auth.js +138 -0
- package/lib/auth.js.map +1 -0
- package/lib/index.d.ts +70 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +79 -0
- package/lib/index.js.map +1 -0
- package/lib/logger.d.ts +11 -0
- package/lib/logger.d.ts.map +1 -0
- package/lib/logger.js +13 -0
- package/lib/logger.js.map +1 -0
- package/lib/middleware.d.ts +31 -0
- package/lib/middleware.d.ts.map +1 -0
- package/lib/middleware.js +274 -0
- package/lib/middleware.js.map +1 -0
- package/lib/types.d.ts +114 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/whitelist.d.ts +26 -0
- package/lib/whitelist.d.ts.map +1 -0
- package/lib/whitelist.js +90 -0
- package/lib/whitelist.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @blocklet/payment-vendor 使用示例
|
|
5
|
+
*
|
|
6
|
+
* 这个示例展示了如何集成 SDK 来创建一个完整的供应商服务
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import VendorSDK from '@blocklet/payment-vendor';
|
|
10
|
+
import express from 'express';
|
|
11
|
+
|
|
12
|
+
// ==================== 基础服务设置 ====================
|
|
13
|
+
|
|
14
|
+
const app = express();
|
|
15
|
+
|
|
16
|
+
// 基础中间件
|
|
17
|
+
app.use(express.json());
|
|
18
|
+
|
|
19
|
+
// ==================== 中介配置 ====================
|
|
20
|
+
|
|
21
|
+
// 方式1: 静态配置(适用于固定中介列表)
|
|
22
|
+
VendorSDK.setBrokers([
|
|
23
|
+
{
|
|
24
|
+
id: 'payment-kit',
|
|
25
|
+
name: 'Payment Kit Service',
|
|
26
|
+
publicKey: process.env.PAYMENT_KIT_PUBLIC_KEY || '0x680688a033b86da179f39018e074410439ae82a97c4cb8e1ad16c26eabcc1795',
|
|
27
|
+
status: 'active',
|
|
28
|
+
rateLimit: 100
|
|
29
|
+
}
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
// 方式2: 动态配置(适用于需要实时更新的场景)
|
|
33
|
+
// VendorSDK.setBrokers(() => {
|
|
34
|
+
// // 从环境变量读取配置
|
|
35
|
+
// const configSource = process.env.VENDOR_DISTRIBUTORS || '[]';
|
|
36
|
+
// try {
|
|
37
|
+
// const brokers = JSON.parse(configSource);
|
|
38
|
+
// return brokers.map((item: any) => ({
|
|
39
|
+
// id: item.brokerId,
|
|
40
|
+
// name: item.name,
|
|
41
|
+
// publicKey: item.publicKey,
|
|
42
|
+
// status: item.enabled ? 'active' : 'inactive',
|
|
43
|
+
// rateLimit: item.rateLimit || 100
|
|
44
|
+
// }));
|
|
45
|
+
// } catch (error) {
|
|
46
|
+
// console.error('Failed to parse broker config:', error);
|
|
47
|
+
// return [];
|
|
48
|
+
// }
|
|
49
|
+
// });
|
|
50
|
+
|
|
51
|
+
// ==================== 中间件配置 ====================
|
|
52
|
+
|
|
53
|
+
// 限流中间件
|
|
54
|
+
app.use('/api/vendor', VendorSDK.middleware.rateLimiter({
|
|
55
|
+
windowMs: 60000, // 1分钟
|
|
56
|
+
max: 1000 // 最多1000次请求
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
// 认证中间件
|
|
60
|
+
app.use('/api/vendor', VendorSDK.middleware.ensureAuth({
|
|
61
|
+
skipTimestamp: false,
|
|
62
|
+
maxAge: 300000 // 5分钟
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
// ==================== 业务端点 ====================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 主要业务端点:处理发货、状态查询、退货等操作
|
|
69
|
+
*/
|
|
70
|
+
app.post('/api/vendor/deliveries', async (req, res) => {
|
|
71
|
+
try {
|
|
72
|
+
const { userInfo, deliveryParams, description } = req.body;
|
|
73
|
+
|
|
74
|
+
console.log(`Processing delivery request - User: ${userInfo.userDid}, Instance: ${deliveryParams.instanceName}`);
|
|
75
|
+
|
|
76
|
+
// 处理发货逻辑
|
|
77
|
+
const fulfillResult = await handleFulfillment(userInfo, deliveryParams, description);
|
|
78
|
+
res.json({
|
|
79
|
+
success: fulfillResult.success,
|
|
80
|
+
status: fulfillResult.success ? 'completed' : 'failed',
|
|
81
|
+
data: fulfillResult.data,
|
|
82
|
+
message: fulfillResult.message
|
|
83
|
+
});
|
|
84
|
+
} catch (error: any) {
|
|
85
|
+
console.error('Request processing failed:', error);
|
|
86
|
+
res.status(500).json({
|
|
87
|
+
success: false,
|
|
88
|
+
status: 'failed',
|
|
89
|
+
error: '内部服务器错误',
|
|
90
|
+
message: error.message
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// ==================== 管理端点 ====================
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 健康检查端点
|
|
99
|
+
*/
|
|
100
|
+
app.get('/health', VendorSDK.middleware.healthCheck());
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 中介状态查询端点
|
|
104
|
+
*/
|
|
105
|
+
app.get('/api/admin/brokers', async (req, res) => {
|
|
106
|
+
try {
|
|
107
|
+
const brokers = await VendorSDK.getWhitelist();
|
|
108
|
+
res.json({
|
|
109
|
+
total: brokers.length,
|
|
110
|
+
active: brokers.filter((d: any) => d.status === 'active').length,
|
|
111
|
+
brokers: brokers.map((d: any) => ({
|
|
112
|
+
id: d.id,
|
|
113
|
+
name: d.name,
|
|
114
|
+
status: d.status,
|
|
115
|
+
rateLimit: d.rateLimit,
|
|
116
|
+
// 不暴露公钥全文,只显示前缀
|
|
117
|
+
publicKeyPrefix: d.publicKey.substring(0, 10) + '...'
|
|
118
|
+
}))
|
|
119
|
+
});
|
|
120
|
+
} catch (error: any) {
|
|
121
|
+
res.status(500).json({
|
|
122
|
+
error: '获取中介列表失败',
|
|
123
|
+
message: error.message
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 系统信息端点
|
|
130
|
+
*/
|
|
131
|
+
app.get('/api/admin/info', (req, res) => {
|
|
132
|
+
res.json({
|
|
133
|
+
service: 'Vendor Service',
|
|
134
|
+
version: '1.0.0',
|
|
135
|
+
uptime: Math.floor(process.uptime()),
|
|
136
|
+
memory: {
|
|
137
|
+
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
|
138
|
+
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024)
|
|
139
|
+
},
|
|
140
|
+
nodeVersion: process.version,
|
|
141
|
+
timestamp: new Date().toISOString()
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// ==================== 错误处理 ====================
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 统一错误处理中间件
|
|
149
|
+
*/
|
|
150
|
+
app.use(VendorSDK.middleware.errorHandler);
|
|
151
|
+
|
|
152
|
+
// ==================== 业务逻辑函数 ====================
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 处理发货逻辑
|
|
156
|
+
*/
|
|
157
|
+
async function handleFulfillment(userInfo: any, deliveryParams: any, description: string) {
|
|
158
|
+
console.log(`Processing delivery - User: ${userInfo.userDid}, Instance: ${deliveryParams.instanceName}`, {
|
|
159
|
+
userEmail: userInfo.email,
|
|
160
|
+
productId: deliveryParams.productId,
|
|
161
|
+
description
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
// 模拟业务处理时间
|
|
166
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
167
|
+
|
|
168
|
+
// 模拟成功率(90%成功)
|
|
169
|
+
const isSuccess = Math.random() > 0.1;
|
|
170
|
+
|
|
171
|
+
if (isSuccess) {
|
|
172
|
+
const instanceId = `inst_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
success: true,
|
|
176
|
+
data: {
|
|
177
|
+
instanceId,
|
|
178
|
+
serviceUrl: `https://example.com/service/${deliveryParams.instanceName}`,
|
|
179
|
+
installUrl: `https://example.com/install/${instanceId}`,
|
|
180
|
+
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString()
|
|
181
|
+
},
|
|
182
|
+
message: '发货成功'
|
|
183
|
+
};
|
|
184
|
+
} else {
|
|
185
|
+
return {
|
|
186
|
+
success: false,
|
|
187
|
+
data: null,
|
|
188
|
+
message: '发货失败,请重试'
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
} catch (error: any) {
|
|
192
|
+
console.error('Delivery processing failed:', error);
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
data: null,
|
|
196
|
+
message: `发货异常: ${error.message}`
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 处理状态查询逻辑 (可选的附加端点)
|
|
203
|
+
*/
|
|
204
|
+
async function getDeliveryStatus(instanceId: string) {
|
|
205
|
+
console.log(`Querying delivery status - Instance: ${instanceId}`);
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
// 模拟状态查询
|
|
209
|
+
const statuses = ['pending', 'processing', 'completed'];
|
|
210
|
+
const status = statuses[Math.floor(Math.random() * statuses.length)];
|
|
211
|
+
|
|
212
|
+
let progress = 0;
|
|
213
|
+
let estimatedTime = 0;
|
|
214
|
+
|
|
215
|
+
switch (status) {
|
|
216
|
+
case 'pending':
|
|
217
|
+
progress = 0;
|
|
218
|
+
estimatedTime = 300; // 5分钟
|
|
219
|
+
break;
|
|
220
|
+
case 'processing':
|
|
221
|
+
progress = Math.floor(Math.random() * 80) + 10; // 10-90%
|
|
222
|
+
estimatedTime = Math.floor(Math.random() * 180) + 60; // 1-3分钟
|
|
223
|
+
break;
|
|
224
|
+
case 'completed':
|
|
225
|
+
progress = 100;
|
|
226
|
+
estimatedTime = 0;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
instanceId,
|
|
232
|
+
status,
|
|
233
|
+
progress,
|
|
234
|
+
estimatedTime,
|
|
235
|
+
serviceUrl: status === 'completed' ? `https://example.com/service/${instanceId}` : undefined
|
|
236
|
+
};
|
|
237
|
+
} catch (error: any) {
|
|
238
|
+
console.error('Status query failed:', error);
|
|
239
|
+
return {
|
|
240
|
+
instanceId,
|
|
241
|
+
status: 'failed',
|
|
242
|
+
progress: 0,
|
|
243
|
+
estimatedTime: 0,
|
|
244
|
+
error: error.message
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ==================== 服务启动 ====================
|
|
250
|
+
|
|
251
|
+
const port = parseInt(process.env.PORT || '3000', 10);
|
|
252
|
+
|
|
253
|
+
app.listen(port, () => {
|
|
254
|
+
console.log('Vendor service started successfully!');
|
|
255
|
+
console.log(`Service URL: http://localhost:${port}`);
|
|
256
|
+
console.log(`Health check: http://localhost:${port}/health`);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// ==================== 优雅关闭 ====================
|
|
260
|
+
|
|
261
|
+
process.on('SIGTERM', () => {
|
|
262
|
+
console.log('Received SIGTERM signal, starting graceful shutdown...');
|
|
263
|
+
process.exit(0);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
process.on('SIGINT', () => {
|
|
267
|
+
console.log('Received SIGINT signal, starting graceful shutdown...');
|
|
268
|
+
process.exit(0);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// ==================== 导出 (可选) ====================
|
|
272
|
+
|
|
273
|
+
export default app;
|
|
274
|
+
|
|
275
|
+
// ==================== 使用说明 ====================
|
|
276
|
+
|
|
277
|
+
/*
|
|
278
|
+
|
|
279
|
+
环境变量配置:
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
# 中介配置
|
|
283
|
+
export PAYMENT_KIT_PUBLIC_KEY="0x680688a033b86da179f39018e074410439ae82a97c4cb8e1ad16c26eabcc1795"
|
|
284
|
+
|
|
285
|
+
# 动态配置示例
|
|
286
|
+
export VENDOR_DISTRIBUTORS='[{
|
|
287
|
+
"brokerId": "payment-kit",
|
|
288
|
+
"name": "Payment Kit Service",
|
|
289
|
+
"publicKey": "0x680688a033b86da179f39018e074410439ae82a97c4cb8e1ad16c26eabcc1795",
|
|
290
|
+
"enabled": true,
|
|
291
|
+
"rateLimit": 100
|
|
292
|
+
}]'
|
|
293
|
+
|
|
294
|
+
# 服务端口
|
|
295
|
+
export PORT=3000
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
启动服务:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# 开发模式
|
|
302
|
+
npm run dev
|
|
303
|
+
|
|
304
|
+
# 生产模式
|
|
305
|
+
npm start
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
测试接口:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# 健康检查
|
|
312
|
+
curl http://localhost:3000/health
|
|
313
|
+
|
|
314
|
+
# 中介列表
|
|
315
|
+
curl http://localhost:3000/api/admin/brokers
|
|
316
|
+
|
|
317
|
+
# 系统信息
|
|
318
|
+
curl http://localhost:3000/api/admin/info
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
*/
|
package/lib/auth.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { VendorRequest, VendorSignedRequest } from './types';
|
|
2
|
+
export declare class VendorAuth {
|
|
3
|
+
/**
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* const request = {
|
|
7
|
+
* orderId: 'order_123',
|
|
8
|
+
* brokerId: 'payment-kit',
|
|
9
|
+
* timestamp: Date.now(),
|
|
10
|
+
* operation: 'fulfill',
|
|
11
|
+
* params: { appName: 'test-app' }
|
|
12
|
+
* };
|
|
13
|
+
*
|
|
14
|
+
* const signature = VendorAuth.signRequest(request, process.env.SERVER_SK);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
static signRequest(request: VendorRequest): string;
|
|
18
|
+
/**
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const broker = WhitelistManager.getBroker('payment-kit');
|
|
22
|
+
* const verified = VendorAuth.verifyRequest(signedRequest, publicKey);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
static verifyRequest(request: VendorSignedRequest, brokerPublicKey: string): Promise<boolean>;
|
|
26
|
+
static validateTimestamp(timestamp: number, maxAge?: number): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const headers = VendorAuth.generateHeaders(request);
|
|
31
|
+
*
|
|
32
|
+
* fetch(brokerEndpoint, { method: 'POST', headers, body: JSON.stringify(request) });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
static generateHeaders(request: VendorRequest): Record<string, string>;
|
|
36
|
+
/**
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const { headers, body } = VendorAuth.signRequestWithHeaders(
|
|
40
|
+
* orderData,
|
|
41
|
+
* wallet.secretKey,
|
|
42
|
+
* wallet.publicKey
|
|
43
|
+
* );
|
|
44
|
+
*
|
|
45
|
+
* const response = await fetch('/api/broker/deliveries', {
|
|
46
|
+
* method: 'POST',
|
|
47
|
+
* headers,
|
|
48
|
+
* body
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
static signRequestWithHeaders(request: Record<string, any>): {
|
|
53
|
+
headers: Record<string, string>;
|
|
54
|
+
body: string;
|
|
55
|
+
};
|
|
56
|
+
static signAndSerialize(request: VendorRequest): string;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAIlE,qBAAa,UAAU;IACrB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM;IAgBlD;;;;;;OAMG;WACU,aAAa,CAAC,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBnG,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,GAAG,OAAO;IAcrE;;;;;;;OAOG;IACH,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAetE;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAW9G,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM;CASxD"}
|
package/lib/auth.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable import/prefer-default-export */
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.VendorAuth = void 0;
|
|
8
|
+
const wallet_1 = __importDefault(require("@blocklet/sdk/lib/wallet"));
|
|
9
|
+
const util_1 = require("@ocap/util");
|
|
10
|
+
const wallet_2 = require("@ocap/wallet");
|
|
11
|
+
const json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
|
|
12
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
13
|
+
const { secretKey, publicKey } = (0, wallet_1.default)();
|
|
14
|
+
class VendorAuth {
|
|
15
|
+
/**
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const request = {
|
|
19
|
+
* orderId: 'order_123',
|
|
20
|
+
* brokerId: 'payment-kit',
|
|
21
|
+
* timestamp: Date.now(),
|
|
22
|
+
* operation: 'fulfill',
|
|
23
|
+
* params: { appName: 'test-app' }
|
|
24
|
+
* };
|
|
25
|
+
*
|
|
26
|
+
* const signature = VendorAuth.signRequest(request, process.env.SERVER_SK);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
static signRequest(request) {
|
|
30
|
+
try {
|
|
31
|
+
if (!secretKey) {
|
|
32
|
+
throw new Error('brokerSk is required for signing');
|
|
33
|
+
}
|
|
34
|
+
const wallet = (0, wallet_2.fromSecretKey)(secretKey);
|
|
35
|
+
const payload = (0, json_stable_stringify_1.default)(request || {});
|
|
36
|
+
const signature = wallet.sign(payload);
|
|
37
|
+
return (0, util_1.toBase58)(signature);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw new Error(`Failed to sign vendor request: ${error.message}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const broker = WhitelistManager.getBroker('payment-kit');
|
|
47
|
+
* const verified = VendorAuth.verifyRequest(signedRequest, publicKey);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
static async verifyRequest(request, brokerPublicKey) {
|
|
51
|
+
try {
|
|
52
|
+
const { signature, ...payload } = request;
|
|
53
|
+
const wallet = (0, wallet_2.fromPublicKey)(brokerPublicKey);
|
|
54
|
+
const payloadString = (0, json_stable_stringify_1.default)(payload || {});
|
|
55
|
+
const signatureBytes = (0, util_1.fromBase58)(signature);
|
|
56
|
+
const verified = await wallet.verify(payloadString, signatureBytes);
|
|
57
|
+
return verified;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
// Critical: Log signature verification errors
|
|
61
|
+
logger_1.default.error('Signature verification failed', { error: error.message });
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
static validateTimestamp(timestamp, maxAge = 300000) {
|
|
66
|
+
try {
|
|
67
|
+
if (!Number.isFinite(timestamp) || timestamp <= 0) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
const age = Math.abs(now - timestamp);
|
|
72
|
+
return age <= maxAge;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const headers = VendorAuth.generateHeaders(request);
|
|
82
|
+
*
|
|
83
|
+
* fetch(brokerEndpoint, { method: 'POST', headers, body: JSON.stringify(request) });
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
static generateHeaders(request) {
|
|
87
|
+
try {
|
|
88
|
+
const signature = VendorAuth.signRequest(request);
|
|
89
|
+
return {
|
|
90
|
+
'Content-Type': 'application/json',
|
|
91
|
+
'x-broker-sig': signature,
|
|
92
|
+
'x-broker-did': publicKey,
|
|
93
|
+
'User-Agent': '@arcblock/vendor-sdk/1.19.18',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new Error(`Failed to generate headers: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const { headers, body } = VendorAuth.signRequestWithHeaders(
|
|
104
|
+
* orderData,
|
|
105
|
+
* wallet.secretKey,
|
|
106
|
+
* wallet.publicKey
|
|
107
|
+
* );
|
|
108
|
+
*
|
|
109
|
+
* const response = await fetch('/api/broker/deliveries', {
|
|
110
|
+
* method: 'POST',
|
|
111
|
+
* headers,
|
|
112
|
+
* body
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
static signRequestWithHeaders(request) {
|
|
117
|
+
try {
|
|
118
|
+
const headers = VendorAuth.generateHeaders(request);
|
|
119
|
+
const body = JSON.stringify(request);
|
|
120
|
+
return { headers, body };
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
throw new Error(`Failed to sign request with headers: ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
static signAndSerialize(request) {
|
|
127
|
+
try {
|
|
128
|
+
const signature = VendorAuth.signRequest(request);
|
|
129
|
+
const signedRequest = { ...request, signature };
|
|
130
|
+
return JSON.stringify(signedRequest);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
throw new Error(`Failed to sign and serialize request: ${error.message}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.VendorAuth = VendorAuth;
|
|
138
|
+
//# sourceMappingURL=auth.js.map
|
package/lib/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { VendorAuth } from './auth';
|
|
2
|
+
import { WhitelistManager } from './whitelist';
|
|
3
|
+
import { ensureVendorAuth, healthCheck, errorHandler, rateLimiter } from './middleware';
|
|
4
|
+
export { VendorAuth } from './auth';
|
|
5
|
+
export { WhitelistManager } from './whitelist';
|
|
6
|
+
export { ensureVendorAuth, healthCheck, errorHandler, rateLimiter } from './middleware';
|
|
7
|
+
export type { VendorOrderStatus, BrokerStatus, DeliveryRequest, VendorRequest, VendorSignedRequest, VendorResponse, BrokerConfig, SigningOptions, AuthMiddlewareOptions, VendorOrder, VendorHooks, VendorStorage, CreateOrderParams, UpdateOrderParams, HealthCheckResponse, } from './types';
|
|
8
|
+
declare const VendorSDK: {
|
|
9
|
+
Auth: typeof VendorAuth;
|
|
10
|
+
Whitelist: typeof WhitelistManager;
|
|
11
|
+
middleware: {
|
|
12
|
+
ensureAuth: typeof ensureVendorAuth;
|
|
13
|
+
healthCheck: typeof healthCheck;
|
|
14
|
+
errorHandler: typeof errorHandler;
|
|
15
|
+
rateLimiter: typeof rateLimiter;
|
|
16
|
+
};
|
|
17
|
+
utils: {
|
|
18
|
+
validateTimestamp: typeof VendorAuth.validateTimestamp;
|
|
19
|
+
generateHeaders: typeof VendorAuth.generateHeaders;
|
|
20
|
+
signAndSerialize: typeof VendorAuth.signAndSerialize;
|
|
21
|
+
signRequestWithHeaders: typeof VendorAuth.signRequestWithHeaders;
|
|
22
|
+
getBroker: typeof WhitelistManager.getBroker;
|
|
23
|
+
getBrokerByPublicKey: typeof WhitelistManager.getBrokerByPublicKey;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* @example
|
|
27
|
+
* VendorSDK.setBrokers([{ id: 'payment-kit', ... }]);
|
|
28
|
+
* VendorSDK.setBrokers(() => parseMyConfig());
|
|
29
|
+
*/
|
|
30
|
+
setBrokers: typeof WhitelistManager.setBrokers;
|
|
31
|
+
/**
|
|
32
|
+
* @example
|
|
33
|
+
* const whitelist = await VendorSDK.getWhitelist();
|
|
34
|
+
* console.log('Current whitelist:', whitelist);
|
|
35
|
+
*/
|
|
36
|
+
getWhitelist: typeof WhitelistManager.getWhitelist;
|
|
37
|
+
getActiveBrokers: typeof WhitelistManager.getActiveBrokers;
|
|
38
|
+
clearBrokers: typeof WhitelistManager.clearBrokers;
|
|
39
|
+
constants: {
|
|
40
|
+
OrderStatus: {
|
|
41
|
+
PENDING: "pending";
|
|
42
|
+
PROCESSING: "processing";
|
|
43
|
+
COMPLETED: "completed";
|
|
44
|
+
FAILED: "failed";
|
|
45
|
+
CANCELLED: "cancelled";
|
|
46
|
+
RETURN_REQUESTED: "return_requested";
|
|
47
|
+
};
|
|
48
|
+
Operation: {
|
|
49
|
+
FULFILL: "fulfill";
|
|
50
|
+
STATUS: "status";
|
|
51
|
+
RETURN: "return";
|
|
52
|
+
};
|
|
53
|
+
Defaults: {
|
|
54
|
+
TIMESTAMP_MAX_AGE: number;
|
|
55
|
+
RATE_LIMIT: number;
|
|
56
|
+
RATE_LIMIT_WINDOW: number;
|
|
57
|
+
MAX_RETRIES: number;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
export default VendorSDK;
|
|
62
|
+
export declare const Auth: typeof VendorAuth;
|
|
63
|
+
export declare const Whitelist: typeof WhitelistManager;
|
|
64
|
+
export declare const middleware: {
|
|
65
|
+
ensureAuth: typeof ensureVendorAuth;
|
|
66
|
+
healthCheck: typeof healthCheck;
|
|
67
|
+
errorHandler: typeof errorHandler;
|
|
68
|
+
rateLimiter: typeof rateLimiter;
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExF,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,WAAW,EACX,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAEjB,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;IAoBb;;;;OAIG;;IAGH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;CA4BJ,CAAC;AAEF,eAAe,SAAS,CAAC;AAEzB,eAAO,MAAM,IAAI,mBAAa,CAAC;AAC/B,eAAO,MAAM,SAAS,yBAAmB,CAAC;AAC1C,eAAO,MAAM,UAAU;;;;;CAKtB,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable import/prefer-default-export */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.middleware = exports.Whitelist = exports.Auth = exports.rateLimiter = exports.errorHandler = exports.healthCheck = exports.ensureVendorAuth = exports.WhitelistManager = exports.VendorAuth = void 0;
|
|
5
|
+
const auth_1 = require("./auth");
|
|
6
|
+
const whitelist_1 = require("./whitelist");
|
|
7
|
+
const middleware_1 = require("./middleware");
|
|
8
|
+
var auth_2 = require("./auth");
|
|
9
|
+
Object.defineProperty(exports, "VendorAuth", { enumerable: true, get: function () { return auth_2.VendorAuth; } });
|
|
10
|
+
var whitelist_2 = require("./whitelist");
|
|
11
|
+
Object.defineProperty(exports, "WhitelistManager", { enumerable: true, get: function () { return whitelist_2.WhitelistManager; } });
|
|
12
|
+
var middleware_2 = require("./middleware");
|
|
13
|
+
Object.defineProperty(exports, "ensureVendorAuth", { enumerable: true, get: function () { return middleware_2.ensureVendorAuth; } });
|
|
14
|
+
Object.defineProperty(exports, "healthCheck", { enumerable: true, get: function () { return middleware_2.healthCheck; } });
|
|
15
|
+
Object.defineProperty(exports, "errorHandler", { enumerable: true, get: function () { return middleware_2.errorHandler; } });
|
|
16
|
+
Object.defineProperty(exports, "rateLimiter", { enumerable: true, get: function () { return middleware_2.rateLimiter; } });
|
|
17
|
+
const VendorSDK = {
|
|
18
|
+
Auth: auth_1.VendorAuth,
|
|
19
|
+
Whitelist: whitelist_1.WhitelistManager,
|
|
20
|
+
middleware: {
|
|
21
|
+
ensureAuth: middleware_1.ensureVendorAuth,
|
|
22
|
+
healthCheck: middleware_1.healthCheck,
|
|
23
|
+
errorHandler: middleware_1.errorHandler,
|
|
24
|
+
rateLimiter: middleware_1.rateLimiter,
|
|
25
|
+
},
|
|
26
|
+
utils: {
|
|
27
|
+
validateTimestamp: auth_1.VendorAuth.validateTimestamp,
|
|
28
|
+
generateHeaders: auth_1.VendorAuth.generateHeaders,
|
|
29
|
+
signAndSerialize: auth_1.VendorAuth.signAndSerialize,
|
|
30
|
+
signRequestWithHeaders: auth_1.VendorAuth.signRequestWithHeaders,
|
|
31
|
+
getBroker: whitelist_1.WhitelistManager.getBroker,
|
|
32
|
+
getBrokerByPublicKey: whitelist_1.WhitelistManager.getBrokerByPublicKey,
|
|
33
|
+
},
|
|
34
|
+
/**
|
|
35
|
+
* @example
|
|
36
|
+
* VendorSDK.setBrokers([{ id: 'payment-kit', ... }]);
|
|
37
|
+
* VendorSDK.setBrokers(() => parseMyConfig());
|
|
38
|
+
*/
|
|
39
|
+
setBrokers: whitelist_1.WhitelistManager.setBrokers,
|
|
40
|
+
/**
|
|
41
|
+
* @example
|
|
42
|
+
* const whitelist = await VendorSDK.getWhitelist();
|
|
43
|
+
* console.log('Current whitelist:', whitelist);
|
|
44
|
+
*/
|
|
45
|
+
getWhitelist: whitelist_1.WhitelistManager.getWhitelist,
|
|
46
|
+
getActiveBrokers: whitelist_1.WhitelistManager.getActiveBrokers,
|
|
47
|
+
clearBrokers: whitelist_1.WhitelistManager.clearBrokers,
|
|
48
|
+
constants: {
|
|
49
|
+
OrderStatus: {
|
|
50
|
+
PENDING: 'pending',
|
|
51
|
+
PROCESSING: 'processing',
|
|
52
|
+
COMPLETED: 'completed',
|
|
53
|
+
FAILED: 'failed',
|
|
54
|
+
CANCELLED: 'cancelled',
|
|
55
|
+
RETURN_REQUESTED: 'return_requested',
|
|
56
|
+
},
|
|
57
|
+
Operation: {
|
|
58
|
+
FULFILL: 'fulfill',
|
|
59
|
+
STATUS: 'status',
|
|
60
|
+
RETURN: 'return',
|
|
61
|
+
},
|
|
62
|
+
Defaults: {
|
|
63
|
+
TIMESTAMP_MAX_AGE: 300000,
|
|
64
|
+
RATE_LIMIT: 100,
|
|
65
|
+
RATE_LIMIT_WINDOW: 60000,
|
|
66
|
+
MAX_RETRIES: 3,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
exports.default = VendorSDK;
|
|
71
|
+
exports.Auth = auth_1.VendorAuth;
|
|
72
|
+
exports.Whitelist = whitelist_1.WhitelistManager;
|
|
73
|
+
exports.middleware = {
|
|
74
|
+
ensureAuth: middleware_1.ensureVendorAuth,
|
|
75
|
+
healthCheck: middleware_1.healthCheck,
|
|
76
|
+
errorHandler: middleware_1.errorHandler,
|
|
77
|
+
rateLimiter: middleware_1.rateLimiter,
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,iDAAiD;;;AAEjD,iCAAoC;AACpC,2CAA+C;AAC/C,6CAAwF;AAExF,+BAAoC;AAA3B,kGAAA,UAAU,OAAA;AACnB,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA;AAEzB,2CAAwF;AAA/E,8GAAA,gBAAgB,OAAA;AAAE,yGAAA,WAAW,OAAA;AAAE,0GAAA,YAAY,OAAA;AAAE,yGAAA,WAAW,OAAA;AAoBjE,MAAM,SAAS,GAAG;IAChB,IAAI,EAAE,iBAAU;IAEhB,SAAS,EAAE,4BAAgB;IAC3B,UAAU,EAAE;QACV,UAAU,EAAE,6BAAgB;QAC5B,WAAW,EAAX,wBAAW;QACX,YAAY,EAAZ,yBAAY;QACZ,WAAW,EAAX,wBAAW;KACZ;IAED,KAAK,EAAE;QACL,iBAAiB,EAAE,iBAAU,CAAC,iBAAiB;QAC/C,eAAe,EAAE,iBAAU,CAAC,eAAe;QAC3C,gBAAgB,EAAE,iBAAU,CAAC,gBAAgB;QAC7C,sBAAsB,EAAE,iBAAU,CAAC,sBAAsB;QACzD,SAAS,EAAE,4BAAgB,CAAC,SAAS;QACrC,oBAAoB,EAAE,4BAAgB,CAAC,oBAAoB;KAC5D;IAED;;;;OAIG;IACH,UAAU,EAAE,4BAAgB,CAAC,UAAU;IAEvC;;;;OAIG;IACH,YAAY,EAAE,4BAAgB,CAAC,YAAY;IAC3C,gBAAgB,EAAE,4BAAgB,CAAC,gBAAgB;IACnD,YAAY,EAAE,4BAAgB,CAAC,YAAY;IAE3C,SAAS,EAAE;QACT,WAAW,EAAE;YACX,OAAO,EAAE,SAAkB;YAC3B,UAAU,EAAE,YAAqB;YACjC,SAAS,EAAE,WAAoB;YAC/B,MAAM,EAAE,QAAiB;YACzB,SAAS,EAAE,WAAoB;YAC/B,gBAAgB,EAAE,kBAA2B;SAC9C;QAED,SAAS,EAAE;YACT,OAAO,EAAE,SAAkB;YAC3B,MAAM,EAAE,QAAiB;YACzB,MAAM,EAAE,QAAiB;SAC1B;QAED,QAAQ,EAAE;YACR,iBAAiB,EAAE,MAAM;YACzB,UAAU,EAAE,GAAG;YACf,iBAAiB,EAAE,KAAK;YACxB,WAAW,EAAE,CAAC;SACf;KACF;CACF,CAAC;AAEF,kBAAe,SAAS,CAAC;AAEZ,QAAA,IAAI,GAAG,iBAAU,CAAC;AAClB,QAAA,SAAS,GAAG,4BAAgB,CAAC;AAC7B,QAAA,UAAU,GAAG;IACxB,UAAU,EAAE,6BAAgB;IAC5B,WAAW,EAAX,wBAAW;IACX,YAAY,EAAZ,yBAAY;IACZ,WAAW,EAAX,wBAAW;CACZ,CAAC"}
|