@agentcash/router 1.13.0 → 1.14.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/index.cjs CHANGED
@@ -42,7 +42,7 @@ var init_constants = __esm({
42
42
  BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
43
43
  BASE_USDC_DECIMALS = 6;
44
44
  ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
45
- DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
45
+ DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.payai.network";
46
46
  DEFAULT_TEMPO_RPC_URL = "https://rpc.tempo.xyz";
47
47
  }
48
48
  });
@@ -151,31 +151,64 @@ function buildSolanaExactOptions(accepts, price) {
151
151
  function hasSolanaAccepts(accepts) {
152
152
  return accepts.some((accept) => isSolanaNetwork(accept.network));
153
153
  }
154
- async function enrichRequirementsWithFacilitatorAccepts(facilitator, resource, requirements) {
154
+ function facilitatorBaseUrl(facilitator) {
155
155
  if (!facilitator.url) {
156
- throw new Error(`Facilitator for ${facilitator.network} is missing a URL for /accepts`);
156
+ throw new Error(`Facilitator for ${facilitator.network} is missing a URL`);
157
157
  }
158
- const authHeaders = await getAcceptsHeadersForFacilitator(facilitator);
159
- const response = await fetch(`${facilitator.url.replace(/\/+$/, "")}/accepts`, {
160
- method: "POST",
161
- headers: {
162
- ...authHeaders,
163
- "content-type": "application/json"
164
- },
165
- body: JSON.stringify({
166
- x402Version: 2,
167
- resource,
168
- accepts: requirements
169
- })
158
+ return facilitator.url.replace(/\/+$/, "");
159
+ }
160
+ function matchesSupportedKind(requirement, kind) {
161
+ const scheme = requirement.scheme ?? "exact";
162
+ return kind.network === requirement.network && (kind.scheme ?? "exact") === scheme;
163
+ }
164
+ async function fetchFacilitatorSupported(facilitator) {
165
+ const authHeaders = await getSupportedHeadersForFacilitator(facilitator);
166
+ const response = await fetch(`${facilitatorBaseUrl(facilitator)}/supported`, {
167
+ headers: authHeaders
170
168
  });
171
169
  if (!response.ok) {
172
- throw new Error(`Facilitator /accepts failed with status ${response.status}`);
170
+ throw new Error(`Facilitator /supported failed with status ${response.status}`);
173
171
  }
174
172
  const body = await response.json();
175
- if (!Array.isArray(body.accepts)) {
176
- throw new Error("Facilitator /accepts response did not include accepts");
173
+ if (!Array.isArray(body.kinds)) {
174
+ throw new Error("Facilitator /supported response did not include kinds");
177
175
  }
178
- return body.accepts;
176
+ return body.kinds;
177
+ }
178
+ function enrichRequirementFromKind(requirement, kinds) {
179
+ const kind = kinds.find((candidate) => matchesSupportedKind(requirement, candidate));
180
+ if (!kind) {
181
+ throw new Error(
182
+ `Facilitator /supported has no kind for ${requirement.scheme} on ${requirement.network}`
183
+ );
184
+ }
185
+ const feePayer = kind.extra?.feePayer;
186
+ if (!feePayer) {
187
+ throw new Error(
188
+ `Facilitator /supported kind for ${requirement.network} is missing extra.feePayer`
189
+ );
190
+ }
191
+ const requirementExtra = requirement.extra ?? {};
192
+ const kindExtra = kind.extra ?? {};
193
+ const requirementFeatures = requirementExtra.features ?? {};
194
+ const kindFeatures = kindExtra.features ?? {};
195
+ return {
196
+ ...requirement,
197
+ ...kind.asset && !requirement.asset ? { asset: kind.asset } : {},
198
+ extra: {
199
+ ...requirementExtra,
200
+ ...kindExtra,
201
+ features: {
202
+ ...requirementFeatures,
203
+ ...kindFeatures,
204
+ xSettlementAccountSupported: true
205
+ }
206
+ }
207
+ };
208
+ }
209
+ async function enrichRequirementsFromFacilitatorSupported(facilitator, requirements) {
210
+ const kinds = await fetchFacilitatorSupported(facilitator);
211
+ return requirements.map((requirement) => enrichRequirementFromKind(requirement, kinds));
179
212
  }
180
213
  function isSolanaRequirement(requirement) {
181
214
  return isSolanaNetwork(requirement.network);
@@ -232,10 +265,7 @@ function getFacilitatorForRequirement(facilitatorsByNetwork, requirement) {
232
265
  function sameResolvedX402Facilitator(a, b) {
233
266
  return sameFacilitatorConfig(a.config, b.config);
234
267
  }
235
- async function getAcceptsHeadersForFacilitator(facilitator) {
236
- if (facilitator.config.createAcceptsHeaders) {
237
- return facilitator.config.createAcceptsHeaders();
238
- }
268
+ async function getSupportedHeadersForFacilitator(facilitator) {
239
269
  if (facilitator.config.createAuthHeaders) {
240
270
  const headers = await facilitator.config.createAuthHeaders();
241
271
  return headers.supported;
@@ -257,7 +287,7 @@ function getNetworkFamily(network) {
257
287
  return null;
258
288
  }
259
289
  function sameFacilitatorConfig(a, b) {
260
- return a.url === b.url && a.createAuthHeaders === b.createAuthHeaders && a.createAcceptsHeaders === b.createAcceptsHeaders;
290
+ return a.url === b.url && a.createAuthHeaders === b.createAuthHeaders;
261
291
  }
262
292
  var init_facilitators = __esm({
263
293
  "src/protocols/x402/facilitators.ts"() {
@@ -1996,15 +2026,14 @@ async function buildChallengeRequirements(server, request, price, accepts, resou
1996
2026
  function needsFacilitatorEnrichment(accepts) {
1997
2027
  return hasSolanaAccepts(accepts);
1998
2028
  }
1999
- async function enrichGroup(group, resource) {
2000
- const accepted = await enrichRequirementsWithFacilitatorAccepts(
2029
+ async function enrichGroup(group) {
2030
+ const accepted = await enrichRequirementsFromFacilitatorSupported(
2001
2031
  group.facilitator,
2002
- resource,
2003
2032
  group.items.map(({ requirement }) => requirement)
2004
2033
  );
2005
2034
  if (accepted.length !== group.items.length) {
2006
2035
  throw new Error(
2007
- `Facilitator /accepts returned ${accepted.length} requirements for ${group.items.length} inputs on ${group.facilitator.url ?? group.facilitator.network}`
2036
+ `Facilitator /supported enrichment returned ${accepted.length} requirements for ${group.items.length} inputs on ${group.facilitator.url ?? group.facilitator.network}`
2008
2037
  );
2009
2038
  }
2010
2039
  return accepted;
@@ -2015,13 +2044,13 @@ async function enrichChallengeRequirements(requirements, resource, facilitatorsB
2015
2044
  const results = await Promise.all(
2016
2045
  groups.map(async (group) => {
2017
2046
  try {
2018
- return { success: true, group, accepted: await enrichGroup(group, resource) };
2047
+ return { success: true, group, accepted: await enrichGroup(group) };
2019
2048
  } catch (err) {
2020
2049
  const label = group.facilitator.url ?? group.facilitator.network;
2021
2050
  const reason = err instanceof Error ? err.message : String(err);
2022
2051
  report?.(
2023
2052
  "warn",
2024
- `${label} /accepts failed, dropping ${group.items.length} requirement(s): ${reason}`
2053
+ `${label} /supported enrichment failed, dropping ${group.items.length} requirement(s): ${reason}`
2025
2054
  );
2026
2055
  return { success: false, group };
2027
2056
  }
package/dist/index.d.cts CHANGED
@@ -222,8 +222,6 @@ interface X402AcceptConfig extends X402AcceptBase {
222
222
  payTo?: PayToConfig;
223
223
  }
224
224
  interface X402RouterFacilitatorConfig extends FacilitatorConfig {
225
- /** Async header builder invoked per facilitator call. Use for short-lived auth tokens (e.g. CDP signed headers). */
226
- createAcceptsHeaders?: () => Promise<Record<string, string>>;
227
225
  }
228
226
  /** A facilitator URL or a full `FacilitatorConfig` (URL + auth header builders). */
229
227
  type X402FacilitatorTarget = string | X402RouterFacilitatorConfig;
@@ -972,7 +970,7 @@ declare const BASE_USDC_DECIMALS = 6;
972
970
  /** All-zeros EVM address. Used as a placeholder/sentinel; not a valid payee. */
973
971
  declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
974
972
  /** Public Solana x402 facilitator. Override per-deployment via `SOLANA_FACILITATOR_URL`. */
975
- declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
973
+ declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.payai.network";
976
974
  /** Public Tempo JSON-RPC endpoint used for MPP on-chain verification. Override per-deployment via `TEMPO_RPC_URL`. */
977
975
  declare const DEFAULT_TEMPO_RPC_URL = "https://rpc.tempo.xyz";
978
976
 
@@ -1002,9 +1000,10 @@ interface ServiceRouter<TPriceKeys extends string = never> {
1002
1000
  monitors(): MonitorEntry[];
1003
1001
  registry: RouteRegistry;
1004
1002
  }
1005
- declare function createRouter<const P extends Record<string, string> = Record<never, string>>(config: RouterConfig & {
1006
- prices?: P;
1007
- }): ServiceRouter<Extract<keyof P, string>>;
1003
+ type ExtractPriceKeys<C> = [C] extends [{
1004
+ prices: infer P extends Record<string, string>;
1005
+ }] ? Extract<keyof P, string> : never;
1006
+ declare function createRouter<const C extends RouterConfig>(config: C): ServiceRouter<ExtractPriceKeys<C>>;
1008
1007
  /**
1009
1008
  * Build a {@link ServiceRouter} from environment variables.
1010
1009
  *
@@ -1025,6 +1024,9 @@ declare function createRouter<const P extends Record<string, string> = Record<ne
1025
1024
  * });
1026
1025
  * ```
1027
1026
  */
1028
- declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
1027
+ type ExtractEnvPriceKeys<O> = [O] extends [{
1028
+ prices: infer P extends Record<string, string>;
1029
+ }] ? Extract<keyof P, string> : never;
1030
+ declare function createRouterFromEnv<const O extends CreateRouterFromEnvOptions>(options: O): ServiceRouter<ExtractEnvPriceKeys<O>>;
1029
1031
 
1030
1032
  export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CheckoutSessionContext, type CheckoutSessionFn, type CheckoutSessionResponse, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type MppProtocolInfo, type PaidOptions, type ProtocolType, RouteDefinitionError, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };
package/dist/index.d.ts CHANGED
@@ -222,8 +222,6 @@ interface X402AcceptConfig extends X402AcceptBase {
222
222
  payTo?: PayToConfig;
223
223
  }
224
224
  interface X402RouterFacilitatorConfig extends FacilitatorConfig {
225
- /** Async header builder invoked per facilitator call. Use for short-lived auth tokens (e.g. CDP signed headers). */
226
- createAcceptsHeaders?: () => Promise<Record<string, string>>;
227
225
  }
228
226
  /** A facilitator URL or a full `FacilitatorConfig` (URL + auth header builders). */
229
227
  type X402FacilitatorTarget = string | X402RouterFacilitatorConfig;
@@ -972,7 +970,7 @@ declare const BASE_USDC_DECIMALS = 6;
972
970
  /** All-zeros EVM address. Used as a placeholder/sentinel; not a valid payee. */
973
971
  declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
974
972
  /** Public Solana x402 facilitator. Override per-deployment via `SOLANA_FACILITATOR_URL`. */
975
- declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
973
+ declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.payai.network";
976
974
  /** Public Tempo JSON-RPC endpoint used for MPP on-chain verification. Override per-deployment via `TEMPO_RPC_URL`. */
977
975
  declare const DEFAULT_TEMPO_RPC_URL = "https://rpc.tempo.xyz";
978
976
 
@@ -1002,9 +1000,10 @@ interface ServiceRouter<TPriceKeys extends string = never> {
1002
1000
  monitors(): MonitorEntry[];
1003
1001
  registry: RouteRegistry;
1004
1002
  }
1005
- declare function createRouter<const P extends Record<string, string> = Record<never, string>>(config: RouterConfig & {
1006
- prices?: P;
1007
- }): ServiceRouter<Extract<keyof P, string>>;
1003
+ type ExtractPriceKeys<C> = [C] extends [{
1004
+ prices: infer P extends Record<string, string>;
1005
+ }] ? Extract<keyof P, string> : never;
1006
+ declare function createRouter<const C extends RouterConfig>(config: C): ServiceRouter<ExtractPriceKeys<C>>;
1008
1007
  /**
1009
1008
  * Build a {@link ServiceRouter} from environment variables.
1010
1009
  *
@@ -1025,6 +1024,9 @@ declare function createRouter<const P extends Record<string, string> = Record<ne
1025
1024
  * });
1026
1025
  * ```
1027
1026
  */
1028
- declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
1027
+ type ExtractEnvPriceKeys<O> = [O] extends [{
1028
+ prices: infer P extends Record<string, string>;
1029
+ }] ? Extract<keyof P, string> : never;
1030
+ declare function createRouterFromEnv<const O extends CreateRouterFromEnvOptions>(options: O): ServiceRouter<ExtractEnvPriceKeys<O>>;
1029
1031
 
1030
1032
  export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CheckoutSessionContext, type CheckoutSessionFn, type CheckoutSessionResponse, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type MppProtocolInfo, type PaidOptions, type ProtocolType, RouteDefinitionError, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ var init_constants = __esm({
20
20
  BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
21
21
  BASE_USDC_DECIMALS = 6;
22
22
  ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
23
- DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
23
+ DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.payai.network";
24
24
  DEFAULT_TEMPO_RPC_URL = "https://rpc.tempo.xyz";
25
25
  }
26
26
  });
@@ -129,31 +129,64 @@ function buildSolanaExactOptions(accepts, price) {
129
129
  function hasSolanaAccepts(accepts) {
130
130
  return accepts.some((accept) => isSolanaNetwork(accept.network));
131
131
  }
132
- async function enrichRequirementsWithFacilitatorAccepts(facilitator, resource, requirements) {
132
+ function facilitatorBaseUrl(facilitator) {
133
133
  if (!facilitator.url) {
134
- throw new Error(`Facilitator for ${facilitator.network} is missing a URL for /accepts`);
134
+ throw new Error(`Facilitator for ${facilitator.network} is missing a URL`);
135
135
  }
136
- const authHeaders = await getAcceptsHeadersForFacilitator(facilitator);
137
- const response = await fetch(`${facilitator.url.replace(/\/+$/, "")}/accepts`, {
138
- method: "POST",
139
- headers: {
140
- ...authHeaders,
141
- "content-type": "application/json"
142
- },
143
- body: JSON.stringify({
144
- x402Version: 2,
145
- resource,
146
- accepts: requirements
147
- })
136
+ return facilitator.url.replace(/\/+$/, "");
137
+ }
138
+ function matchesSupportedKind(requirement, kind) {
139
+ const scheme = requirement.scheme ?? "exact";
140
+ return kind.network === requirement.network && (kind.scheme ?? "exact") === scheme;
141
+ }
142
+ async function fetchFacilitatorSupported(facilitator) {
143
+ const authHeaders = await getSupportedHeadersForFacilitator(facilitator);
144
+ const response = await fetch(`${facilitatorBaseUrl(facilitator)}/supported`, {
145
+ headers: authHeaders
148
146
  });
149
147
  if (!response.ok) {
150
- throw new Error(`Facilitator /accepts failed with status ${response.status}`);
148
+ throw new Error(`Facilitator /supported failed with status ${response.status}`);
151
149
  }
152
150
  const body = await response.json();
153
- if (!Array.isArray(body.accepts)) {
154
- throw new Error("Facilitator /accepts response did not include accepts");
151
+ if (!Array.isArray(body.kinds)) {
152
+ throw new Error("Facilitator /supported response did not include kinds");
155
153
  }
156
- return body.accepts;
154
+ return body.kinds;
155
+ }
156
+ function enrichRequirementFromKind(requirement, kinds) {
157
+ const kind = kinds.find((candidate) => matchesSupportedKind(requirement, candidate));
158
+ if (!kind) {
159
+ throw new Error(
160
+ `Facilitator /supported has no kind for ${requirement.scheme} on ${requirement.network}`
161
+ );
162
+ }
163
+ const feePayer = kind.extra?.feePayer;
164
+ if (!feePayer) {
165
+ throw new Error(
166
+ `Facilitator /supported kind for ${requirement.network} is missing extra.feePayer`
167
+ );
168
+ }
169
+ const requirementExtra = requirement.extra ?? {};
170
+ const kindExtra = kind.extra ?? {};
171
+ const requirementFeatures = requirementExtra.features ?? {};
172
+ const kindFeatures = kindExtra.features ?? {};
173
+ return {
174
+ ...requirement,
175
+ ...kind.asset && !requirement.asset ? { asset: kind.asset } : {},
176
+ extra: {
177
+ ...requirementExtra,
178
+ ...kindExtra,
179
+ features: {
180
+ ...requirementFeatures,
181
+ ...kindFeatures,
182
+ xSettlementAccountSupported: true
183
+ }
184
+ }
185
+ };
186
+ }
187
+ async function enrichRequirementsFromFacilitatorSupported(facilitator, requirements) {
188
+ const kinds = await fetchFacilitatorSupported(facilitator);
189
+ return requirements.map((requirement) => enrichRequirementFromKind(requirement, kinds));
157
190
  }
158
191
  function isSolanaRequirement(requirement) {
159
192
  return isSolanaNetwork(requirement.network);
@@ -210,10 +243,7 @@ function getFacilitatorForRequirement(facilitatorsByNetwork, requirement) {
210
243
  function sameResolvedX402Facilitator(a, b) {
211
244
  return sameFacilitatorConfig(a.config, b.config);
212
245
  }
213
- async function getAcceptsHeadersForFacilitator(facilitator) {
214
- if (facilitator.config.createAcceptsHeaders) {
215
- return facilitator.config.createAcceptsHeaders();
216
- }
246
+ async function getSupportedHeadersForFacilitator(facilitator) {
217
247
  if (facilitator.config.createAuthHeaders) {
218
248
  const headers = await facilitator.config.createAuthHeaders();
219
249
  return headers.supported;
@@ -235,7 +265,7 @@ function getNetworkFamily(network) {
235
265
  return null;
236
266
  }
237
267
  function sameFacilitatorConfig(a, b) {
238
- return a.url === b.url && a.createAuthHeaders === b.createAuthHeaders && a.createAcceptsHeaders === b.createAcceptsHeaders;
268
+ return a.url === b.url && a.createAuthHeaders === b.createAuthHeaders;
239
269
  }
240
270
  var init_facilitators = __esm({
241
271
  "src/protocols/x402/facilitators.ts"() {
@@ -1957,15 +1987,14 @@ async function buildChallengeRequirements(server, request, price, accepts, resou
1957
1987
  function needsFacilitatorEnrichment(accepts) {
1958
1988
  return hasSolanaAccepts(accepts);
1959
1989
  }
1960
- async function enrichGroup(group, resource) {
1961
- const accepted = await enrichRequirementsWithFacilitatorAccepts(
1990
+ async function enrichGroup(group) {
1991
+ const accepted = await enrichRequirementsFromFacilitatorSupported(
1962
1992
  group.facilitator,
1963
- resource,
1964
1993
  group.items.map(({ requirement }) => requirement)
1965
1994
  );
1966
1995
  if (accepted.length !== group.items.length) {
1967
1996
  throw new Error(
1968
- `Facilitator /accepts returned ${accepted.length} requirements for ${group.items.length} inputs on ${group.facilitator.url ?? group.facilitator.network}`
1997
+ `Facilitator /supported enrichment returned ${accepted.length} requirements for ${group.items.length} inputs on ${group.facilitator.url ?? group.facilitator.network}`
1969
1998
  );
1970
1999
  }
1971
2000
  return accepted;
@@ -1976,13 +2005,13 @@ async function enrichChallengeRequirements(requirements, resource, facilitatorsB
1976
2005
  const results = await Promise.all(
1977
2006
  groups.map(async (group) => {
1978
2007
  try {
1979
- return { success: true, group, accepted: await enrichGroup(group, resource) };
2008
+ return { success: true, group, accepted: await enrichGroup(group) };
1980
2009
  } catch (err) {
1981
2010
  const label = group.facilitator.url ?? group.facilitator.network;
1982
2011
  const reason = err instanceof Error ? err.message : String(err);
1983
2012
  report?.(
1984
2013
  "warn",
1985
- `${label} /accepts failed, dropping ${group.items.length} requirement(s): ${reason}`
2014
+ `${label} /supported enrichment failed, dropping ${group.items.length} requirement(s): ${reason}`
1986
2015
  );
1987
2016
  return { success: false, group };
1988
2017
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcash/router",
3
- "version": "1.13.0",
3
+ "version": "1.14.1",
4
4
  "description": "Unified route builder for Next.js App Router APIs with x402, MPP, SIWX, and API key auth",
5
5
  "type": "module",
6
6
  "exports": {
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "scripts": {
67
67
  "build": "tsup",
68
- "typecheck": "tsc --noEmit",
68
+ "typecheck": "tsc --noEmit && tsc -p tests/tsconfig.json --noEmit",
69
69
  "lint": "eslint src/ tests/ --max-warnings 0",
70
70
  "lint:fix": "eslint src/ tests/ --fix",
71
71
  "format": "prettier --write 'src/**/*.ts' 'tests/**/*.ts' 'examples/fortune/**/*.ts' 'examples/fortune/**/*.md' '*.json' '*.mjs'",