@armory-sh/base 0.2.19 → 0.2.21
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/index.d.ts +3 -0
- package/dist/index.js +166 -0
- package/dist/types/api.d.ts +56 -0
- package/dist/types/hooks.d.ts +35 -0
- package/dist/utils/routes.d.ts +28 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,10 @@ export { ERC20_ABI } from "./abi/erc20";
|
|
|
14
14
|
export type { TypedDataDomain, EIP712Domain, TransferWithAuthorization, TypedDataField, EIP712Types, } from "./eip712";
|
|
15
15
|
export { EIP712_TYPES, USDC_DOMAIN, createEIP712Domain, createTransferWithAuthorization, validateTransferWithAuthorization, } from "./eip712";
|
|
16
16
|
export { resolveNetwork, resolveToken, resolveFacilitator, checkFacilitatorSupport, validatePaymentConfig, validateAcceptConfig, getAvailableNetworks, getAvailableTokens, isValidationError, isResolvedNetwork, isResolvedToken, createError, normalizeNetworkName, } from "./validation";
|
|
17
|
+
export type { RoutePattern, RouteMatcher, RouteConfig, ParsedPattern, RouteInputConfig, RouteValidationError, } from "./utils/routes";
|
|
18
|
+
export { parseRoutePattern, matchRoute, findMatchingRoute, validateRouteConfig, } from "./utils/routes";
|
|
17
19
|
export { encodePaymentV2, decodePaymentV2, encodeSettlementV2, decodeSettlementV2, isPaymentV2, isSettlementV2, } from "./encoding";
|
|
18
20
|
export type { NetworkId, TokenId, FacilitatorConfig, FacilitatorVerifyResult, FacilitatorSettleResult, SettlementMode, PayToAddress, AcceptPaymentOptions, PricingConfig, PaymentResult, PaymentError, PaymentErrorCode, ArmoryPaymentResult, ResolvedNetwork, ResolvedToken, ResolvedFacilitator, ResolvedPaymentConfig, ValidationError, } from "./types/api";
|
|
21
|
+
export type { PaymentRequiredContext, PaymentPayloadContext, HookResult, OnPaymentRequiredHook, BeforePaymentHook, ExtensionHook, HookConfig, HookRegistry, } from "./types/hooks";
|
|
19
22
|
export { createX402V2Payload, createLegacyV2Payload, INVALID_PAYLOADS, TEST_PAYER_ADDRESS, TEST_PAY_TO_ADDRESS, TEST_CONTRACT_ADDRESS, TEST_PRIVATE_KEY, } from "./fixtures/payloads";
|
|
20
23
|
export { DEFAULT_PAYMENT_CONFIG, type TestPaymentConfig } from "./fixtures/config";
|
package/dist/index.js
CHANGED
|
@@ -1109,6 +1109,168 @@ var isResolvedToken = (value) => {
|
|
|
1109
1109
|
return typeof value === "object" && value !== null && "config" in value && "caipAsset" in value;
|
|
1110
1110
|
};
|
|
1111
1111
|
|
|
1112
|
+
// src/utils/routes.ts
|
|
1113
|
+
var PRIORITY_EXACT = 3;
|
|
1114
|
+
var PRIORITY_PARAMETRIZED = 2;
|
|
1115
|
+
var PRIORITY_WILDCARD = 1;
|
|
1116
|
+
function parseRoutePattern(pattern) {
|
|
1117
|
+
const normalizedPattern = pattern.startsWith("/") ? pattern : `/${pattern}`;
|
|
1118
|
+
const segments = normalizedPattern.split("/").filter(Boolean);
|
|
1119
|
+
let isWildcard = false;
|
|
1120
|
+
let isParametrized = false;
|
|
1121
|
+
const paramNames = [];
|
|
1122
|
+
const seenParamNames = /* @__PURE__ */ new Set();
|
|
1123
|
+
const recordParamName = (name) => {
|
|
1124
|
+
if (!name) {
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
if (seenParamNames.has(name)) {
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
seenParamNames.add(name);
|
|
1131
|
+
paramNames.push(name);
|
|
1132
|
+
};
|
|
1133
|
+
for (const segment of segments) {
|
|
1134
|
+
if (segment === "*") {
|
|
1135
|
+
isWildcard = true;
|
|
1136
|
+
continue;
|
|
1137
|
+
}
|
|
1138
|
+
const hasWildcardToken = segment.includes("*");
|
|
1139
|
+
if (segment.startsWith(":")) {
|
|
1140
|
+
isParametrized = true;
|
|
1141
|
+
const paramName = segment.replace(/\*+$/, "").slice(1);
|
|
1142
|
+
recordParamName(paramName);
|
|
1143
|
+
if (hasWildcardToken) {
|
|
1144
|
+
isWildcard = true;
|
|
1145
|
+
}
|
|
1146
|
+
continue;
|
|
1147
|
+
}
|
|
1148
|
+
if (hasWildcardToken) {
|
|
1149
|
+
const parts = segment.split("*");
|
|
1150
|
+
for (const part of parts) {
|
|
1151
|
+
if (part.startsWith(":")) {
|
|
1152
|
+
isParametrized = true;
|
|
1153
|
+
recordParamName(part.slice(1));
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
isWildcard = true;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
let priority = PRIORITY_WILDCARD;
|
|
1160
|
+
if (!isWildcard && !isParametrized) {
|
|
1161
|
+
priority = PRIORITY_EXACT;
|
|
1162
|
+
} else if (isParametrized && !isWildcard) {
|
|
1163
|
+
priority = PRIORITY_PARAMETRIZED;
|
|
1164
|
+
} else if (isParametrized && isWildcard) {
|
|
1165
|
+
priority = PRIORITY_PARAMETRIZED;
|
|
1166
|
+
}
|
|
1167
|
+
return { segments, isWildcard, isParametrized, paramNames, priority };
|
|
1168
|
+
}
|
|
1169
|
+
function matchSegment(patternSegment, pathSegment) {
|
|
1170
|
+
if (patternSegment === "*") {
|
|
1171
|
+
return true;
|
|
1172
|
+
}
|
|
1173
|
+
if (patternSegment.startsWith(":")) {
|
|
1174
|
+
return true;
|
|
1175
|
+
}
|
|
1176
|
+
if (patternSegment.includes("*")) {
|
|
1177
|
+
const regex = new RegExp(
|
|
1178
|
+
"^" + patternSegment.replace(/\*/g, ".*").replace(/:/g, "") + "$"
|
|
1179
|
+
);
|
|
1180
|
+
return regex.test(pathSegment);
|
|
1181
|
+
}
|
|
1182
|
+
return patternSegment === pathSegment;
|
|
1183
|
+
}
|
|
1184
|
+
function matchWildcardPattern(patternSegments, pathSegments) {
|
|
1185
|
+
const requiredSegments = patternSegments.filter((s) => s !== "*");
|
|
1186
|
+
if (requiredSegments.length > pathSegments.length) {
|
|
1187
|
+
return false;
|
|
1188
|
+
}
|
|
1189
|
+
for (let i = 0; i < requiredSegments.length; i++) {
|
|
1190
|
+
const patternIndex = patternSegments.indexOf(requiredSegments[i]);
|
|
1191
|
+
if (pathSegments[patternIndex] !== requiredSegments[i].replace(/^\:/, "")) {
|
|
1192
|
+
if (!requiredSegments[i].startsWith(":") && requiredSegments[i] !== "*") {
|
|
1193
|
+
return false;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
return true;
|
|
1198
|
+
}
|
|
1199
|
+
function matchRoute(pattern, path) {
|
|
1200
|
+
const normalizedPattern = pattern.startsWith("/") ? pattern : `/${pattern}`;
|
|
1201
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1202
|
+
if (normalizedPattern === normalizedPath) {
|
|
1203
|
+
return true;
|
|
1204
|
+
}
|
|
1205
|
+
const parsed = parseRoutePattern(normalizedPattern);
|
|
1206
|
+
const patternSegments = parsed.segments;
|
|
1207
|
+
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
1208
|
+
if (!parsed.isWildcard && patternSegments.length !== pathSegments.length) {
|
|
1209
|
+
return false;
|
|
1210
|
+
}
|
|
1211
|
+
if (parsed.isWildcard && patternSegments.length > pathSegments.length + 1) {
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
if (parsed.isWildcard) {
|
|
1215
|
+
return matchWildcardPattern(patternSegments, pathSegments);
|
|
1216
|
+
}
|
|
1217
|
+
for (let i = 0; i < patternSegments.length; i++) {
|
|
1218
|
+
if (!matchSegment(patternSegments[i], pathSegments[i])) {
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
return true;
|
|
1223
|
+
}
|
|
1224
|
+
function findMatchingRoute(routes, path) {
|
|
1225
|
+
const matchingRoutes = [];
|
|
1226
|
+
for (const route of routes) {
|
|
1227
|
+
if (matchRoute(route.pattern, path)) {
|
|
1228
|
+
const parsed = parseRoutePattern(route.pattern);
|
|
1229
|
+
matchingRoutes.push({ route, parsed });
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
if (matchingRoutes.length === 0) {
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
matchingRoutes.sort((a, b) => {
|
|
1236
|
+
if (b.parsed.priority !== a.parsed.priority) {
|
|
1237
|
+
return b.parsed.priority - a.parsed.priority;
|
|
1238
|
+
}
|
|
1239
|
+
if (b.parsed.segments.length !== a.parsed.segments.length) {
|
|
1240
|
+
return b.parsed.segments.length - a.parsed.segments.length;
|
|
1241
|
+
}
|
|
1242
|
+
return b.route.pattern.length - a.route.pattern.length;
|
|
1243
|
+
});
|
|
1244
|
+
return matchingRoutes[0].route;
|
|
1245
|
+
}
|
|
1246
|
+
function containsWildcard(pattern) {
|
|
1247
|
+
return pattern.includes("*");
|
|
1248
|
+
}
|
|
1249
|
+
function validateRouteConfig(config) {
|
|
1250
|
+
const { route, routes } = config;
|
|
1251
|
+
if (!route && !routes) {
|
|
1252
|
+
return null;
|
|
1253
|
+
}
|
|
1254
|
+
if (route && routes) {
|
|
1255
|
+
return {
|
|
1256
|
+
code: "INVALID_ROUTE_CONFIG",
|
|
1257
|
+
message: "Cannot specify both 'route' and 'routes'. Use 'route' for a single exact path or 'routes' for multiple paths.",
|
|
1258
|
+
path: "route",
|
|
1259
|
+
value: { route, routes }
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
if (route && containsWildcard(route)) {
|
|
1263
|
+
return {
|
|
1264
|
+
code: "INVALID_ROUTE_PATTERN",
|
|
1265
|
+
message: `Wildcard routes must use the routes array, not 'route'. Use 'routes: ["/api/*"]' instead of 'route: "/api/*"'.`,
|
|
1266
|
+
path: "route",
|
|
1267
|
+
value: route,
|
|
1268
|
+
validOptions: ['routes: ["/api/*"]', 'routes: ["/api/users", "/api/posts"]']
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1112
1274
|
// src/encoding.ts
|
|
1113
1275
|
function safeBase64Decode2(str) {
|
|
1114
1276
|
const padding = 4 - str.length % 4;
|
|
@@ -1275,6 +1437,7 @@ export {
|
|
|
1275
1437
|
encodeSettlementV2,
|
|
1276
1438
|
encodeX402Response,
|
|
1277
1439
|
extractPaymentFromHeaders,
|
|
1440
|
+
findMatchingRoute,
|
|
1278
1441
|
fromAtomicUnits,
|
|
1279
1442
|
getAllCustomTokens,
|
|
1280
1443
|
getAllTokens,
|
|
@@ -1318,9 +1481,11 @@ export {
|
|
|
1318
1481
|
isX402V2Requirements,
|
|
1319
1482
|
isX402V2Settlement,
|
|
1320
1483
|
legacyToPaymentPayload,
|
|
1484
|
+
matchRoute,
|
|
1321
1485
|
networkToCaip2,
|
|
1322
1486
|
normalizeAddress,
|
|
1323
1487
|
normalizeNetworkName,
|
|
1488
|
+
parseRoutePattern,
|
|
1324
1489
|
parseSignature as parseSignatureV2,
|
|
1325
1490
|
registerToken,
|
|
1326
1491
|
resolveFacilitator,
|
|
@@ -1332,5 +1497,6 @@ export {
|
|
|
1332
1497
|
unregisterToken,
|
|
1333
1498
|
validateAcceptConfig,
|
|
1334
1499
|
validatePaymentConfig,
|
|
1500
|
+
validateRouteConfig,
|
|
1335
1501
|
validateTransferWithAuthorization
|
|
1336
1502
|
};
|
package/dist/types/api.d.ts
CHANGED
|
@@ -194,3 +194,59 @@ export interface ValidationError {
|
|
|
194
194
|
/** Valid options */
|
|
195
195
|
validOptions?: string[];
|
|
196
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Route pattern type for matching paths
|
|
199
|
+
*/
|
|
200
|
+
export type RoutePattern = string;
|
|
201
|
+
/**
|
|
202
|
+
* Route matcher function type
|
|
203
|
+
*/
|
|
204
|
+
export type RouteMatcher = (path: string) => boolean;
|
|
205
|
+
/**
|
|
206
|
+
* Route configuration with associated config data
|
|
207
|
+
*/
|
|
208
|
+
export interface RouteConfig<T = unknown> {
|
|
209
|
+
/** Route pattern (e.g., "/api/users", "/api/*", "/api/users/:id") */
|
|
210
|
+
pattern: RoutePattern;
|
|
211
|
+
/** Configuration associated with this route */
|
|
212
|
+
config: T;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Parsed route pattern information
|
|
216
|
+
*/
|
|
217
|
+
export interface ParsedPattern {
|
|
218
|
+
/** Route segments split by "/" */
|
|
219
|
+
segments: string[];
|
|
220
|
+
/** Whether this pattern contains a wildcard */
|
|
221
|
+
isWildcard: boolean;
|
|
222
|
+
/** Whether this pattern contains parameters (e.g., :id) */
|
|
223
|
+
isParametrized: boolean;
|
|
224
|
+
/** Parameter names extracted from the pattern */
|
|
225
|
+
paramNames: string[];
|
|
226
|
+
/** Match priority (higher = more specific) */
|
|
227
|
+
priority: number;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Route input configuration for middleware
|
|
231
|
+
*/
|
|
232
|
+
export interface RouteInputConfig {
|
|
233
|
+
/** Single exact route (no wildcards allowed) */
|
|
234
|
+
route?: string;
|
|
235
|
+
/** Multiple routes (allows wildcards) */
|
|
236
|
+
routes?: string[];
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Route-specific validation error details
|
|
240
|
+
*/
|
|
241
|
+
export interface RouteValidationError {
|
|
242
|
+
/** Error code (custom string, not PaymentErrorCode) */
|
|
243
|
+
code: string;
|
|
244
|
+
/** Error message */
|
|
245
|
+
message: string;
|
|
246
|
+
/** Path to the invalid value */
|
|
247
|
+
path?: string;
|
|
248
|
+
/** Invalid value */
|
|
249
|
+
value?: unknown;
|
|
250
|
+
/** Valid options */
|
|
251
|
+
validOptions?: string[];
|
|
252
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension Hook System Types
|
|
3
|
+
*
|
|
4
|
+
* Provides a generic hook system for x402 clients to register
|
|
5
|
+
* extension handlers that can modify payment payloads or respond
|
|
6
|
+
* to payment requirements.
|
|
7
|
+
*
|
|
8
|
+
* Hooks allow extensibility without custom code in each client package.
|
|
9
|
+
*/
|
|
10
|
+
import type { PaymentPayloadV2, PaymentRequirementsV2, Extensions, Address } from "./v2";
|
|
11
|
+
export interface PaymentRequiredContext {
|
|
12
|
+
url: RequestInfo | URL;
|
|
13
|
+
requestInit: RequestInit | undefined;
|
|
14
|
+
requirements: PaymentRequirementsV2;
|
|
15
|
+
serverExtensions: Extensions | undefined;
|
|
16
|
+
fromAddress: Address;
|
|
17
|
+
nonce: `0x${string}`;
|
|
18
|
+
validBefore: number;
|
|
19
|
+
}
|
|
20
|
+
export interface PaymentPayloadContext<TWallet = unknown> {
|
|
21
|
+
payload: PaymentPayloadV2;
|
|
22
|
+
requirements: PaymentRequirementsV2;
|
|
23
|
+
wallet: TWallet;
|
|
24
|
+
paymentContext: PaymentRequiredContext;
|
|
25
|
+
}
|
|
26
|
+
export type HookResult = void | Promise<void>;
|
|
27
|
+
export type OnPaymentRequiredHook<TWallet = unknown> = (context: PaymentRequiredContext) => HookResult;
|
|
28
|
+
export type BeforePaymentHook<TWallet = unknown> = (context: PaymentPayloadContext<TWallet>) => HookResult;
|
|
29
|
+
export type ExtensionHook<TWallet = unknown> = OnPaymentRequiredHook<TWallet> | BeforePaymentHook<TWallet>;
|
|
30
|
+
export interface HookConfig<TWallet = unknown> {
|
|
31
|
+
hook: ExtensionHook<TWallet>;
|
|
32
|
+
priority?: number;
|
|
33
|
+
name?: string;
|
|
34
|
+
}
|
|
35
|
+
export type HookRegistry<TWallet = unknown> = Record<string, HookConfig<TWallet>>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type RoutePattern = string;
|
|
2
|
+
export type RouteMatcher = (path: string) => boolean;
|
|
3
|
+
export interface RouteConfig<T = unknown> {
|
|
4
|
+
pattern: RoutePattern;
|
|
5
|
+
config: T;
|
|
6
|
+
}
|
|
7
|
+
export interface ParsedPattern {
|
|
8
|
+
segments: string[];
|
|
9
|
+
isWildcard: boolean;
|
|
10
|
+
isParametrized: boolean;
|
|
11
|
+
paramNames: string[];
|
|
12
|
+
priority: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function parseRoutePattern(pattern: string): ParsedPattern;
|
|
15
|
+
export declare function matchRoute(pattern: string, path: string): boolean;
|
|
16
|
+
export declare function findMatchingRoute<T>(routes: RouteConfig<T>[], path: string): RouteConfig<T> | null;
|
|
17
|
+
export interface RouteInputConfig {
|
|
18
|
+
route?: string;
|
|
19
|
+
routes?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface RouteValidationError {
|
|
22
|
+
code: string;
|
|
23
|
+
message: string;
|
|
24
|
+
path?: string;
|
|
25
|
+
value?: unknown;
|
|
26
|
+
validOptions?: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function validateRouteConfig(config: RouteInputConfig): RouteValidationError | null;
|