@agentcash/router 0.4.6 → 0.4.7
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/.claude/CLAUDE.md +129 -0
- package/dist/client/index.cjs +94 -0
- package/dist/client/index.d.cts +86 -0
- package/dist/client/index.d.ts +86 -0
- package/dist/client/index.js +56 -0
- package/dist/index.cjs +219 -36
- package/dist/index.d.cts +75 -1
- package/dist/index.d.ts +75 -1
- package/dist/index.js +216 -36
- package/dist/siwx-BMlja_nt.d.cts +9 -0
- package/dist/siwx-BMlja_nt.d.ts +9 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -130,6 +130,10 @@ function consolePlugin() {
|
|
|
130
130
|
const ctx = createDefaultContext(meta);
|
|
131
131
|
return ctx;
|
|
132
132
|
},
|
|
133
|
+
onAuthVerified(_ctx, auth) {
|
|
134
|
+
const wallet = auth.wallet ? ` wallet=${auth.wallet}` : "";
|
|
135
|
+
console.log(`[router] AUTH ${auth.authMode} ${auth.route}${wallet}`);
|
|
136
|
+
},
|
|
133
137
|
onPaymentVerified(_ctx, payment) {
|
|
134
138
|
console.log(`[router] VERIFIED ${payment.protocol} ${payment.payer} ${payment.amount}`);
|
|
135
139
|
},
|
|
@@ -159,6 +163,65 @@ function consolePlugin() {
|
|
|
159
163
|
};
|
|
160
164
|
}
|
|
161
165
|
|
|
166
|
+
// src/auth/nonce.ts
|
|
167
|
+
var SIWX_CHALLENGE_EXPIRY_MS = 5 * 60 * 1e3;
|
|
168
|
+
var MemoryNonceStore = class {
|
|
169
|
+
seen = /* @__PURE__ */ new Map();
|
|
170
|
+
async check(nonce) {
|
|
171
|
+
this.evict();
|
|
172
|
+
if (this.seen.has(nonce)) return false;
|
|
173
|
+
this.seen.set(nonce, Date.now() + SIWX_CHALLENGE_EXPIRY_MS);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
evict() {
|
|
177
|
+
const now = Date.now();
|
|
178
|
+
for (const [n, exp] of this.seen) {
|
|
179
|
+
if (exp < now) this.seen.delete(n);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
function detectRedisClientType(client) {
|
|
184
|
+
if (!client || typeof client !== "object") {
|
|
185
|
+
throw new Error(
|
|
186
|
+
"createRedisNonceStore requires a Redis client. Supported: @upstash/redis, ioredis. Pass your Redis client instance as the first argument."
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
if ("options" in client && "status" in client) {
|
|
190
|
+
return "ioredis";
|
|
191
|
+
}
|
|
192
|
+
const constructor = client.constructor?.name;
|
|
193
|
+
if (constructor === "Redis" && "url" in client) {
|
|
194
|
+
return "upstash";
|
|
195
|
+
}
|
|
196
|
+
if (typeof client.set === "function") {
|
|
197
|
+
return "upstash";
|
|
198
|
+
}
|
|
199
|
+
throw new Error(
|
|
200
|
+
"Unrecognized Redis client. Supported: @upstash/redis, ioredis. If using a different client, implement NonceStore interface directly."
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
function createRedisNonceStore(client, opts) {
|
|
204
|
+
const prefix = opts?.prefix ?? "siwx:nonce:";
|
|
205
|
+
const ttlSeconds = Math.ceil((opts?.ttlMs ?? SIWX_CHALLENGE_EXPIRY_MS) / 1e3);
|
|
206
|
+
const clientType = detectRedisClientType(client);
|
|
207
|
+
return {
|
|
208
|
+
async check(nonce) {
|
|
209
|
+
const key = `${prefix}${nonce}`;
|
|
210
|
+
if (clientType === "upstash") {
|
|
211
|
+
const redis = client;
|
|
212
|
+
const result = await redis.set(key, "1", { ex: ttlSeconds, nx: true });
|
|
213
|
+
return result !== null;
|
|
214
|
+
}
|
|
215
|
+
if (clientType === "ioredis") {
|
|
216
|
+
const redis = client;
|
|
217
|
+
const result = await redis.set(key, "1", "EX", ttlSeconds, "NX");
|
|
218
|
+
return result === "OK";
|
|
219
|
+
}
|
|
220
|
+
throw new Error("Unknown Redis client type");
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
162
225
|
// src/protocols/detect.ts
|
|
163
226
|
function detectProtocol(request) {
|
|
164
227
|
if (request.headers.get("PAYMENT-SIGNATURE") || request.headers.get("X-PAYMENT")) {
|
|
@@ -433,21 +496,47 @@ function buildMPPReceipt(reference) {
|
|
|
433
496
|
}
|
|
434
497
|
|
|
435
498
|
// src/auth/siwx.ts
|
|
499
|
+
var SIWX_ERROR_MESSAGES = {
|
|
500
|
+
siwx_missing_header: "Missing SIGN-IN-WITH-X header",
|
|
501
|
+
siwx_malformed: "Malformed SIWX payload",
|
|
502
|
+
siwx_expired: "SIWX message expired \u2014 request a new challenge",
|
|
503
|
+
siwx_nonce_used: "Nonce already used \u2014 request a new challenge",
|
|
504
|
+
siwx_invalid_signature: "Invalid signature \u2014 wallet mismatch or corrupted proof"
|
|
505
|
+
};
|
|
506
|
+
function categorizeValidationError(error) {
|
|
507
|
+
if (!error) return "siwx_malformed";
|
|
508
|
+
const err = error.toLowerCase();
|
|
509
|
+
if (err.includes("expired") || err.includes("message too old")) {
|
|
510
|
+
return "siwx_expired";
|
|
511
|
+
}
|
|
512
|
+
if (err.includes("nonce validation failed")) {
|
|
513
|
+
return "siwx_nonce_used";
|
|
514
|
+
}
|
|
515
|
+
return "siwx_malformed";
|
|
516
|
+
}
|
|
436
517
|
async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
437
518
|
const { parseSIWxHeader, validateSIWxMessage, verifySIWxSignature } = await import("@x402/extensions/sign-in-with-x");
|
|
438
519
|
const header = request.headers.get("SIGN-IN-WITH-X");
|
|
439
|
-
if (!header)
|
|
440
|
-
|
|
520
|
+
if (!header) {
|
|
521
|
+
return { valid: false, wallet: null, code: "siwx_missing_header" };
|
|
522
|
+
}
|
|
523
|
+
let payload;
|
|
524
|
+
try {
|
|
525
|
+
payload = parseSIWxHeader(header);
|
|
526
|
+
} catch {
|
|
527
|
+
return { valid: false, wallet: null, code: "siwx_malformed" };
|
|
528
|
+
}
|
|
441
529
|
const uri = request.url;
|
|
442
530
|
const validation = await validateSIWxMessage(payload, uri, {
|
|
443
531
|
checkNonce: (nonce) => nonceStore.check(nonce)
|
|
444
532
|
});
|
|
445
533
|
if (!validation.valid) {
|
|
446
|
-
|
|
534
|
+
const code = categorizeValidationError(validation.error);
|
|
535
|
+
return { valid: false, wallet: null, code };
|
|
447
536
|
}
|
|
448
537
|
const verified = await verifySIWxSignature(payload);
|
|
449
538
|
if (!verified?.valid) {
|
|
450
|
-
return { valid: false, wallet: null };
|
|
539
|
+
return { valid: false, wallet: null, code: "siwx_invalid_signature" };
|
|
451
540
|
}
|
|
452
541
|
return { valid: true, wallet: verified.address };
|
|
453
542
|
}
|
|
@@ -521,6 +610,15 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
521
610
|
firePluginResponse(deps, pluginCtx, meta, body2.response);
|
|
522
611
|
return body2.response;
|
|
523
612
|
}
|
|
613
|
+
if (routeEntry.validateFn) {
|
|
614
|
+
try {
|
|
615
|
+
await routeEntry.validateFn(body2.data);
|
|
616
|
+
} catch (err) {
|
|
617
|
+
const status = err.status ?? 400;
|
|
618
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
619
|
+
return fail(status, message, meta, pluginCtx);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
524
622
|
const { response, rawResult } = await invoke(
|
|
525
623
|
request,
|
|
526
624
|
meta,
|
|
@@ -545,13 +643,20 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
545
643
|
return fail(401, "Invalid or missing API key", meta, pluginCtx);
|
|
546
644
|
}
|
|
547
645
|
account = keyResult.account;
|
|
646
|
+
firePluginHook(deps.plugin, "onAuthVerified", pluginCtx, {
|
|
647
|
+
authMode: "apiKey",
|
|
648
|
+
wallet: null,
|
|
649
|
+
route: routeEntry.key,
|
|
650
|
+
account
|
|
651
|
+
});
|
|
548
652
|
if (routeEntry.authMode === "apiKey" && !routeEntry.pricing) {
|
|
549
653
|
return handleAuth(null, account);
|
|
550
654
|
}
|
|
551
655
|
}
|
|
552
656
|
const protocol = detectProtocol(request);
|
|
553
657
|
let earlyBodyData;
|
|
554
|
-
|
|
658
|
+
const needsEarlyParse = !protocol && routeEntry.bodySchema && (typeof routeEntry.pricing === "function" || routeEntry.validateFn);
|
|
659
|
+
if (needsEarlyParse) {
|
|
555
660
|
const requestForPricing = request.clone();
|
|
556
661
|
const earlyBodyResult = await parseBody(requestForPricing, routeEntry);
|
|
557
662
|
if (!earlyBodyResult.ok) {
|
|
@@ -559,11 +664,35 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
559
664
|
return earlyBodyResult.response;
|
|
560
665
|
}
|
|
561
666
|
earlyBodyData = earlyBodyResult.data;
|
|
667
|
+
if (routeEntry.validateFn) {
|
|
668
|
+
try {
|
|
669
|
+
await routeEntry.validateFn(earlyBodyData);
|
|
670
|
+
} catch (err) {
|
|
671
|
+
const status = err.status ?? 400;
|
|
672
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
673
|
+
return fail(status, message, meta, pluginCtx);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
562
676
|
}
|
|
563
677
|
if (routeEntry.authMode === "siwx") {
|
|
678
|
+
if (routeEntry.validateFn && routeEntry.bodySchema && !request.headers.get("SIGN-IN-WITH-X")) {
|
|
679
|
+
const requestForValidation = request.clone();
|
|
680
|
+
const earlyBodyResult = await parseBody(requestForValidation, routeEntry);
|
|
681
|
+
if (!earlyBodyResult.ok) {
|
|
682
|
+
firePluginResponse(deps, pluginCtx, meta, earlyBodyResult.response);
|
|
683
|
+
return earlyBodyResult.response;
|
|
684
|
+
}
|
|
685
|
+
try {
|
|
686
|
+
await routeEntry.validateFn(earlyBodyResult.data);
|
|
687
|
+
} catch (err) {
|
|
688
|
+
const status = err.status ?? 400;
|
|
689
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
690
|
+
return fail(status, message, meta, pluginCtx);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
564
693
|
if (!request.headers.get("SIGN-IN-WITH-X")) {
|
|
565
694
|
const url = new URL(request.url);
|
|
566
|
-
const nonce = crypto.randomUUID();
|
|
695
|
+
const nonce = crypto.randomUUID().replace(/-/g, "");
|
|
567
696
|
const siwxInfo = {
|
|
568
697
|
domain: url.hostname,
|
|
569
698
|
uri: request.url,
|
|
@@ -572,7 +701,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
572
701
|
type: "eip191",
|
|
573
702
|
nonce,
|
|
574
703
|
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
575
|
-
expirationTime: new Date(Date.now() +
|
|
704
|
+
expirationTime: new Date(Date.now() + SIWX_CHALLENGE_EXPIRY_MS).toISOString(),
|
|
576
705
|
statement: "Sign in to verify your wallet identity"
|
|
577
706
|
};
|
|
578
707
|
let siwxSchema;
|
|
@@ -592,6 +721,8 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
592
721
|
extensions: {
|
|
593
722
|
"sign-in-with-x": {
|
|
594
723
|
info: siwxInfo,
|
|
724
|
+
// supportedChains at top level required by MCP tools for chain detection
|
|
725
|
+
supportedChains: [{ chainId: deps.network, type: "eip191" }],
|
|
595
726
|
...siwxSchema ? { schema: siwxSchema } : {}
|
|
596
727
|
}
|
|
597
728
|
}
|
|
@@ -617,15 +748,21 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
617
748
|
}
|
|
618
749
|
const siwx = await verifySIWX(request, routeEntry, deps.nonceStore);
|
|
619
750
|
if (!siwx.valid) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
meta,
|
|
624
|
-
pluginCtx
|
|
751
|
+
const response = NextResponse2.json(
|
|
752
|
+
{ error: siwx.code, message: SIWX_ERROR_MESSAGES[siwx.code] },
|
|
753
|
+
{ status: 402 }
|
|
625
754
|
);
|
|
755
|
+
firePluginResponse(deps, pluginCtx, meta, response);
|
|
756
|
+
return response;
|
|
626
757
|
}
|
|
627
|
-
|
|
628
|
-
|
|
758
|
+
const wallet = siwx.wallet.toLowerCase();
|
|
759
|
+
pluginCtx.setVerifiedWallet(wallet);
|
|
760
|
+
firePluginHook(deps.plugin, "onAuthVerified", pluginCtx, {
|
|
761
|
+
authMode: "siwx",
|
|
762
|
+
wallet,
|
|
763
|
+
route: routeEntry.key
|
|
764
|
+
});
|
|
765
|
+
return handleAuth(wallet, void 0);
|
|
629
766
|
}
|
|
630
767
|
if (!protocol || protocol === "siwx") {
|
|
631
768
|
return await build402(request, routeEntry, deps, meta, pluginCtx, earlyBodyData);
|
|
@@ -635,6 +772,15 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
635
772
|
firePluginResponse(deps, pluginCtx, meta, body.response);
|
|
636
773
|
return body.response;
|
|
637
774
|
}
|
|
775
|
+
if (routeEntry.validateFn) {
|
|
776
|
+
try {
|
|
777
|
+
await routeEntry.validateFn(body.data);
|
|
778
|
+
} catch (err) {
|
|
779
|
+
const status = err.status ?? 400;
|
|
780
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
781
|
+
return fail(status, message, meta, pluginCtx);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
638
784
|
let price;
|
|
639
785
|
try {
|
|
640
786
|
price = await resolvePrice(routeEntry.pricing, body.data);
|
|
@@ -661,10 +807,11 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
661
807
|
);
|
|
662
808
|
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
663
809
|
const { payload: verifyPayload, requirements: verifyRequirements } = verify;
|
|
664
|
-
|
|
810
|
+
const wallet = verify.payer.toLowerCase();
|
|
811
|
+
pluginCtx.setVerifiedWallet(wallet);
|
|
665
812
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
666
813
|
protocol: "x402",
|
|
667
|
-
payer:
|
|
814
|
+
payer: wallet,
|
|
668
815
|
amount: price,
|
|
669
816
|
network: deps.network
|
|
670
817
|
});
|
|
@@ -672,7 +819,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
672
819
|
request,
|
|
673
820
|
meta,
|
|
674
821
|
pluginCtx,
|
|
675
|
-
|
|
822
|
+
wallet,
|
|
676
823
|
account,
|
|
677
824
|
body.data
|
|
678
825
|
);
|
|
@@ -723,7 +870,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
723
870
|
if (!deps.mppConfig) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
724
871
|
const verify = await verifyMPPCredential(request, routeEntry, deps.mppConfig, price);
|
|
725
872
|
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
726
|
-
const wallet = verify.payer;
|
|
873
|
+
const wallet = verify.payer.toLowerCase();
|
|
727
874
|
pluginCtx.setVerifiedWallet(wallet);
|
|
728
875
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
729
876
|
protocol: "mpp",
|
|
@@ -982,6 +1129,8 @@ var RouteBuilder = class {
|
|
|
982
1129
|
_providerName;
|
|
983
1130
|
/** @internal */
|
|
984
1131
|
_providerConfig;
|
|
1132
|
+
/** @internal */
|
|
1133
|
+
_validateFn;
|
|
985
1134
|
constructor(key, registry, deps) {
|
|
986
1135
|
this._key = key;
|
|
987
1136
|
this._registry = registry;
|
|
@@ -994,6 +1143,11 @@ var RouteBuilder = class {
|
|
|
994
1143
|
return next;
|
|
995
1144
|
}
|
|
996
1145
|
paid(pricing, options) {
|
|
1146
|
+
if (this._authMode === "siwx") {
|
|
1147
|
+
throw new Error(
|
|
1148
|
+
`route '${this._key}': Cannot combine .paid() and .siwx() on the same route. Paid routes get wallet identity from the payment proof. Use separate routes if you need both payment and SIWX auth.`
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
997
1151
|
const next = this.fork();
|
|
998
1152
|
next._authMode = "paid";
|
|
999
1153
|
next._pricing = pricing;
|
|
@@ -1023,6 +1177,11 @@ var RouteBuilder = class {
|
|
|
1023
1177
|
return next;
|
|
1024
1178
|
}
|
|
1025
1179
|
siwx() {
|
|
1180
|
+
if (this._authMode === "paid") {
|
|
1181
|
+
throw new Error(
|
|
1182
|
+
`route '${this._key}': Cannot combine .paid() and .siwx() on the same route. Paid routes get wallet identity from the payment proof. Use separate routes if you need both payment and SIWX auth.`
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1026
1185
|
const next = this.fork();
|
|
1027
1186
|
next._authMode = "siwx";
|
|
1028
1187
|
next._protocols = [];
|
|
@@ -1083,7 +1242,41 @@ var RouteBuilder = class {
|
|
|
1083
1242
|
next._method = m;
|
|
1084
1243
|
return next;
|
|
1085
1244
|
}
|
|
1245
|
+
// -------------------------------------------------------------------------
|
|
1246
|
+
// Pre-payment validation
|
|
1247
|
+
// -------------------------------------------------------------------------
|
|
1248
|
+
/**
|
|
1249
|
+
* Add pre-payment validation that runs after body parsing but before the 402
|
|
1250
|
+
* challenge is shown. Use this for async business logic like "is this resource
|
|
1251
|
+
* available?" or "has this user hit their rate limit?".
|
|
1252
|
+
*
|
|
1253
|
+
* Requires `.body()` — call `.body()` before `.validate()` for type inference.
|
|
1254
|
+
*
|
|
1255
|
+
* @example
|
|
1256
|
+
* ```typescript
|
|
1257
|
+
* router
|
|
1258
|
+
* .route('domain/register')
|
|
1259
|
+
* .paid(calculatePrice)
|
|
1260
|
+
* .body(RegisterSchema) // .body() first for type inference
|
|
1261
|
+
* .validate(async (body) => {
|
|
1262
|
+
* if (await isDomainTaken(body.domain)) {
|
|
1263
|
+
* throw Object.assign(new Error('Domain taken'), { status: 409 });
|
|
1264
|
+
* }
|
|
1265
|
+
* })
|
|
1266
|
+
* .handler(async ({ body }) => { ... });
|
|
1267
|
+
* ```
|
|
1268
|
+
*/
|
|
1269
|
+
validate(fn) {
|
|
1270
|
+
const next = this.fork();
|
|
1271
|
+
next._validateFn = fn;
|
|
1272
|
+
return next;
|
|
1273
|
+
}
|
|
1086
1274
|
handler(fn) {
|
|
1275
|
+
if (this._validateFn && !this._bodySchema) {
|
|
1276
|
+
throw new Error(
|
|
1277
|
+
`route '${this._key}': .validate() requires .body() \u2014 validation runs on parsed body`
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1087
1280
|
const entry = {
|
|
1088
1281
|
key: this._key,
|
|
1089
1282
|
authMode: this._authMode,
|
|
@@ -1098,30 +1291,14 @@ var RouteBuilder = class {
|
|
|
1098
1291
|
maxPrice: this._maxPrice,
|
|
1099
1292
|
apiKeyResolver: this._apiKeyResolver,
|
|
1100
1293
|
providerName: this._providerName,
|
|
1101
|
-
providerConfig: this._providerConfig
|
|
1294
|
+
providerConfig: this._providerConfig,
|
|
1295
|
+
validateFn: this._validateFn
|
|
1102
1296
|
};
|
|
1103
1297
|
this._registry.register(entry);
|
|
1104
1298
|
return createRequestHandler(entry, fn, this._deps);
|
|
1105
1299
|
}
|
|
1106
1300
|
};
|
|
1107
1301
|
|
|
1108
|
-
// src/auth/nonce.ts
|
|
1109
|
-
var MemoryNonceStore = class {
|
|
1110
|
-
seen = /* @__PURE__ */ new Map();
|
|
1111
|
-
async check(nonce) {
|
|
1112
|
-
this.evict();
|
|
1113
|
-
if (this.seen.has(nonce)) return false;
|
|
1114
|
-
this.seen.set(nonce, Date.now() + 5 * 60 * 1e3);
|
|
1115
|
-
return true;
|
|
1116
|
-
}
|
|
1117
|
-
evict() {
|
|
1118
|
-
const now = Date.now();
|
|
1119
|
-
for (const [n, exp] of this.seen) {
|
|
1120
|
-
if (exp < now) this.seen.delete(n);
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
};
|
|
1124
|
-
|
|
1125
1302
|
// src/discovery/well-known.ts
|
|
1126
1303
|
import { NextResponse as NextResponse3 } from "next/server";
|
|
1127
1304
|
function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
@@ -1353,6 +1530,9 @@ export {
|
|
|
1353
1530
|
MemoryNonceStore,
|
|
1354
1531
|
RouteBuilder,
|
|
1355
1532
|
RouteRegistry,
|
|
1533
|
+
SIWX_CHALLENGE_EXPIRY_MS,
|
|
1534
|
+
SIWX_ERROR_MESSAGES,
|
|
1356
1535
|
consolePlugin,
|
|
1536
|
+
createRedisNonceStore,
|
|
1357
1537
|
createRouter
|
|
1358
1538
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SIWX verification error codes.
|
|
3
|
+
* Enables clients to auto-retry transient failures (e.g., expired challenge).
|
|
4
|
+
*/
|
|
5
|
+
type SiwxErrorCode = 'siwx_missing_header' | 'siwx_malformed' | 'siwx_expired' | 'siwx_nonce_used' | 'siwx_invalid_signature';
|
|
6
|
+
/** Human-readable error messages for each SIWX error code. */
|
|
7
|
+
declare const SIWX_ERROR_MESSAGES: Record<SiwxErrorCode, string>;
|
|
8
|
+
|
|
9
|
+
export { SIWX_ERROR_MESSAGES as S, type SiwxErrorCode as a };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SIWX verification error codes.
|
|
3
|
+
* Enables clients to auto-retry transient failures (e.g., expired challenge).
|
|
4
|
+
*/
|
|
5
|
+
type SiwxErrorCode = 'siwx_missing_header' | 'siwx_malformed' | 'siwx_expired' | 'siwx_nonce_used' | 'siwx_invalid_signature';
|
|
6
|
+
/** Human-readable error messages for each SIWX error code. */
|
|
7
|
+
declare const SIWX_ERROR_MESSAGES: Record<SiwxErrorCode, string>;
|
|
8
|
+
|
|
9
|
+
export { SIWX_ERROR_MESSAGES as S, type SiwxErrorCode as a };
|