@onesub/server 0.21.0 → 0.21.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/dist/__tests__/errors.test.d.ts +12 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/errors.d.ts +34 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.cjs +79 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +79 -152
- package/dist/index.js.map +1 -1
- package/dist/routes/admin.d.ts.map +1 -1
- package/dist/routes/apple-offer.d.ts.map +1 -1
- package/dist/routes/entitlements.d.ts.map +1 -1
- package/dist/routes/purchase.d.ts.map +1 -1
- package/dist/routes/validate.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1271,6 +1271,16 @@ function sendZodError(res, err2, extra = {}) {
|
|
|
1271
1271
|
extra
|
|
1272
1272
|
);
|
|
1273
1273
|
}
|
|
1274
|
+
function parseOrSend(res, schema, input, opts = {}) {
|
|
1275
|
+
const result = schema.safeParse(input);
|
|
1276
|
+
if (result.success) return result.data;
|
|
1277
|
+
if (opts.message !== void 0) {
|
|
1278
|
+
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, opts.message, opts.extra ?? {});
|
|
1279
|
+
} else {
|
|
1280
|
+
sendZodError(res, result.error, opts.extra ?? {});
|
|
1281
|
+
}
|
|
1282
|
+
return void 0;
|
|
1283
|
+
}
|
|
1274
1284
|
|
|
1275
1285
|
// src/apps.ts
|
|
1276
1286
|
function appName(app) {
|
|
@@ -1369,20 +1379,9 @@ function createValidateRouter(config, store) {
|
|
|
1369
1379
|
const router = Router();
|
|
1370
1380
|
const registry = getAppRegistry(config);
|
|
1371
1381
|
router.post(ROUTES.VALIDATE, async (req, res) => {
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
let productId;
|
|
1376
|
-
let appId;
|
|
1377
|
-
try {
|
|
1378
|
-
({ platform, receipt, userId, productId, appId } = validateSchema.parse(req.body));
|
|
1379
|
-
} catch (err2) {
|
|
1380
|
-
if (err2 instanceof z.ZodError) {
|
|
1381
|
-
sendZodError(res, err2, NO_SUB);
|
|
1382
|
-
return;
|
|
1383
|
-
}
|
|
1384
|
-
throw err2;
|
|
1385
|
-
}
|
|
1382
|
+
const body = parseOrSend(res, validateSchema, req.body, { extra: NO_SUB });
|
|
1383
|
+
if (!body) return;
|
|
1384
|
+
const { platform, receipt, userId, productId, appId } = body;
|
|
1386
1385
|
try {
|
|
1387
1386
|
let sub = null;
|
|
1388
1387
|
const appConfig = registry.configFor({
|
|
@@ -1991,16 +1990,8 @@ function createPurchaseRouter(config, purchaseStore) {
|
|
|
1991
1990
|
const router = Router();
|
|
1992
1991
|
const registry = getAppRegistry(config);
|
|
1993
1992
|
router.post(ROUTES.VALIDATE_PURCHASE, async (req, res) => {
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
body = validatePurchaseSchema.parse(req.body);
|
|
1997
|
-
} catch (err2) {
|
|
1998
|
-
if (err2 instanceof z.ZodError) {
|
|
1999
|
-
sendZodError(res, err2, NO_PURCHASE);
|
|
2000
|
-
return;
|
|
2001
|
-
}
|
|
2002
|
-
throw err2;
|
|
2003
|
-
}
|
|
1993
|
+
const body = parseOrSend(res, validatePurchaseSchema, req.body, { extra: NO_PURCHASE });
|
|
1994
|
+
if (!body) return;
|
|
2004
1995
|
const { platform, receipt, userId, productId, type, appId } = body;
|
|
2005
1996
|
const appConfig = registry.configFor({
|
|
2006
1997
|
appId,
|
|
@@ -2126,16 +2117,10 @@ function createPurchaseRouter(config, purchaseStore) {
|
|
|
2126
2117
|
}
|
|
2127
2118
|
});
|
|
2128
2119
|
router.get(ROUTES.PURCHASE_STATUS, async (req, res) => {
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
if (err2 instanceof z.ZodError) {
|
|
2134
|
-
sendZodError(res, err2, { purchases: [] });
|
|
2135
|
-
return;
|
|
2136
|
-
}
|
|
2137
|
-
throw err2;
|
|
2138
|
-
}
|
|
2120
|
+
const query = parseOrSend(res, purchaseStatusQuerySchema, req.query, {
|
|
2121
|
+
extra: { purchases: [] }
|
|
2122
|
+
});
|
|
2123
|
+
if (!query) return;
|
|
2139
2124
|
const { userId, productId } = query;
|
|
2140
2125
|
try {
|
|
2141
2126
|
const purchases = productId !== void 0 ? await purchasesForProduct(purchaseStore, userId, productId) : await purchaseStore.getPurchasesByUserId(userId);
|
|
@@ -2183,6 +2168,8 @@ async function evaluateEntitlement(userId, entitlement, store, purchaseStore) {
|
|
|
2183
2168
|
}
|
|
2184
2169
|
var userIdSchema = z.string().min(1).max(256);
|
|
2185
2170
|
var entitlementIdSchema = z.string().min(1).max(128);
|
|
2171
|
+
var entitlementQuerySchema = z.object({ userId: userIdSchema, id: entitlementIdSchema });
|
|
2172
|
+
var entitlementsQuerySchema = z.object({ userId: userIdSchema });
|
|
2186
2173
|
function createEntitlementRouter(config, store, purchaseStore) {
|
|
2187
2174
|
if (!config.entitlements || Object.keys(config.entitlements).length === 0) {
|
|
2188
2175
|
return null;
|
|
@@ -2190,15 +2177,11 @@ function createEntitlementRouter(config, store, purchaseStore) {
|
|
|
2190
2177
|
const entitlements = config.entitlements;
|
|
2191
2178
|
const router = Router();
|
|
2192
2179
|
router.get(ROUTES.ENTITLEMENT, async (req, res) => {
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
} catch {
|
|
2199
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "userId and id are required");
|
|
2200
|
-
return;
|
|
2201
|
-
}
|
|
2180
|
+
const query = parseOrSend(res, entitlementQuerySchema, req.query, {
|
|
2181
|
+
message: "userId and id are required"
|
|
2182
|
+
});
|
|
2183
|
+
if (!query) return;
|
|
2184
|
+
const { userId, id } = query;
|
|
2202
2185
|
const entitlement = entitlements[id];
|
|
2203
2186
|
if (!entitlement) {
|
|
2204
2187
|
sendError(res, 404, ONESUB_ERROR_CODE.ENTITLEMENT_NOT_FOUND, `Unknown entitlement: ${id}`);
|
|
@@ -2214,13 +2197,11 @@ function createEntitlementRouter(config, store, purchaseStore) {
|
|
|
2214
2197
|
}
|
|
2215
2198
|
});
|
|
2216
2199
|
router.get(ROUTES.ENTITLEMENTS, async (req, res) => {
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
return;
|
|
2223
|
-
}
|
|
2200
|
+
const query = parseOrSend(res, entitlementsQuerySchema, req.query, {
|
|
2201
|
+
message: "userId is required"
|
|
2202
|
+
});
|
|
2203
|
+
if (!query) return;
|
|
2204
|
+
const { userId } = query;
|
|
2224
2205
|
try {
|
|
2225
2206
|
const [subs, purchases] = await Promise.all([
|
|
2226
2207
|
store.getAllByUserId(userId),
|
|
@@ -2269,13 +2250,10 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2269
2250
|
productId: z.string().min(1).max(256)
|
|
2270
2251
|
});
|
|
2271
2252
|
router.delete("/onesub/purchase/admin/:userId/:productId", async (req, res) => {
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "userId and productId required");
|
|
2277
|
-
return;
|
|
2278
|
-
}
|
|
2253
|
+
const params = parseOrSend(res, resetParamsSchema, req.params, {
|
|
2254
|
+
message: "userId and productId required"
|
|
2255
|
+
});
|
|
2256
|
+
if (!params) return;
|
|
2279
2257
|
const deleted = await purchaseStore.deletePurchases(params.userId, params.productId);
|
|
2280
2258
|
res.json({ ok: true, deleted });
|
|
2281
2259
|
});
|
|
@@ -2284,16 +2262,8 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2284
2262
|
newUserId: z.string().min(1).max(256)
|
|
2285
2263
|
});
|
|
2286
2264
|
router.post("/onesub/purchase/admin/transfer", async (req, res) => {
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
body = transferSchema.parse(req.body);
|
|
2290
|
-
} catch (err2) {
|
|
2291
|
-
if (err2 instanceof z.ZodError) {
|
|
2292
|
-
sendZodError(res, err2);
|
|
2293
|
-
return;
|
|
2294
|
-
}
|
|
2295
|
-
throw err2;
|
|
2296
|
-
}
|
|
2265
|
+
const body = parseOrSend(res, transferSchema, req.body);
|
|
2266
|
+
if (!body) return;
|
|
2297
2267
|
const existing = await purchaseStore.getPurchaseByTransactionId(body.transactionId);
|
|
2298
2268
|
if (!existing) {
|
|
2299
2269
|
sendError(res, 404, ONESUB_ERROR_CODE.TRANSACTION_NOT_FOUND, "TRANSACTION_NOT_FOUND");
|
|
@@ -2315,16 +2285,8 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2315
2285
|
transactionId: z.string().min(1).max(256).optional()
|
|
2316
2286
|
});
|
|
2317
2287
|
router.post("/onesub/purchase/admin/grant", async (req, res) => {
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
body = grantSchema.parse(req.body);
|
|
2321
|
-
} catch (err2) {
|
|
2322
|
-
if (err2 instanceof z.ZodError) {
|
|
2323
|
-
sendZodError(res, err2);
|
|
2324
|
-
return;
|
|
2325
|
-
}
|
|
2326
|
-
throw err2;
|
|
2327
|
-
}
|
|
2288
|
+
const body = parseOrSend(res, grantSchema, req.body);
|
|
2289
|
+
if (!body) return;
|
|
2328
2290
|
const transactionId = body.transactionId ?? `admin_grant_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
2329
2291
|
const purchase = {
|
|
2330
2292
|
transactionId,
|
|
@@ -2356,16 +2318,8 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2356
2318
|
offset: z.coerce.number().int().nonnegative().optional()
|
|
2357
2319
|
});
|
|
2358
2320
|
router.get(ROUTES.ADMIN_SUBSCRIPTIONS, async (req, res) => {
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
query = listQuerySchema.parse(req.query);
|
|
2362
|
-
} catch (err2) {
|
|
2363
|
-
if (err2 instanceof z.ZodError) {
|
|
2364
|
-
sendZodError(res, err2);
|
|
2365
|
-
return;
|
|
2366
|
-
}
|
|
2367
|
-
throw err2;
|
|
2368
|
-
}
|
|
2321
|
+
const query = parseOrSend(res, listQuerySchema, req.query);
|
|
2322
|
+
if (!query) return;
|
|
2369
2323
|
try {
|
|
2370
2324
|
const result = await store.listFiltered(query);
|
|
2371
2325
|
const response = {
|
|
@@ -2376,20 +2330,18 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2376
2330
|
};
|
|
2377
2331
|
res.status(200).json(response);
|
|
2378
2332
|
} catch (err2) {
|
|
2379
|
-
|
|
2333
|
+
log.error("[onesub/admin/subscriptions] list error:", err2);
|
|
2334
|
+
sendError(res, 500, ONESUB_ERROR_CODE.STORE_ERROR, "Internal server error");
|
|
2380
2335
|
}
|
|
2381
2336
|
});
|
|
2382
2337
|
const detailParamsSchema = z.object({
|
|
2383
2338
|
transactionId: z.string().min(1).max(256)
|
|
2384
2339
|
});
|
|
2385
2340
|
router.get("/onesub/admin/subscriptions/:transactionId", async (req, res) => {
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "transactionId required");
|
|
2391
|
-
return;
|
|
2392
|
-
}
|
|
2341
|
+
const params = parseOrSend(res, detailParamsSchema, req.params, {
|
|
2342
|
+
message: "transactionId required"
|
|
2343
|
+
});
|
|
2344
|
+
if (!params) return;
|
|
2393
2345
|
try {
|
|
2394
2346
|
const sub = await store.getByTransactionId(params.transactionId);
|
|
2395
2347
|
if (!sub) {
|
|
@@ -2398,20 +2350,18 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2398
2350
|
}
|
|
2399
2351
|
res.status(200).json(sub);
|
|
2400
2352
|
} catch (err2) {
|
|
2401
|
-
|
|
2353
|
+
log.error("[onesub/admin/subscriptions/:transactionId] detail error:", err2);
|
|
2354
|
+
sendError(res, 500, ONESUB_ERROR_CODE.STORE_ERROR, "Internal server error");
|
|
2402
2355
|
}
|
|
2403
2356
|
});
|
|
2404
2357
|
const customerParamsSchema = z.object({
|
|
2405
2358
|
userId: z.string().min(1).max(256)
|
|
2406
2359
|
});
|
|
2407
2360
|
router.get("/onesub/admin/customers/:userId", async (req, res) => {
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "userId required");
|
|
2413
|
-
return;
|
|
2414
|
-
}
|
|
2361
|
+
const params = parseOrSend(res, customerParamsSchema, req.params, {
|
|
2362
|
+
message: "userId required"
|
|
2363
|
+
});
|
|
2364
|
+
if (!params) return;
|
|
2415
2365
|
try {
|
|
2416
2366
|
const [subscriptions, purchases] = await Promise.all([
|
|
2417
2367
|
store.getAllByUserId(params.userId),
|
|
@@ -2433,20 +2383,18 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2433
2383
|
};
|
|
2434
2384
|
res.status(200).json(response);
|
|
2435
2385
|
} catch (err2) {
|
|
2436
|
-
|
|
2386
|
+
log.error("[onesub/admin/customers/:userId] error:", err2);
|
|
2387
|
+
sendError(res, 500, ONESUB_ERROR_CODE.STORE_ERROR, "Internal server error");
|
|
2437
2388
|
}
|
|
2438
2389
|
});
|
|
2439
2390
|
const syncAppleParamsSchema = z.object({
|
|
2440
2391
|
originalTransactionId: z.string().min(1).max(256)
|
|
2441
2392
|
});
|
|
2442
2393
|
router.post(ROUTES.ADMIN_SYNC_APPLE, async (req, res) => {
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "originalTransactionId required");
|
|
2448
|
-
return;
|
|
2449
|
-
}
|
|
2394
|
+
const params = parseOrSend(res, syncAppleParamsSchema, req.params, {
|
|
2395
|
+
message: "originalTransactionId required"
|
|
2396
|
+
});
|
|
2397
|
+
if (!params) return;
|
|
2450
2398
|
if (!config.apple?.issuerId || !config.apple?.keyId || !config.apple?.privateKey) {
|
|
2451
2399
|
sendError(res, 400, ONESUB_ERROR_CODE.APPLE_CONFIG_MISSING, "Apple API credentials not configured");
|
|
2452
2400
|
return;
|
|
@@ -2465,7 +2413,8 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2465
2413
|
await store.save(fresh);
|
|
2466
2414
|
res.status(200).json({ ok: true, subscription: fresh });
|
|
2467
2415
|
} catch (err2) {
|
|
2468
|
-
|
|
2416
|
+
log.error("[onesub/admin/sync-apple] error:", err2);
|
|
2417
|
+
sendError(res, 500, ONESUB_ERROR_CODE.INTERNAL_ERROR, "Internal server error");
|
|
2469
2418
|
}
|
|
2470
2419
|
});
|
|
2471
2420
|
const overrideParamsSchema = z.object({ userId: z.string().min(1).max(256) });
|
|
@@ -2474,19 +2423,10 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2474
2423
|
res.json({ overrides: listTestOverrides() });
|
|
2475
2424
|
});
|
|
2476
2425
|
router.put(ROUTES.ADMIN_TEST_OVERRIDE, (req, res) => {
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
body = overrideBodySchema.parse(req.body);
|
|
2482
|
-
} catch (err2) {
|
|
2483
|
-
if (err2 instanceof z.ZodError) {
|
|
2484
|
-
sendZodError(res, err2);
|
|
2485
|
-
} else {
|
|
2486
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "userId and { entitled: boolean } required");
|
|
2487
|
-
}
|
|
2488
|
-
return;
|
|
2489
|
-
}
|
|
2426
|
+
const params = parseOrSend(res, overrideParamsSchema, req.params);
|
|
2427
|
+
if (!params) return;
|
|
2428
|
+
const body = parseOrSend(res, overrideBodySchema, req.body);
|
|
2429
|
+
if (!body) return;
|
|
2490
2430
|
setTestOverride(params.userId, body.entitled);
|
|
2491
2431
|
log.warn(
|
|
2492
2432
|
`[onesub/admin] sandbox test override set for ${params.userId}: entitled=${body.entitled}`
|
|
@@ -2494,13 +2434,10 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2494
2434
|
res.json({ ok: true, userId: params.userId, entitled: body.entitled, sandboxOnly: true });
|
|
2495
2435
|
});
|
|
2496
2436
|
router.delete(ROUTES.ADMIN_TEST_OVERRIDE, (req, res) => {
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "userId required");
|
|
2502
|
-
return;
|
|
2503
|
-
}
|
|
2437
|
+
const params = parseOrSend(res, overrideParamsSchema, req.params, {
|
|
2438
|
+
message: "userId required"
|
|
2439
|
+
});
|
|
2440
|
+
if (!params) return;
|
|
2504
2441
|
const cleared = clearTestOverride(params.userId);
|
|
2505
2442
|
res.json({ ok: true, userId: params.userId, cleared });
|
|
2506
2443
|
});
|
|
@@ -2510,25 +2447,22 @@ function createAdminRouter(config, purchaseStore, store, webhookQueue) {
|
|
|
2510
2447
|
const items = await webhookQueue.listDeadLetters();
|
|
2511
2448
|
res.status(200).json({ items });
|
|
2512
2449
|
} catch (err2) {
|
|
2513
|
-
|
|
2450
|
+
log.error("[onesub/admin/webhook-deadletters] error:", err2);
|
|
2451
|
+
sendError(res, 500, ONESUB_ERROR_CODE.STORE_ERROR, "Internal server error");
|
|
2514
2452
|
}
|
|
2515
2453
|
});
|
|
2516
2454
|
}
|
|
2517
2455
|
if (webhookQueue?.replayDeadLetter) {
|
|
2518
2456
|
const replayParamsSchema = z.object({ id: z.string().min(1).max(256) });
|
|
2519
2457
|
router.post("/onesub/admin/webhook-replay/:id", async (req, res) => {
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
params = replayParamsSchema.parse(req.params);
|
|
2523
|
-
} catch {
|
|
2524
|
-
sendError(res, 400, ONESUB_ERROR_CODE.INVALID_INPUT, "id required");
|
|
2525
|
-
return;
|
|
2526
|
-
}
|
|
2458
|
+
const params = parseOrSend(res, replayParamsSchema, req.params, { message: "id required" });
|
|
2459
|
+
if (!params) return;
|
|
2527
2460
|
try {
|
|
2528
2461
|
await webhookQueue.replayDeadLetter(params.id);
|
|
2529
2462
|
res.status(200).json({ ok: true });
|
|
2530
2463
|
} catch (err2) {
|
|
2531
|
-
|
|
2464
|
+
log.error("[onesub/admin/webhook-replay] error:", err2);
|
|
2465
|
+
sendError(res, 500, ONESUB_ERROR_CODE.STORE_ERROR, "Internal server error");
|
|
2532
2466
|
}
|
|
2533
2467
|
});
|
|
2534
2468
|
}
|
|
@@ -2787,16 +2721,8 @@ function createAppleOfferRouter(config) {
|
|
|
2787
2721
|
return;
|
|
2788
2722
|
}
|
|
2789
2723
|
}
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
body = offerBodySchema.parse(req.body);
|
|
2793
|
-
} catch (err2) {
|
|
2794
|
-
if (err2 instanceof z.ZodError) {
|
|
2795
|
-
sendZodError(res, err2);
|
|
2796
|
-
return;
|
|
2797
|
-
}
|
|
2798
|
-
throw err2;
|
|
2799
|
-
}
|
|
2724
|
+
const body = parseOrSend(res, offerBodySchema, req.body);
|
|
2725
|
+
if (!body) return;
|
|
2800
2726
|
if (!apple.bundleId) {
|
|
2801
2727
|
sendError(res, 400, ONESUB_ERROR_CODE.APPLE_CONFIG_MISSING, "config.apple.bundleId is required for offer signing");
|
|
2802
2728
|
return;
|
|
@@ -2813,7 +2739,8 @@ function createAppleOfferRouter(config) {
|
|
|
2813
2739
|
);
|
|
2814
2740
|
res.status(200).json(result);
|
|
2815
2741
|
} catch (err2) {
|
|
2816
|
-
|
|
2742
|
+
log.error("[onesub/apple/offer] signing error:", err2);
|
|
2743
|
+
sendError(res, 500, ONESUB_ERROR_CODE.INTERNAL_ERROR, "Offer signing failed");
|
|
2817
2744
|
}
|
|
2818
2745
|
});
|
|
2819
2746
|
return router;
|