From b7211961ba92cc5cd68ad633592b5428060e8478 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 2 Mar 2026 19:14:53 +0000
Subject: [PATCH 1/8] feat(api): add action_counts to rule performance reports
and code to authorization actions
---
.stats.yml | 6 +-
api.md | 3 +-
src/resources/auth-rules/auth-rules.ts | 6 +-
src/resources/auth-rules/index.ts | 3 +-
src/resources/auth-rules/v2/backtests.ts | 4 +-
src/resources/auth-rules/v2/index.ts | 3 +-
src/resources/auth-rules/v2/v2.ts | 444 +++++++++++++++++--
tests/api-resources/auth-rules/v2/v2.test.ts | 2 +
8 files changed, 426 insertions(+), 45 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index c89f8408..17f87283 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 185
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-a45946df228eec554b3cd2491f658bd5a45cb91509da0a9f92d50468ea88072f.yml
-openapi_spec_hash: 24c7c13e1e7385cab5442ca66091ffc6
-config_hash: 50031f78031362c2e4900222b9ce7ada
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-b29a4bd5ca21348ef426162cbd1fa21070f695572626e4e6faabfa14af38f0b0.yml
+openapi_spec_hash: e7c285d6b7006d040ecb50a9d0d2fc17
+config_hash: fb5070d41fcabdedbc084b83964b592a
diff --git a/api.md b/api.md
index a417649d..405a5437 100644
--- a/api.md
+++ b/api.md
@@ -84,6 +84,7 @@ Types:
- AuthRule
- AuthRuleCondition
+- BacktestStats
- Conditional3DSActionParameters
- ConditionalACHActionParameters
- ConditionalAttribute
@@ -94,7 +95,7 @@ Types:
- ConditionalValue
- EventStream
- MerchantLockParameters
-- RuleStats
+- ReportStats
- VelocityLimitParams
- VelocityLimitPeriod
- V2ListResultsResponse
diff --git a/src/resources/auth-rules/auth-rules.ts b/src/resources/auth-rules/auth-rules.ts
index 11dcf45a..4d3b2a36 100644
--- a/src/resources/auth-rules/auth-rules.ts
+++ b/src/resources/auth-rules/auth-rules.ts
@@ -6,6 +6,7 @@ import {
AuthRule,
AuthRuleCondition,
AuthRulesCursorPage,
+ BacktestStats,
Conditional3DSActionParameters,
ConditionalACHActionParameters,
ConditionalAttribute,
@@ -16,7 +17,7 @@ import {
ConditionalValue,
EventStream,
MerchantLockParameters,
- RuleStats,
+ ReportStats,
V2,
V2CreateParams,
V2DraftParams,
@@ -44,6 +45,7 @@ export declare namespace AuthRules {
V2 as V2,
type AuthRule as AuthRule,
type AuthRuleCondition as AuthRuleCondition,
+ type BacktestStats as BacktestStats,
type Conditional3DSActionParameters as Conditional3DSActionParameters,
type ConditionalACHActionParameters as ConditionalACHActionParameters,
type ConditionalAttribute as ConditionalAttribute,
@@ -54,7 +56,7 @@ export declare namespace AuthRules {
type ConditionalValue as ConditionalValue,
type EventStream as EventStream,
type MerchantLockParameters as MerchantLockParameters,
- type RuleStats as RuleStats,
+ type ReportStats as ReportStats,
type VelocityLimitParams as VelocityLimitParams,
type VelocityLimitPeriod as VelocityLimitPeriod,
type V2ListResultsResponse as V2ListResultsResponse,
diff --git a/src/resources/auth-rules/index.ts b/src/resources/auth-rules/index.ts
index dcb1e7f9..2e33e3c2 100644
--- a/src/resources/auth-rules/index.ts
+++ b/src/resources/auth-rules/index.ts
@@ -5,6 +5,7 @@ export {
V2,
type AuthRule,
type AuthRuleCondition,
+ type BacktestStats,
type Conditional3DSActionParameters,
type ConditionalACHActionParameters,
type ConditionalAttribute,
@@ -15,7 +16,7 @@ export {
type ConditionalValue,
type EventStream,
type MerchantLockParameters,
- type RuleStats,
+ type ReportStats,
type VelocityLimitParams,
type VelocityLimitPeriod,
type V2ListResultsResponse,
diff --git a/src/resources/auth-rules/v2/backtests.ts b/src/resources/auth-rules/v2/backtests.ts
index a9562a9e..20f71d75 100644
--- a/src/resources/auth-rules/v2/backtests.ts
+++ b/src/resources/auth-rules/v2/backtests.ts
@@ -88,9 +88,9 @@ export interface BacktestResults {
export namespace BacktestResults {
export interface Results {
- current_version?: V2API.RuleStats | null;
+ current_version?: V2API.BacktestStats | null;
- draft_version?: V2API.RuleStats | null;
+ draft_version?: V2API.BacktestStats | null;
}
export interface SimulationParameters {
diff --git a/src/resources/auth-rules/v2/index.ts b/src/resources/auth-rules/v2/index.ts
index 0166be00..f35dc3a5 100644
--- a/src/resources/auth-rules/v2/index.ts
+++ b/src/resources/auth-rules/v2/index.ts
@@ -11,6 +11,7 @@ export {
V2,
type AuthRule,
type AuthRuleCondition,
+ type BacktestStats,
type Conditional3DSActionParameters,
type ConditionalACHActionParameters,
type ConditionalAttribute,
@@ -21,7 +22,7 @@ export {
type ConditionalValue,
type EventStream,
type MerchantLockParameters,
- type RuleStats,
+ type ReportStats,
type VelocityLimitParams,
type VelocityLimitPeriod,
type V2ListResultsResponse,
diff --git a/src/resources/auth-rules/v2/v2.ts b/src/resources/auth-rules/v2/v2.ts
index 2d1c157f..c096b249 100644
--- a/src/resources/auth-rules/v2/v2.ts
+++ b/src/resources/auth-rules/v2/v2.ts
@@ -324,6 +324,60 @@ export interface AuthRuleCondition {
value: ConditionalValue;
}
+export interface BacktestStats {
+ /**
+ * The total number of historical transactions approved by this rule during the
+ * backtest period, or the number of transactions that would have been approved if
+ * the rule was evaluated in shadow mode.
+ */
+ approved?: number;
+
+ /**
+ * The total number of historical transactions challenged by this rule during the
+ * backtest period, or the number of transactions that would have been challenged
+ * if the rule was evaluated in shadow mode. Currently applicable only for 3DS Auth
+ * Rules.
+ */
+ challenged?: number;
+
+ /**
+ * The total number of historical transactions declined by this rule during the
+ * backtest period, or the number of transactions that would have been declined if
+ * the rule was evaluated in shadow mode.
+ */
+ declined?: number;
+
+ /**
+ * Example events and their outcomes.
+ */
+ examples?: Array;
+
+ /**
+ * The version of the rule, this is incremented whenever the rule's parameters
+ * change.
+ */
+ version?: number;
+}
+
+export namespace BacktestStats {
+ export interface Example {
+ /**
+ * The decision made by the rule for this event.
+ */
+ decision?: 'APPROVED' | 'DECLINED' | 'CHALLENGED';
+
+ /**
+ * The event token.
+ */
+ event_token?: string;
+
+ /**
+ * The timestamp of the event.
+ */
+ timestamp?: string;
+ }
+}
+
export interface Conditional3DSActionParameters {
/**
* The action to take if the conditions are met.
@@ -388,13 +442,13 @@ export interface ConditionalACHActionParameters {
/**
* The action to take if the conditions are met.
*/
- action: ConditionalACHActionParameters.ApproveAction | ConditionalACHActionParameters.ReturnAction;
+ action: ConditionalACHActionParameters.ApproveActionACH | ConditionalACHActionParameters.ReturnAction;
conditions: Array;
}
export namespace ConditionalACHActionParameters {
- export interface ApproveAction {
+ export interface ApproveActionACH {
/**
* Approve the ACH transaction
*/
@@ -720,14 +774,14 @@ export interface ConditionalTokenizationActionParameters {
* The action to take if the conditions are met.
*/
action:
- | ConditionalTokenizationActionParameters.DeclineAction
+ | ConditionalTokenizationActionParameters.DeclineActionTokenization
| ConditionalTokenizationActionParameters.RequireTfaAction;
conditions: Array;
}
export namespace ConditionalTokenizationActionParameters {
- export interface DeclineAction {
+ export interface DeclineActionTokenization {
/**
* Decline the tokenization request
*/
@@ -906,50 +960,65 @@ export namespace MerchantLockParameters {
}
}
-export interface RuleStats {
+export interface ReportStats {
/**
- * The total number of historical transactions approved by this rule during the
- * relevant period, or the number of transactions that would have been approved if
- * the rule was evaluated in shadow mode.
+ * A mapping of action types to the number of times that action was returned by
+ * this rule during the relevant period. Actions are the possible outcomes of a
+ * rule evaluation, such as DECLINE, CHALLENGE, REQUIRE_TFA, etc. In case rule
+ * didn't trigger any action, it's counted under NO_ACTION key.
+ */
+ action_counts?: { [key: string]: number };
+
+ /**
+ * @deprecated The total number of historical transactions approved by this rule
+ * during the relevant period, or the number of transactions that would have been
+ * approved if the rule was evaluated in shadow mode.
*/
approved?: number;
/**
- * The total number of historical transactions challenged by this rule during the
- * relevant period, or the number of transactions that would have been challenged
- * if the rule was evaluated in shadow mode. Currently applicable only for 3DS Auth
- * Rules.
+ * @deprecated The total number of historical transactions challenged by this rule
+ * during the relevant period, or the number of transactions that would have been
+ * challenged if the rule was evaluated in shadow mode. Currently applicable only
+ * for 3DS Auth Rules.
*/
challenged?: number;
/**
- * The total number of historical transactions declined by this rule during the
- * relevant period, or the number of transactions that would have been declined if
- * the rule was evaluated in shadow mode.
+ * @deprecated The total number of historical transactions declined by this rule
+ * during the relevant period, or the number of transactions that would have been
+ * declined if the rule was evaluated in shadow mode.
*/
declined?: number;
/**
* Example events and their outcomes.
*/
- examples?: Array;
-
- /**
- * The version of the rule, this is incremented whenever the rule's parameters
- * change.
- */
- version?: number;
+ examples?: Array;
}
-export namespace RuleStats {
+export namespace ReportStats {
export interface Example {
/**
- * Whether the rule would have approved the request.
+ * The actions taken by the rule for this event.
+ */
+ actions?: Array<
+ | Example.DeclineActionAuthorization
+ | Example.ChallengeActionAuthorization
+ | Example.ResultAuthentication3DSAction
+ | Example.DeclineActionTokenization
+ | Example.RequireTfaAction
+ | Example.ApproveActionACH
+ | Example.ReturnAction
+ >;
+
+ /**
+ * @deprecated Whether the rule would have approved the request.
*/
approved?: boolean;
/**
- * The decision made by the rule for this event.
+ * @deprecated The decision made by the rule for this event.
*/
decision?: 'APPROVED' | 'DECLINED' | 'CHALLENGED';
@@ -963,6 +1032,225 @@ export namespace RuleStats {
*/
timestamp?: string;
}
+
+ export namespace Example {
+ export interface DeclineActionAuthorization {
+ /**
+ * The detailed result code explaining the specific reason for the decline
+ */
+ code:
+ | 'ACCOUNT_DAILY_SPEND_LIMIT_EXCEEDED'
+ | 'ACCOUNT_DELINQUENT'
+ | 'ACCOUNT_INACTIVE'
+ | 'ACCOUNT_LIFETIME_SPEND_LIMIT_EXCEEDED'
+ | 'ACCOUNT_MONTHLY_SPEND_LIMIT_EXCEEDED'
+ | 'ACCOUNT_PAUSED'
+ | 'ACCOUNT_UNDER_REVIEW'
+ | 'ADDRESS_INCORRECT'
+ | 'APPROVED'
+ | 'AUTH_RULE_ALLOWED_COUNTRY'
+ | 'AUTH_RULE_ALLOWED_MCC'
+ | 'AUTH_RULE_BLOCKED_COUNTRY'
+ | 'AUTH_RULE_BLOCKED_MCC'
+ | 'AUTH_RULE'
+ | 'CARD_CLOSED'
+ | 'CARD_CRYPTOGRAM_VALIDATION_FAILURE'
+ | 'CARD_EXPIRED'
+ | 'CARD_EXPIRY_DATE_INCORRECT'
+ | 'CARD_INVALID'
+ | 'CARD_NOT_ACTIVATED'
+ | 'CARD_PAUSED'
+ | 'CARD_PIN_INCORRECT'
+ | 'CARD_RESTRICTED'
+ | 'CARD_SECURITY_CODE_INCORRECT'
+ | 'CARD_SPEND_LIMIT_EXCEEDED'
+ | 'CONTACT_CARD_ISSUER'
+ | 'CUSTOMER_ASA_TIMEOUT'
+ | 'CUSTOM_ASA_RESULT'
+ | 'DECLINED'
+ | 'DO_NOT_HONOR'
+ | 'DRIVER_NUMBER_INVALID'
+ | 'FORMAT_ERROR'
+ | 'INSUFFICIENT_FUNDING_SOURCE_BALANCE'
+ | 'INSUFFICIENT_FUNDS'
+ | 'LITHIC_SYSTEM_ERROR'
+ | 'LITHIC_SYSTEM_RATE_LIMIT'
+ | 'MALFORMED_ASA_RESPONSE'
+ | 'MERCHANT_INVALID'
+ | 'MERCHANT_LOCKED_CARD_ATTEMPTED_ELSEWHERE'
+ | 'MERCHANT_NOT_PERMITTED'
+ | 'OVER_REVERSAL_ATTEMPTED'
+ | 'PIN_BLOCKED'
+ | 'PROGRAM_CARD_SPEND_LIMIT_EXCEEDED'
+ | 'PROGRAM_SUSPENDED'
+ | 'PROGRAM_USAGE_RESTRICTION'
+ | 'REVERSAL_UNMATCHED'
+ | 'SECURITY_VIOLATION'
+ | 'SINGLE_USE_CARD_REATTEMPTED'
+ | 'SUSPECTED_FRAUD'
+ | 'TRANSACTION_INVALID'
+ | 'TRANSACTION_NOT_PERMITTED_TO_ACQUIRER_OR_TERMINAL'
+ | 'TRANSACTION_NOT_PERMITTED_TO_ISSUER_OR_CARDHOLDER'
+ | 'TRANSACTION_PREVIOUSLY_COMPLETED'
+ | 'UNAUTHORIZED_MERCHANT'
+ | 'VEHICLE_NUMBER_INVALID'
+ | 'CARDHOLDER_CHALLENGED'
+ | 'CARDHOLDER_CHALLENGE_FAILED';
+
+ type: 'DECLINE';
+ }
+
+ export interface ChallengeActionAuthorization {
+ type: 'CHALLENGE';
+ }
+
+ export interface ResultAuthentication3DSAction {
+ type: 'DECLINE' | 'CHALLENGE';
+ }
+
+ export interface DeclineActionTokenization {
+ /**
+ * Decline the tokenization request
+ */
+ type: 'DECLINE';
+
+ /**
+ * Reason code for declining the tokenization request
+ */
+ reason?:
+ | 'ACCOUNT_SCORE_1'
+ | 'DEVICE_SCORE_1'
+ | 'ALL_WALLET_DECLINE_REASONS_PRESENT'
+ | 'WALLET_RECOMMENDED_DECISION_RED'
+ | 'CVC_MISMATCH'
+ | 'CARD_EXPIRY_MONTH_MISMATCH'
+ | 'CARD_EXPIRY_YEAR_MISMATCH'
+ | 'CARD_INVALID_STATE'
+ | 'CUSTOMER_RED_PATH'
+ | 'INVALID_CUSTOMER_RESPONSE'
+ | 'NETWORK_FAILURE'
+ | 'GENERIC_DECLINE'
+ | 'DIGITAL_CARD_ART_REQUIRED';
+ }
+
+ export interface RequireTfaAction {
+ /**
+ * Require two-factor authentication for the tokenization request
+ */
+ type: 'REQUIRE_TFA';
+
+ /**
+ * Reason code for requiring two-factor authentication
+ */
+ reason?:
+ | 'WALLET_RECOMMENDED_TFA'
+ | 'SUSPICIOUS_ACTIVITY'
+ | 'DEVICE_RECENTLY_LOST'
+ | 'TOO_MANY_RECENT_ATTEMPTS'
+ | 'TOO_MANY_RECENT_TOKENS'
+ | 'TOO_MANY_DIFFERENT_CARDHOLDERS'
+ | 'OUTSIDE_HOME_TERRITORY'
+ | 'HAS_SUSPENDED_TOKENS'
+ | 'HIGH_RISK'
+ | 'ACCOUNT_SCORE_LOW'
+ | 'DEVICE_SCORE_LOW'
+ | 'CARD_STATE_TFA'
+ | 'HARDCODED_TFA'
+ | 'CUSTOMER_RULE_TFA'
+ | 'DEVICE_HOST_CARD_EMULATION';
+ }
+
+ export interface ApproveActionACH {
+ /**
+ * Approve the ACH transaction
+ */
+ type: 'APPROVE';
+ }
+
+ export interface ReturnAction {
+ /**
+ * NACHA return code to use when returning the transaction. Note that the list of
+ * available return codes is subject to an allowlist configured at the program
+ * level
+ */
+ code:
+ | 'R01'
+ | 'R02'
+ | 'R03'
+ | 'R04'
+ | 'R05'
+ | 'R06'
+ | 'R07'
+ | 'R08'
+ | 'R09'
+ | 'R10'
+ | 'R11'
+ | 'R12'
+ | 'R13'
+ | 'R14'
+ | 'R15'
+ | 'R16'
+ | 'R17'
+ | 'R18'
+ | 'R19'
+ | 'R20'
+ | 'R21'
+ | 'R22'
+ | 'R23'
+ | 'R24'
+ | 'R25'
+ | 'R26'
+ | 'R27'
+ | 'R28'
+ | 'R29'
+ | 'R30'
+ | 'R31'
+ | 'R32'
+ | 'R33'
+ | 'R34'
+ | 'R35'
+ | 'R36'
+ | 'R37'
+ | 'R38'
+ | 'R39'
+ | 'R40'
+ | 'R41'
+ | 'R42'
+ | 'R43'
+ | 'R44'
+ | 'R45'
+ | 'R46'
+ | 'R47'
+ | 'R50'
+ | 'R51'
+ | 'R52'
+ | 'R53'
+ | 'R61'
+ | 'R62'
+ | 'R67'
+ | 'R68'
+ | 'R69'
+ | 'R70'
+ | 'R71'
+ | 'R72'
+ | 'R73'
+ | 'R74'
+ | 'R75'
+ | 'R76'
+ | 'R77'
+ | 'R80'
+ | 'R81'
+ | 'R82'
+ | 'R83'
+ | 'R84'
+ | 'R85';
+
+ /**
+ * Return the ACH transaction
+ */
+ type: 'RETURN';
+ }
+ }
}
export interface VelocityLimitParams {
@@ -1146,7 +1434,9 @@ export namespace V2ListResultsResponse {
/**
* Actions returned by the rule evaluation
*/
- actions: Array;
+ actions: Array<
+ AuthorizationResult.DeclineActionAuthorization | AuthorizationResult.ChallengeActionAuthorization
+ >;
/**
* The Auth Rule token
@@ -1180,8 +1470,79 @@ export namespace V2ListResultsResponse {
}
export namespace AuthorizationResult {
- export interface Action {
- type: 'DECLINE' | 'CHALLENGE';
+ export interface DeclineActionAuthorization {
+ /**
+ * The detailed result code explaining the specific reason for the decline
+ */
+ code:
+ | 'ACCOUNT_DAILY_SPEND_LIMIT_EXCEEDED'
+ | 'ACCOUNT_DELINQUENT'
+ | 'ACCOUNT_INACTIVE'
+ | 'ACCOUNT_LIFETIME_SPEND_LIMIT_EXCEEDED'
+ | 'ACCOUNT_MONTHLY_SPEND_LIMIT_EXCEEDED'
+ | 'ACCOUNT_PAUSED'
+ | 'ACCOUNT_UNDER_REVIEW'
+ | 'ADDRESS_INCORRECT'
+ | 'APPROVED'
+ | 'AUTH_RULE_ALLOWED_COUNTRY'
+ | 'AUTH_RULE_ALLOWED_MCC'
+ | 'AUTH_RULE_BLOCKED_COUNTRY'
+ | 'AUTH_RULE_BLOCKED_MCC'
+ | 'AUTH_RULE'
+ | 'CARD_CLOSED'
+ | 'CARD_CRYPTOGRAM_VALIDATION_FAILURE'
+ | 'CARD_EXPIRED'
+ | 'CARD_EXPIRY_DATE_INCORRECT'
+ | 'CARD_INVALID'
+ | 'CARD_NOT_ACTIVATED'
+ | 'CARD_PAUSED'
+ | 'CARD_PIN_INCORRECT'
+ | 'CARD_RESTRICTED'
+ | 'CARD_SECURITY_CODE_INCORRECT'
+ | 'CARD_SPEND_LIMIT_EXCEEDED'
+ | 'CONTACT_CARD_ISSUER'
+ | 'CUSTOMER_ASA_TIMEOUT'
+ | 'CUSTOM_ASA_RESULT'
+ | 'DECLINED'
+ | 'DO_NOT_HONOR'
+ | 'DRIVER_NUMBER_INVALID'
+ | 'FORMAT_ERROR'
+ | 'INSUFFICIENT_FUNDING_SOURCE_BALANCE'
+ | 'INSUFFICIENT_FUNDS'
+ | 'LITHIC_SYSTEM_ERROR'
+ | 'LITHIC_SYSTEM_RATE_LIMIT'
+ | 'MALFORMED_ASA_RESPONSE'
+ | 'MERCHANT_INVALID'
+ | 'MERCHANT_LOCKED_CARD_ATTEMPTED_ELSEWHERE'
+ | 'MERCHANT_NOT_PERMITTED'
+ | 'OVER_REVERSAL_ATTEMPTED'
+ | 'PIN_BLOCKED'
+ | 'PROGRAM_CARD_SPEND_LIMIT_EXCEEDED'
+ | 'PROGRAM_SUSPENDED'
+ | 'PROGRAM_USAGE_RESTRICTION'
+ | 'REVERSAL_UNMATCHED'
+ | 'SECURITY_VIOLATION'
+ | 'SINGLE_USE_CARD_REATTEMPTED'
+ | 'SUSPECTED_FRAUD'
+ | 'TRANSACTION_INVALID'
+ | 'TRANSACTION_NOT_PERMITTED_TO_ACQUIRER_OR_TERMINAL'
+ | 'TRANSACTION_NOT_PERMITTED_TO_ISSUER_OR_CARDHOLDER'
+ | 'TRANSACTION_PREVIOUSLY_COMPLETED'
+ | 'UNAUTHORIZED_MERCHANT'
+ | 'VEHICLE_NUMBER_INVALID'
+ | 'CARDHOLDER_CHALLENGED'
+ | 'CARDHOLDER_CHALLENGE_FAILED';
+
+ type: 'DECLINE';
+
+ /**
+ * Optional explanation for why this action was taken
+ */
+ explanation?: string;
+ }
+
+ export interface ChallengeActionAuthorization {
+ type: 'CHALLENGE';
/**
* Optional explanation for why this action was taken
@@ -1252,7 +1613,7 @@ export namespace V2ListResultsResponse {
/**
* Actions returned by the rule evaluation
*/
- actions: Array;
+ actions: Array;
/**
* The Auth Rule token
@@ -1286,7 +1647,7 @@ export namespace V2ListResultsResponse {
}
export namespace TokenizationResult {
- export interface DeclineAction {
+ export interface DeclineActionTokenization {
/**
* Decline the tokenization request
*/
@@ -1358,7 +1719,7 @@ export namespace V2ListResultsResponse {
/**
* Actions returned by the rule evaluation
*/
- actions: Array;
+ actions: Array;
/**
* The Auth Rule token
@@ -1392,7 +1753,7 @@ export namespace V2ListResultsResponse {
}
export namespace ACHResult {
- export interface ApproveAction {
+ export interface ApproveActionACH {
/**
* Approve the ACH transaction
*/
@@ -1619,7 +1980,7 @@ export namespace V2RetrieveReportResponse {
/**
* Detailed statistics for the current version of the rule.
*/
- current_version_statistics: V2API.RuleStats | null;
+ current_version_statistics: V2API.ReportStats | null;
/**
* The date (UTC) for which the statistics are reported.
@@ -1629,7 +1990,7 @@ export namespace V2RetrieveReportResponse {
/**
* Detailed statistics for the draft version of the rule.
*/
- draft_version_statistics: V2API.RuleStats | null;
+ draft_version_statistics: V2API.ReportStats | null;
}
}
@@ -1918,6 +2279,18 @@ export interface V2ListResultsParams extends CursorPageParams {
*/
auth_rule_token?: string;
+ /**
+ * Date string in RFC 3339 format. Only events evaluated after the specified time
+ * will be included. UTC time zone.
+ */
+ begin?: string;
+
+ /**
+ * Date string in RFC 3339 format. Only events evaluated before the specified time
+ * will be included. UTC time zone.
+ */
+ end?: string;
+
/**
* Filter by event token
*/
@@ -1954,6 +2327,7 @@ export declare namespace V2 {
export {
type AuthRule as AuthRule,
type AuthRuleCondition as AuthRuleCondition,
+ type BacktestStats as BacktestStats,
type Conditional3DSActionParameters as Conditional3DSActionParameters,
type ConditionalACHActionParameters as ConditionalACHActionParameters,
type ConditionalAttribute as ConditionalAttribute,
@@ -1964,7 +2338,7 @@ export declare namespace V2 {
type ConditionalValue as ConditionalValue,
type EventStream as EventStream,
type MerchantLockParameters as MerchantLockParameters,
- type RuleStats as RuleStats,
+ type ReportStats as ReportStats,
type VelocityLimitParams as VelocityLimitParams,
type VelocityLimitPeriod as VelocityLimitPeriod,
type V2ListResultsResponse as V2ListResultsResponse,
diff --git a/tests/api-resources/auth-rules/v2/v2.test.ts b/tests/api-resources/auth-rules/v2/v2.test.ts
index 7fa93ea9..488f6402 100644
--- a/tests/api-resources/auth-rules/v2/v2.test.ts
+++ b/tests/api-resources/auth-rules/v2/v2.test.ts
@@ -141,6 +141,8 @@ describe('resource v2', () => {
client.authRules.v2.listResults(
{
auth_rule_token: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
+ begin: '2019-12-27T18:11:19.117Z',
+ end: '2019-12-27T18:11:19.117Z',
ending_before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
event_token: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
has_actions: true,
From e0b8292748ddb37a3758a909c5e7314c511985e4 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 2 Mar 2026 19:49:06 +0000
Subject: [PATCH 2/8] feat(api): Remove deprecated beneficial owner entities
field
---
.stats.yml | 4 +-
.../account-holders/account-holders.ts | 197 ------------------
src/resources/account-holders/entities.ts | 8 +-
src/resources/webhooks.ts | 10 -
.../account-holders/account-holders.test.ts | 17 --
5 files changed, 6 insertions(+), 230 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 17f87283..1cea7b96 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 185
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-b29a4bd5ca21348ef426162cbd1fa21070f695572626e4e6faabfa14af38f0b0.yml
-openapi_spec_hash: e7c285d6b7006d040ecb50a9d0d2fc17
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-df289940d26615072a7c5c9dd4d32b9bc7a86d977642b377c58abbe7a4cb93d0.yml
+openapi_spec_hash: 836bb078df7ac5f8d2dd5081c2e833be
config_hash: fb5070d41fcabdedbc084b83964b592a
diff --git a/src/resources/account-holders/account-holders.ts b/src/resources/account-holders/account-holders.ts
index 43e56e22..39d12907 100644
--- a/src/resources/account-holders/account-holders.ts
+++ b/src/resources/account-holders/account-holders.ts
@@ -62,15 +62,6 @@ export class AccountHolders extends APIResource {
* nature_of_business: 'Software company selling solutions to the restaurant industry',
* tos_timestamp: '2022-03-08T08:00:00Z',
* workflow: 'KYB_BYO',
- * beneficial_owner_entities: [
- * {
- * address: { ... },
- * dba_business_name: 'MHoldings',
- * government_id: '98-7654321',
- * legal_business_name: 'Majority Holdings LLC',
- * phone_numbers: ['+15555555555'],
- * },
- * ],
* kyb_passed_timestamp: '2022-03-08T08:00:00Z',
* naics_code: '541512',
* website_url: 'https://www.mybusiness.com',
@@ -331,11 +322,6 @@ export interface AccountHolder {
*/
account_token?: string;
- /**
- * @deprecated Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* Only present when user_type == "BUSINESS". You must submit a list of all direct
* and indirect individuals with 25% or more ownership in the company. A maximum of
@@ -468,48 +454,6 @@ export interface AccountHolder {
}
export namespace AccountHolder {
- export interface BeneficialOwnerEntity {
- /**
- * Business's physical address - PO boxes, UPS drops, and FedEx drops are not
- * acceptable; APO/FPO are acceptable.
- */
- address: Shared.Address;
-
- /**
- * Any name that the business operates under that is not its legal business name
- * (if applicable).
- */
- dba_business_name: string;
-
- /**
- * Globally unique identifier for the entity.
- */
- entity_token: string;
-
- /**
- * Government-issued identification number. US Federal Employer Identification
- * Numbers (EIN) are currently supported, entered as full nine-digits, with or
- * without hyphens.
- */
- government_id: string;
-
- /**
- * Legal (formal) business name.
- */
- legal_business_name: string;
-
- /**
- * One or more of the business's phone number(s), entered as a list in E.164
- * format.
- */
- phone_numbers: Array;
-
- /**
- * Parent company name (if applicable).
- */
- parent_company?: string;
- }
-
/**
* Information about an individual associated with an account holder. A subset of
* the information provided via KYC. For example, we do not return the government
@@ -808,11 +752,6 @@ export interface KYB {
*/
workflow: 'KYB_BASIC' | 'KYB_BYO';
- /**
- * @deprecated Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* A user provided id that can be used to link an account holder with an external
* system
@@ -977,43 +916,6 @@ export namespace KYB {
*/
phone_number?: string;
}
-
- export interface BeneficialOwnerEntity {
- /**
- * Business's physical address - PO boxes, UPS drops, and FedEx drops are not
- * acceptable; APO/FPO are acceptable.
- */
- address: Shared.Address;
-
- /**
- * Government-issued identification number. US Federal Employer Identification
- * Numbers (EIN) are currently supported, entered as full nine-digits, with or
- * without hyphens.
- */
- government_id: string;
-
- /**
- * Legal (formal) business name.
- */
- legal_business_name: string;
-
- /**
- * One or more of the business's phone number(s), entered as a list in E.164
- * format.
- */
- phone_numbers: Array;
-
- /**
- * Any name that the business operates under that is not its legal business name
- * (if applicable).
- */
- dba_business_name?: string;
-
- /**
- * Parent company name (if applicable).
- */
- parent_company?: string;
- }
}
export interface KYBBusinessEntity {
@@ -1330,11 +1232,6 @@ export namespace AccountHolderUpdateResponse {
*/
account_token?: string;
- /**
- * Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* Only present when user_type == "BUSINESS". You must submit a list of all direct
* and indirect individuals with 25% or more ownership in the company. A maximum of
@@ -1890,11 +1787,6 @@ export interface AccountHolderSimulateEnrollmentReviewResponse {
*/
account_token?: string;
- /**
- * Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* Only present when user_type == "BUSINESS". You must submit a list of all direct
* and indirect individuals with 25% or more ownership in the company. A maximum of
@@ -2406,11 +2298,6 @@ export declare namespace AccountHolderCreateParams {
*/
workflow: 'KYB_BASIC' | 'KYB_BYO';
- /**
- * @deprecated Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* A user provided id that can be used to link an account holder with an external
* system
@@ -2575,43 +2462,6 @@ export declare namespace AccountHolderCreateParams {
*/
phone_number?: string;
}
-
- export interface BeneficialOwnerEntity {
- /**
- * Business's physical address - PO boxes, UPS drops, and FedEx drops are not
- * acceptable; APO/FPO are acceptable.
- */
- address: Shared.Address;
-
- /**
- * Government-issued identification number. US Federal Employer Identification
- * Numbers (EIN) are currently supported, entered as full nine-digits, with or
- * without hyphens.
- */
- government_id: string;
-
- /**
- * Legal (formal) business name.
- */
- legal_business_name: string;
-
- /**
- * One or more of the business's phone number(s), entered as a list in E.164
- * format.
- */
- phone_numbers: Array;
-
- /**
- * Any name that the business operates under that is not its legal business name
- * (if applicable).
- */
- dba_business_name?: string;
-
- /**
- * Parent company name (if applicable).
- */
- parent_company?: string;
- }
}
export interface KYBDelegated {
@@ -2958,11 +2808,6 @@ export type AccountHolderUpdateParams =
export declare namespace AccountHolderUpdateParams {
export interface KYBPatchRequest {
- /**
- * @deprecated Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* You must submit a list of all direct and indirect individuals with 25% or more
* ownership in the company. A maximum of 4 beneficial owners can be submitted. If
@@ -3016,48 +2861,6 @@ export declare namespace AccountHolderUpdateParams {
}
export namespace KYBPatchRequest {
- export interface BeneficialOwnerEntity {
- /**
- * Globally unique identifier for an entity.
- */
- entity_token: string;
-
- /**
- * Business''s physical address - PO boxes, UPS drops, and FedEx drops are not
- * acceptable; APO/FPO are acceptable.
- */
- address?: AccountHoldersAPI.AddressUpdate;
-
- /**
- * Any name that the business operates under that is not its legal business name
- * (if applicable).
- */
- dba_business_name?: string;
-
- /**
- * Government-issued identification number. US Federal Employer Identification
- * Numbers (EIN) are currently supported, entered as full nine-digits, with or
- * without hyphens.
- */
- government_id?: string;
-
- /**
- * Legal (formal) business name.
- */
- legal_business_name?: string;
-
- /**
- * Parent company name (if applicable).
- */
- parent_company?: string;
-
- /**
- * One or more of the business's phone number(s), entered as a list in E.164
- * format.
- */
- phone_numbers?: Array;
- }
-
/**
* Individuals associated with a KYB application. Phone number is optional.
*/
diff --git a/src/resources/account-holders/entities.ts b/src/resources/account-holders/entities.ts
index fde363d0..3ca8796d 100644
--- a/src/resources/account-holders/entities.ts
+++ b/src/resources/account-holders/entities.ts
@@ -8,8 +8,8 @@ import { path } from '../../internal/utils/path';
export class Entities extends APIResource {
/**
- * Create a new beneficial owner or replace the control person entity on an
- * existing KYB account holder. This endpoint is only applicable for account
+ * Create a new beneficial owner individual or replace the control person entity on
+ * an existing KYB account holder. This endpoint is only applicable for account
* holders enrolled through a KYB workflow with the Persona KYB provider. A new
* control person can only replace the existing one. A maximum of 4 beneficial
* owners can be associated with an account holder.
@@ -46,8 +46,8 @@ export class Entities extends APIResource {
}
/**
- * Deactivate a beneficial owner entity on an existing KYB account holder. Only
- * beneficial owner entities can be deactivated.
+ * Deactivate a beneficial owner individual on an existing KYB account holder. Only
+ * beneficial owner individuals can be deactivated.
*
* @example
* ```ts
diff --git a/src/resources/webhooks.ts b/src/resources/webhooks.ts
index 916dad08..e92629db 100644
--- a/src/resources/webhooks.ts
+++ b/src/resources/webhooks.ts
@@ -175,11 +175,6 @@ export namespace AccountHolderUpdatedWebhookEvent {
* Original request to update the account holder.
*/
export interface UpdateRequest {
- /**
- * @deprecated Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* You must submit a list of all direct and indirect individuals with 25% or more
* ownership in the company. A maximum of 4 beneficial owners can be submitted. If
@@ -2501,11 +2496,6 @@ export namespace ParsedWebhookEvent {
* Original request to update the account holder.
*/
export interface UpdateRequest {
- /**
- * @deprecated Deprecated.
- */
- beneficial_owner_entities?: Array;
-
/**
* You must submit a list of all direct and indirect individuals with 25% or more
* ownership in the company. A maximum of 4 beneficial owners can be submitted. If
diff --git a/tests/api-resources/account-holders/account-holders.test.ts b/tests/api-resources/account-holders/account-holders.test.ts
index 4429f670..490692da 100644
--- a/tests/api-resources/account-holders/account-holders.test.ts
+++ b/tests/api-resources/account-holders/account-holders.test.ts
@@ -119,23 +119,6 @@ describe('resource accountHolders', () => {
nature_of_business: 'Software company selling solutions to the restaurant industry',
tos_timestamp: '2018-05-29T21:16:05Z',
workflow: 'KYB_BASIC',
- beneficial_owner_entities: [
- {
- address: {
- address1: '123 Old Forest Way',
- city: 'Omaha',
- country: 'USA',
- postal_code: '68022',
- state: 'NE',
- address2: 'address2',
- },
- government_id: '114-123-1513',
- legal_business_name: 'Acme, Inc.',
- phone_numbers: ['+15555555555'],
- dba_business_name: 'dba_business_name',
- parent_company: 'parent_company',
- },
- ],
external_id: 'external_id',
kyb_passed_timestamp: '2018-05-29T21:16:05Z',
naics_code: '541512',
From 582aeb7164a9e9523becb601a08e7393904cd4e5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 2 Mar 2026 23:04:08 +0000
Subject: [PATCH 3/8] feat(api): Add Hold API for financial account fund
reservations
---
.stats.yml | 4 ++--
src/resources/payments.ts | 15 +++++++++++++++
tests/api-resources/payments.test.ts | 1 +
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 1cea7b96..3301005b 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 185
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-df289940d26615072a7c5c9dd4d32b9bc7a86d977642b377c58abbe7a4cb93d0.yml
-openapi_spec_hash: 836bb078df7ac5f8d2dd5081c2e833be
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-45bd51c1d7885bde620179da56671e3378571e301528c60975604c4fbaa2c800.yml
+openapi_spec_hash: e1355583b829f269875b6f800078a9e0
config_hash: fb5070d41fcabdedbc084b83964b592a
diff --git a/src/resources/payments.ts b/src/resources/payments.ts
index 1fd9cea9..36f60559 100644
--- a/src/resources/payments.ts
+++ b/src/resources/payments.ts
@@ -606,6 +606,11 @@ export interface PaymentCreateParams {
*/
token?: string;
+ /**
+ * Optional hold to settle when this payment is initiated.
+ */
+ hold?: PaymentCreateParams.Hold;
+
memo?: string;
user_defined_id?: string;
@@ -622,6 +627,16 @@ export namespace PaymentCreateParams {
addenda?: string | null;
}
+
+ /**
+ * Optional hold to settle when this payment is initiated.
+ */
+ export interface Hold {
+ /**
+ * Token of the hold to settle when this payment is initiated.
+ */
+ token: string;
+ }
}
export interface PaymentListParams extends CursorPageParams {
diff --git a/tests/api-resources/payments.test.ts b/tests/api-resources/payments.test.ts
index 617dd768..d42b8cb6 100644
--- a/tests/api-resources/payments.test.ts
+++ b/tests/api-resources/payments.test.ts
@@ -39,6 +39,7 @@ describe('resource payments', () => {
},
type: 'COLLECTION',
token: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
+ hold: { token: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' },
memo: 'memo',
user_defined_id: 'user_defined_id',
});
From bccb03cc6e6d046aa76dac2b77237233d1a614a7 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 4 Mar 2026 02:59:35 +0000
Subject: [PATCH 4/8] chore(internal): codegen related update
---
packages/mcp-server/package.json | 6 +-
packages/mcp-server/src/code-tool.ts | 28 ++-
packages/mcp-server/src/docs-search-tool.ts | 37 ++-
packages/mcp-server/src/http.ts | 74 ++++--
packages/mcp-server/src/index.ts | 26 +-
packages/mcp-server/src/instructions.ts | 3 +-
packages/mcp-server/src/logger.ts | 28 +++
packages/mcp-server/src/options.ts | 11 +
packages/mcp-server/src/stdio.ts | 3 +-
packages/mcp-server/yarn.lock | 265 ++++++++++++++++++--
tests/api-resources/webhooks.test.ts | 77 ++++--
11 files changed, 468 insertions(+), 90 deletions(-)
create mode 100644 packages/mcp-server/src/logger.ts
diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json
index 2a29d262..2571b33c 100644
--- a/packages/mcp-server/package.json
+++ b/packages/mcp-server/package.json
@@ -39,8 +39,9 @@
"express": "^5.1.0",
"fuse.js": "^7.1.0",
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz",
- "morgan": "^1.10.0",
- "morgan-body": "^2.6.9",
+ "pino": "^10.3.1",
+ "pino-http": "^11.0.0",
+ "pino-pretty": "^13.1.3",
"qs": "^6.14.1",
"typescript": "5.8.3",
"yargs": "^17.7.2",
@@ -57,7 +58,6 @@
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jest": "^29.4.0",
- "@types/morgan": "^1.9.10",
"@types/qs": "^6.14.0",
"@types/yargs": "^17.0.8",
"@typescript-eslint/eslint-plugin": "8.31.1",
diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts
index 2939b217..0d52a8a7 100644
--- a/packages/mcp-server/src/code-tool.ts
+++ b/packages/mcp-server/src/code-tool.ts
@@ -17,6 +17,7 @@ import {
import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { readEnv, requireValue } from './util';
import { WorkerInput, WorkerOutput } from './code-tool-types';
+import { getLogger } from './logger';
import { SdkMethod } from './methods';
import { McpCodeExecutionMode } from './options';
import { ClientOptions } from 'lithic';
@@ -83,6 +84,8 @@ export function codeTool({
},
};
+ const logger = getLogger();
+
const handler = async ({
reqContext,
args,
@@ -107,11 +110,27 @@ export function codeTool({
}
}
+ let result: ToolCallResult;
+ const startTime = Date.now();
+
if (codeExecutionMode === 'local') {
- return await localDenoHandler({ reqContext, args });
+ logger.debug('Executing code in local Deno environment');
+ result = await localDenoHandler({ reqContext, args });
} else {
- return await remoteStainlessHandler({ reqContext, args });
+ logger.debug('Executing code in remote Stainless environment');
+ result = await remoteStainlessHandler({ reqContext, args });
}
+
+ logger.info(
+ {
+ codeExecutionMode,
+ durationMs: Date.now() - startTime,
+ isError: result.isError,
+ contentRows: result.content?.length ?? 0,
+ },
+ 'Got code tool execution result',
+ );
+ return result;
};
return { metadata, tool, handler };
@@ -157,6 +176,11 @@ const remoteStainlessHandler = async ({
});
if (!res.ok) {
+ if (res.status === 404 && !reqContext.stainlessApiKey) {
+ throw new Error(
+ 'Could not access code tool for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.',
+ );
+ }
throw new Error(
`${res.status}: ${
res.statusText
diff --git a/packages/mcp-server/src/docs-search-tool.ts b/packages/mcp-server/src/docs-search-tool.ts
index 8dd26a03..0fa5587f 100644
--- a/packages/mcp-server/src/docs-search-tool.ts
+++ b/packages/mcp-server/src/docs-search-tool.ts
@@ -1,7 +1,8 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { Metadata, McpRequestContext, asTextContentResult } from './types';
import { Tool } from '@modelcontextprotocol/sdk/types.js';
+import { Metadata, McpRequestContext, asTextContentResult } from './types';
+import { getLogger } from './logger';
export const metadata: Metadata = {
resource: 'all',
@@ -50,19 +51,49 @@ export const handler = async ({
}) => {
const body = args as any;
const query = new URLSearchParams(body).toString();
+
+ const startTime = Date.now();
const result = await fetch(`${docsSearchURL}?${query}`, {
headers: {
...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }),
},
});
+ const logger = getLogger();
+
if (!result.ok) {
+ const errorText = await result.text();
+ logger.warn(
+ {
+ durationMs: Date.now() - startTime,
+ query: body.query,
+ status: result.status,
+ statusText: result.statusText,
+ errorText,
+ },
+ 'Got error response from docs search tool',
+ );
+
+ if (result.status === 404 && !reqContext.stainlessApiKey) {
+ throw new Error(
+ 'Could not find docs for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.',
+ );
+ }
+
throw new Error(
- `${result.status}: ${result.statusText} when using doc search tool. Details: ${await result.text()}`,
+ `${result.status}: ${result.statusText} when using doc search tool. Details: ${errorText}`,
);
}
- return asTextContentResult(await result.json());
+ const resultBody = await result.json();
+ logger.info(
+ {
+ durationMs: Date.now() - startTime,
+ query: body.query,
+ },
+ 'Got docs search result',
+ );
+ return asTextContentResult(resultBody);
};
export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts
index b1f56bed..cbca4fd1 100644
--- a/packages/mcp-server/src/http.ts
+++ b/packages/mcp-server/src/http.ts
@@ -4,9 +4,10 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { ClientOptions } from 'lithic';
import express from 'express';
-import morgan from 'morgan';
-import morganBody from 'morgan-body';
+import pino from 'pino';
+import pinoHttp from 'pino-http';
import { getStainlessApiKey, parseClientAuthHeaders } from './auth';
+import { getLogger } from './logger';
import { McpOptions } from './options';
import { initMcpServer, newMcpServer } from './server';
@@ -70,29 +71,60 @@ const del = async (req: express.Request, res: express.Response) => {
});
};
+const redactHeaders = (headers: Record) => {
+ const hiddenHeaders = /auth|cookie|key|token/i;
+ const filtered = { ...headers };
+ Object.keys(filtered).forEach((key) => {
+ if (hiddenHeaders.test(key)) {
+ filtered[key] = '[REDACTED]';
+ }
+ });
+ return filtered;
+};
+
export const streamableHTTPApp = ({
clientOptions = {},
mcpOptions,
- debug,
}: {
clientOptions?: ClientOptions;
mcpOptions: McpOptions;
- debug: boolean;
}): express.Express => {
const app = express();
app.set('query parser', 'extended');
app.use(express.json());
-
- if (debug) {
- morganBody(app, {
- logAllReqHeader: true,
- logAllResHeader: true,
- logRequestBody: true,
- logResponseBody: true,
- });
- } else {
- app.use(morgan('combined'));
- }
+ app.use(
+ pinoHttp({
+ logger: getLogger(),
+ customLogLevel: (req, res) => {
+ if (res.statusCode >= 500) {
+ return 'error';
+ } else if (res.statusCode >= 400) {
+ return 'warn';
+ }
+ return 'info';
+ },
+ customSuccessMessage: function (req, res) {
+ return `Request ${req.method} to ${req.url} completed with status ${res.statusCode}`;
+ },
+ customErrorMessage: function (req, res, err) {
+ return `Request ${req.method} to ${req.url} errored with status ${res.statusCode}`;
+ },
+ serializers: {
+ req: pino.stdSerializers.wrapRequestSerializer((req) => {
+ return {
+ ...req,
+ headers: redactHeaders(req.raw.headers),
+ };
+ }),
+ res: pino.stdSerializers.wrapResponseSerializer((res) => {
+ return {
+ ...res,
+ headers: redactHeaders(res.headers),
+ };
+ }),
+ },
+ }),
+ );
app.get('/health', async (req: express.Request, res: express.Response) => {
res.status(200).send('OK');
@@ -106,22 +138,22 @@ export const streamableHTTPApp = ({
export const launchStreamableHTTPServer = async ({
mcpOptions,
- debug,
port,
}: {
mcpOptions: McpOptions;
- debug: boolean;
port: number | string | undefined;
}) => {
- const app = streamableHTTPApp({ mcpOptions, debug });
+ const app = streamableHTTPApp({ mcpOptions });
const server = app.listen(port);
const address = server.address();
+ const logger = getLogger();
+
if (typeof address === 'string') {
- console.error(`MCP Server running on streamable HTTP at ${address}`);
+ logger.info(`MCP Server running on streamable HTTP at ${address}`);
} else if (address !== null) {
- console.error(`MCP Server running on streamable HTTP on port ${address.port}`);
+ logger.info(`MCP Server running on streamable HTTP on port ${address.port}`);
} else {
- console.error(`MCP Server running on streamable HTTP on port ${port}`);
+ logger.info(`MCP Server running on streamable HTTP on port ${port}`);
}
};
diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts
index 654d25cf..5bca4a60 100644
--- a/packages/mcp-server/src/index.ts
+++ b/packages/mcp-server/src/index.ts
@@ -5,15 +5,20 @@ import { McpOptions, parseCLIOptions } from './options';
import { launchStdioServer } from './stdio';
import { launchStreamableHTTPServer } from './http';
import type { McpTool } from './types';
+import { configureLogger, getLogger } from './logger';
async function main() {
const options = parseOptionsOrError();
+ configureLogger({
+ level: options.debug ? 'debug' : 'info',
+ pretty: options.logFormat === 'pretty',
+ });
const selectedTools = await selectToolsOrError(options);
- console.error(
- `MCP Server starting with ${selectedTools.length} tools:`,
- selectedTools.map((e) => e.tool.name),
+ getLogger().info(
+ { tools: selectedTools.map((e) => e.tool.name) },
+ `MCP Server starting with ${selectedTools.length} tools`,
);
switch (options.transport) {
@@ -23,7 +28,6 @@ async function main() {
case 'http':
await launchStreamableHTTPServer({
mcpOptions: options,
- debug: options.debug,
port: options.socket ?? options.port,
});
break;
@@ -32,7 +36,8 @@ async function main() {
if (require.main === module) {
main().catch((error) => {
- console.error('Fatal error in main():', error);
+ // Logger might not be initialized yet
+ console.error('Fatal error in main()', error);
process.exit(1);
});
}
@@ -41,7 +46,8 @@ function parseOptionsOrError() {
try {
return parseCLIOptions();
} catch (error) {
- console.error('Error parsing options:', error);
+ // Logger is initialized after options, so use console.error here
+ console.error('Error parsing options', error);
process.exit(1);
}
}
@@ -50,16 +56,12 @@ async function selectToolsOrError(options: McpOptions): Promise {
try {
const includedTools = selectTools(options);
if (includedTools.length === 0) {
- console.error('No tools match the provided filters.');
+ getLogger().error('No tools match the provided filters');
process.exit(1);
}
return includedTools;
} catch (error) {
- if (error instanceof Error) {
- console.error('Error filtering tools:', error.message);
- } else {
- console.error('Error filtering tools:', error);
- }
+ getLogger().error({ error }, 'Error filtering tools');
process.exit(1);
}
}
diff --git a/packages/mcp-server/src/instructions.ts b/packages/mcp-server/src/instructions.ts
index 3e2dd699..2cfce0f5 100644
--- a/packages/mcp-server/src/instructions.ts
+++ b/packages/mcp-server/src/instructions.ts
@@ -1,6 +1,7 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
import { readEnv } from './util';
+import { getLogger } from './logger';
const INSTRUCTIONS_CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes
@@ -50,7 +51,7 @@ async function fetchLatestInstructions(stainlessApiKey: string | undefined): Pro
let instructions: string | undefined;
if (!response.ok) {
- console.warn(
+ getLogger().warn(
'Warning: failed to retrieve MCP server instructions. Proceeding with default instructions...',
);
diff --git a/packages/mcp-server/src/logger.ts b/packages/mcp-server/src/logger.ts
new file mode 100644
index 00000000..29dab11c
--- /dev/null
+++ b/packages/mcp-server/src/logger.ts
@@ -0,0 +1,28 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { pino, type Level, type Logger } from 'pino';
+import pretty from 'pino-pretty';
+
+let _logger: Logger | undefined;
+
+export function configureLogger({ level, pretty: usePretty }: { level: Level; pretty: boolean }): void {
+ _logger = pino(
+ {
+ level,
+ timestamp: pino.stdTimeFunctions.isoTime,
+ formatters: {
+ level(label) {
+ return { level: label };
+ },
+ },
+ },
+ usePretty ? pretty({ colorize: true, levelFirst: true, destination: 2 }) : process.stderr,
+ );
+}
+
+export function getLogger(): Logger {
+ if (!_logger) {
+ throw new Error('Logger has not been configured. Call configureLogger() before using the logger.');
+ }
+ return _logger;
+}
diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts
index 069b8811..b9e8e8a6 100644
--- a/packages/mcp-server/src/options.ts
+++ b/packages/mcp-server/src/options.ts
@@ -8,6 +8,7 @@ import { readEnv } from './util';
export type CLIOptions = McpOptions & {
debug: boolean;
+ logFormat: 'json' | 'pretty';
transport: 'stdio' | 'http';
port: number | undefined;
socket: string | undefined;
@@ -52,6 +53,11 @@ export function parseCLIOptions(): CLIOptions {
"Where to run code execution in code tool; 'stainless-sandbox' will execute code in Stainless-hosted sandboxes whereas 'local' will execute code locally on the MCP server machine.",
})
.option('debug', { type: 'boolean', description: 'Enable debug logging' })
+ .option('log-format', {
+ type: 'string',
+ choices: ['json', 'pretty'],
+ description: 'Format for log output; defaults to json unless tty is detected',
+ })
.option('no-tools', {
type: 'string',
array: true,
@@ -97,6 +103,10 @@ export function parseCLIOptions(): CLIOptions {
const includeDocsTools = shouldIncludeToolType('docs');
const transport = argv.transport as 'stdio' | 'http';
+ const logFormat =
+ argv.logFormat ? (argv.logFormat as 'json' | 'pretty')
+ : process.stderr.isTTY ? 'pretty'
+ : 'json';
return {
...(includeCodeTool !== undefined && { includeCodeTool }),
@@ -108,6 +118,7 @@ export function parseCLIOptions(): CLIOptions {
codeBlockedMethods: argv.codeBlockedMethods,
codeExecutionMode: argv.codeExecutionMode as McpCodeExecutionMode,
transport,
+ logFormat,
port: argv.port,
socket: argv.socket,
};
diff --git a/packages/mcp-server/src/stdio.ts b/packages/mcp-server/src/stdio.ts
index ceccaed3..e8bcbb19 100644
--- a/packages/mcp-server/src/stdio.ts
+++ b/packages/mcp-server/src/stdio.ts
@@ -1,6 +1,7 @@
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { McpOptions } from './options';
import { initMcpServer, newMcpServer } from './server';
+import { getLogger } from './logger';
export const launchStdioServer = async (mcpOptions: McpOptions) => {
const server = await newMcpServer(mcpOptions.stainlessApiKey);
@@ -9,5 +10,5 @@ export const launchStdioServer = async (mcpOptions: McpOptions) => {
const transport = new StdioServerTransport();
await server.connect(transport);
- console.error('MCP Server running on stdio');
+ getLogger().info('MCP Server running on stdio');
};
diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock
index fe102775..14529bc9 100644
--- a/packages/mcp-server/yarn.lock
+++ b/packages/mcp-server/yarn.lock
@@ -329,10 +329,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
-"@hono/node-server@^1.19.7":
- version "1.19.9"
- resolved "https://registry.yarnpkg.com/@hono/node-server/-/node-server-1.19.9.tgz#8f37119b1acf283fd3f6035f3d1356fdb97a09ac"
- integrity sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==
+"@hono/node-server@^1.19.9":
+ version "1.19.10"
+ resolved "https://registry.yarnpkg.com/@hono/node-server/-/node-server-1.19.10.tgz#e230fbb7fb31891cafc653d01deee03f437dd66b"
+ integrity sha512-hZ7nOssGqRgyV3FVVQdfi+U4q02uB23bpnYpdvNXkYTRRyWx84b7yf1ans+dnJ/7h41sGL3CeQTfO+ZGxuO+Iw==
"@humanwhocodes/config-array@^0.13.0":
version "0.13.0"
@@ -741,12 +741,12 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
-"@modelcontextprotocol/sdk@^1.25.2":
- version "1.25.2"
- resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz#2284560b4e044b4ce5f328ee180931110cb8c5cf"
- integrity sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==
+"@modelcontextprotocol/sdk@^1.26.0":
+ version "1.27.1"
+ resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz#a602cf823bf8a68e13e7112f50aeb02b09fb83b9"
+ integrity sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==
dependencies:
- "@hono/node-server" "^1.19.7"
+ "@hono/node-server" "^1.19.9"
ajv "^8.17.1"
ajv-formats "^3.0.1"
content-type "^1.0.5"
@@ -754,14 +754,15 @@
cross-spawn "^7.0.5"
eventsource "^3.0.2"
eventsource-parser "^3.0.0"
- express "^5.0.1"
- express-rate-limit "^7.5.0"
- jose "^6.1.1"
+ express "^5.2.1"
+ express-rate-limit "^8.2.1"
+ hono "^4.11.4"
+ jose "^6.1.3"
json-schema-typed "^8.0.2"
pkce-challenge "^5.0.0"
raw-body "^3.0.0"
zod "^3.25 || ^4.0"
- zod-to-json-schema "^3.25.0"
+ zod-to-json-schema "^3.25.1"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@@ -784,6 +785,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@pinojs/redact@^0.4.0":
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/@pinojs/redact/-/redact-0.4.0.tgz#c3de060dd12640dcc838516aa2a6803cc7b2e9d6"
+ integrity sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==
+
"@pkgr/core@^0.2.9":
version "0.2.9"
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b"
@@ -808,6 +814,11 @@
dependencies:
"@sinonjs/commons" "^3.0.0"
+"@stablelib/base64@^1.0.0":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@stablelib/base64/-/base64-1.0.1.tgz#bdfc1c6d3a62d7a3b7bbc65b6cce1bb4561641be"
+ integrity sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==
+
"@ts-morph/common@~0.20.0":
version "0.20.0"
resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.20.0.tgz#3f161996b085ba4519731e4d24c35f6cba5b80af"
@@ -886,6 +897,11 @@
dependencies:
"@types/node" "*"
+"@types/cookie-parser@^1.4.10":
+ version "1.4.10"
+ resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.10.tgz#a045272a383a30597a01955d4f9c790018f214e4"
+ integrity sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==
+
"@types/cors@^2.8.19":
version "2.8.19"
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.19.tgz#d93ea2673fd8c9f697367f5eeefc2bbfa94f0342"
@@ -1219,6 +1235,11 @@ argparse@^2.0.1:
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+atomic-sleep@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
+ integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==
+
babel-jest@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5"
@@ -1474,6 +1495,11 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+colorette@^2.0.7:
+ version "2.0.20"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
+ integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
+
commander@^13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46"
@@ -1499,12 +1525,25 @@ convert-source-map@^2.0.0:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
+cookie-parser@^1.4.6:
+ version "1.4.7"
+ resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.7.tgz#e2125635dfd766888ffe90d60c286404fa0e7b26"
+ integrity sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==
+ dependencies:
+ cookie "0.7.2"
+ cookie-signature "1.0.6"
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
cookie-signature@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793"
integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
-cookie@^0.7.1:
+cookie@0.7.2, cookie@^0.7.1:
version "0.7.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
@@ -1544,6 +1583,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.5:
shebang-command "^2.0.0"
which "^2.0.1"
+dateformat@^4.6.3:
+ version "4.6.3"
+ resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5"
+ integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==
+
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0, debug@^4.4.3:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
@@ -1627,6 +1671,13 @@ encodeurl@^2.0.0:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
+end-of-stream@^1.1.0:
+ version "1.4.5"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c"
+ integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==
+ dependencies:
+ once "^1.4.0"
+
error-ex@^1.3.1:
version "1.3.4"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414"
@@ -1839,12 +1890,14 @@ expect@^29.0.0, expect@^29.7.0:
jest-message-util "^29.7.0"
jest-util "^29.7.0"
-express-rate-limit@^7.5.0:
- version "7.5.1"
- resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.1.tgz#8c3a42f69209a3a1c969890070ece9e20a879dec"
- integrity sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==
+express-rate-limit@^8.2.1:
+ version "8.2.1"
+ resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-8.2.1.tgz#ec75fdfe280ecddd762b8da8784c61bae47d7f7f"
+ integrity sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==
+ dependencies:
+ ip-address "10.0.1"
-express@^5.0.1, express@^5.1.0:
+express@^5.1.0, express@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/express/-/express-5.2.1.tgz#8f21d15b6d327f92b4794ecf8cb08a72f956ac04"
integrity sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==
@@ -1887,6 +1940,11 @@ external-editor@^3.1.0:
iconv-lite "^0.4.24"
tmp "^0.0.33"
+fast-copy@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-4.0.2.tgz#57f14115e1edbec274f69090072a480aa29cbedd"
+ integrity sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==
+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -1918,6 +1976,16 @@ fast-levenshtein@^2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+fast-safe-stringify@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
+ integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
+
+fast-sha256@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/fast-sha256/-/fast-sha256-1.3.0.tgz#7916ba2054eeb255982608cccd0f6660c79b7ae6"
+ integrity sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==
+
fast-uri@^3.0.1:
version "3.1.0"
resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.0.tgz#66eecff6c764c0df9b762e62ca7edcfb53b4edfa"
@@ -2180,6 +2248,16 @@ hasown@^2.0.2:
dependencies:
function-bind "^1.1.2"
+help-me@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6"
+ integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==
+
+hono@^4.11.4:
+ version "4.12.4"
+ resolved "https://registry.yarnpkg.com/hono/-/hono-4.12.4.tgz#fcfb5a064b90d5203dd41231e0d5a67262fc1729"
+ integrity sha512-ooiZW1Xy8rQ4oELQ++otI2T9DsKpV0M6c6cO6JGx4RTfav9poFFLlet9UMXHZnoM1yG0HWGlQLswBGX3RZmHtg==
+
html-escaper@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
@@ -2264,6 +2342,11 @@ inherits@2, inherits@^2.0.3, inherits@~2.0.4:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+ip-address@10.0.1:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.0.1.tgz#a8180b783ce7788777d796286d61bce4276818ed"
+ integrity sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==
+
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
@@ -2739,11 +2822,16 @@ jest@^29.4.0:
import-local "^3.0.2"
jest-cli "^29.7.0"
-jose@^6.1.1:
+jose@^6.1.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/jose/-/jose-6.1.3.tgz#8453d7be88af7bb7d64a0481d6a35a0145ba3ea5"
integrity sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==
+joycon@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03"
+ integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==
+
"jq-web@https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz":
version "0.8.8"
resolved "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz#7849ef64bdfc28f70cbfc9888f886860e96da10d"
@@ -2847,6 +2935,11 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+"lithic@file:../../dist":
+ version "0.130.0"
+ dependencies:
+ standardwebhooks "^1.0.0"
+
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@@ -3040,6 +3133,11 @@ object-inspect@^1.13.3:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213"
integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==
+on-exit-leak-free@^2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8"
+ integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==
+
on-finished@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
@@ -3047,7 +3145,7 @@ on-finished@^2.4.1:
dependencies:
ee-first "1.1.1"
-once@^1.3.0, once@^1.4.0:
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
@@ -3187,6 +3285,64 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+pino-abstract-transport@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz#b21e5f33a297e8c4c915c62b3ce5dd4a87a52c23"
+ integrity sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==
+ dependencies:
+ split2 "^4.0.0"
+
+pino-http@^11.0.0:
+ version "11.0.0"
+ resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-11.0.0.tgz#ebadef4694fc59aadab9be7e5939aea625b4615f"
+ integrity sha512-wqg5XIAGRRIWtTk8qPGxkbrfiwEWz1lgedVLvhLALudKXvg1/L2lTFgTGPJ4Z2e3qcRmxoFxDuSdMdMGNM6I1g==
+ dependencies:
+ get-caller-file "^2.0.5"
+ pino "^10.0.0"
+ pino-std-serializers "^7.0.0"
+ process-warning "^5.0.0"
+
+pino-pretty@^13.1.3:
+ version "13.1.3"
+ resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-13.1.3.tgz#2274cccda925dd355c104079a5029f6598d0381b"
+ integrity sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==
+ dependencies:
+ colorette "^2.0.7"
+ dateformat "^4.6.3"
+ fast-copy "^4.0.0"
+ fast-safe-stringify "^2.1.1"
+ help-me "^5.0.0"
+ joycon "^3.1.1"
+ minimist "^1.2.6"
+ on-exit-leak-free "^2.1.0"
+ pino-abstract-transport "^3.0.0"
+ pump "^3.0.0"
+ secure-json-parse "^4.0.0"
+ sonic-boom "^4.0.1"
+ strip-json-comments "^5.0.2"
+
+pino-std-serializers@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz#a7b0cd65225f29e92540e7853bd73b07479893fc"
+ integrity sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==
+
+pino@^10.0.0, pino@^10.3.1:
+ version "10.3.1"
+ resolved "https://registry.yarnpkg.com/pino/-/pino-10.3.1.tgz#6552c8f8d8481844c9e452e7bf0be90bff1939ce"
+ integrity sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==
+ dependencies:
+ "@pinojs/redact" "^0.4.0"
+ atomic-sleep "^1.0.0"
+ on-exit-leak-free "^2.1.0"
+ pino-abstract-transport "^3.0.0"
+ pino-std-serializers "^7.0.0"
+ process-warning "^5.0.0"
+ quick-format-unescaped "^4.0.3"
+ real-require "^0.2.0"
+ safe-stable-stringify "^2.3.1"
+ sonic-boom "^4.0.1"
+ thread-stream "^4.0.0"
+
pirates@^4.0.4:
version "4.0.7"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22"
@@ -3235,6 +3391,11 @@ pretty-format@^29.0.0, pretty-format@^29.7.0:
ansi-styles "^5.0.0"
react-is "^18.0.0"
+process-warning@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7"
+ integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==
+
prompts@^2.0.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
@@ -3251,6 +3412,14 @@ proxy-addr@^2.0.7:
forwarded "0.2.0"
ipaddr.js "1.9.1"
+pump@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.4.tgz#1f313430527fa8b905622ebd22fe1444e757ab3c"
+ integrity sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
punycode@^2.1.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
@@ -3273,6 +3442,11 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+quick-format-unescaped@^4.0.3:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7"
+ integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
+
range-parser@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
@@ -3302,6 +3476,11 @@ readable-stream@^3.4.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
+real-require@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78"
+ integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==
+
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
@@ -3378,11 +3557,21 @@ safe-buffer@~5.2.0:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+safe-stable-stringify@^2.3.1:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd"
+ integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==
+
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+secure-json-parse@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-4.1.0.tgz#4f1ab41c67a13497ea1b9131bb4183a22865477c"
+ integrity sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==
+
semver@^6.3.0, semver@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
@@ -3497,6 +3686,13 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+sonic-boom@^4.0.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.1.tgz#28598250df4899c0ac572d7e2f0460690ba6a030"
+ integrity sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==
+ dependencies:
+ atomic-sleep "^1.0.0"
+
source-map-support@0.5.13:
version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
@@ -3510,6 +3706,11 @@ source-map@^0.6.0, source-map@^0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+split2@^4.0.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
+ integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
+
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
@@ -3522,6 +3723,14 @@ stack-utils@^2.0.3:
dependencies:
escape-string-regexp "^2.0.0"
+standardwebhooks@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/standardwebhooks/-/standardwebhooks-1.0.0.tgz#5faa23ceacbf9accd344361101d9e3033b64324f"
+ integrity sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==
+ dependencies:
+ "@stablelib/base64" "^1.0.0"
+ fast-sha256 "^1.3.0"
+
statuses@^2.0.1, statuses@^2.0.2, statuses@~2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382"
@@ -3585,6 +3794,11 @@ strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+strip-json-comments@^5.0.2:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz#b7304249dd402ee67fd518ada993ab3593458bcf"
+ integrity sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==
+
superstruct@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca"
@@ -3630,6 +3844,13 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+thread-stream@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-4.0.0.tgz#732f007c24da7084f729d6e3a7e3f5934a7380b7"
+ integrity sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==
+ dependencies:
+ real-require "^0.2.0"
+
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -3933,7 +4154,7 @@ yoctocolors-cjs@^2.1.2:
resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa"
integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==
-zod-to-json-schema@^3.24.5, zod-to-json-schema@^3.24.6, zod-to-json-schema@^3.25.0:
+zod-to-json-schema@^3.24.5, zod-to-json-schema@^3.24.6, zod-to-json-schema@^3.25.1:
version "3.25.1"
resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz#7f24962101a439ddade2bf1aeab3c3bfec7d84ba"
integrity sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==
diff --git a/tests/api-resources/webhooks.test.ts b/tests/api-resources/webhooks.test.ts
index 173c5bd1..728450b3 100644
--- a/tests/api-resources/webhooks.test.ts
+++ b/tests/api-resources/webhooks.test.ts
@@ -237,20 +237,27 @@ describe('resource webhooks', () => {
});
describe('parse', () => {
- it('should unwrap and validate typed webhook event', () => {
- const secret = 'whsec_c2VjcmV0Cg==';
- const payload =
- '{"event_type":"account_holder.created","token":"00000000-0000-0000-0000-000000000001","account_token":"00000000-0000-0000-0000-000000000001","created":"2019-12-27T18:11:19.117Z","required_documents":[{"entity_token":"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e","status_reasons":["string"],"valid_documents":["string"]}],"status":"ACCEPTED","status_reason":["string"]}';
+ const secret = 'whsec_c2VjcmV0Cg==';
+ const payload =
+ '{"event_type":"account_holder.created","token":"00000000-0000-0000-0000-000000000001","account_token":"00000000-0000-0000-0000-000000000001","created":"2019-12-27T18:11:19.117Z","required_documents":[{"entity_token":"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e","status_reasons":["string"],"valid_documents":["string"]}],"status":"ACCEPTED","status_reason":["string"]}';
+
+ function makeHeaders() {
const msgID = '1';
const timestamp = new Date();
const wh = new Webhook(secret);
const signature = wh.sign(msgID, timestamp, payload);
- const headers: Record = {
- 'webhook-signature': signature,
- 'webhook-id': msgID,
- 'webhook-timestamp': String(Math.floor(timestamp.getTime() / 1000)),
+ return {
+ wh,
+ headers: {
+ 'webhook-signature': signature,
+ 'webhook-id': msgID,
+ 'webhook-timestamp': String(Math.floor(timestamp.getTime() / 1000)),
+ } as Record,
};
+ }
+ it('should unwrap and validate typed webhook event', () => {
+ const { headers } = makeHeaders();
const event = lithic.webhooks.parse(payload, { headers, secret });
expect(event).toBeDefined();
if ('event_type' in event) {
@@ -258,24 +265,44 @@ describe('resource webhooks', () => {
}
});
- it('should throw for wrong secret', () => {
- const secret = 'whsec_c2VjcmV0Cg==';
- const payload =
- '{"event_type":"account_holder.created","token":"00000000-0000-0000-0000-000000000001","account_token":"00000000-0000-0000-0000-000000000001","created":"2019-12-27T18:11:19.117Z","required_documents":[{"entity_token":"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e","status_reasons":["string"],"valid_documents":["string"]}],"status":"ACCEPTED","status_reason":["string"]}';
- const msgID = '1';
- const timestamp = new Date();
- const wh = new Webhook(secret);
- const signature = wh.sign(msgID, timestamp, payload);
- const headers: Record = {
- 'webhook-signature': signature,
- 'webhook-id': msgID,
- 'webhook-timestamp': String(Math.floor(timestamp.getTime() / 1000)),
- };
+ it('should work with withOptions webhookSecret', () => {
+ const { headers } = makeHeaders();
- expect(() => {
- const wrongSecret = 'whsec_' + Buffer.from('wrong_secret').toString('base64');
- lithic.webhooks.parse(payload, { headers, secret: wrongSecret });
- }).toThrow('No matching signature found');
+ // secret via withOptions
+ lithic.withOptions({ webhookSecret: secret }).webhooks.parse(payload, { headers });
+
+ // per-call secret overrides withOptions
+ lithic
+ .withOptions({ webhookSecret: 'whsec_aaaaaaaaaa==' })
+ .webhooks.parse(payload, { headers, secret });
+ });
+
+ it.each([
+ {
+ name: 'wrong secret',
+ tweakHeaders: (h: Record) => h,
+ overrideSecret: 'whsec_' + Buffer.from('wrong_secret').toString('base64'),
+ error: 'No matching signature found',
+ },
+ {
+ name: 'bad signature from different payload',
+ tweakHeaders: (h: Record, wh: Webhook) => ({
+ ...h,
+ 'webhook-signature': wh.sign('1', new Date(), 'some other payload'),
+ }),
+ error: 'No matching signature found',
+ },
+ {
+ name: 'wrong message ID',
+ tweakHeaders: (h: Record) => ({ ...h, 'webhook-id': 'wrong' }),
+ error: 'No matching signature found',
+ },
+ ])('should throw for $name', ({ tweakHeaders, overrideSecret, error }) => {
+ const { wh, headers } = makeHeaders();
+ const tweaked = tweakHeaders(headers, wh);
+ expect(() =>
+ lithic.webhooks.parse(payload, { headers: tweaked, secret: overrideSecret ?? secret }),
+ ).toThrow(error);
});
});
From 9b372c842a010857cbe352d74f3e1987e498b032 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 3 Mar 2026 22:11:55 +0000
Subject: [PATCH 5/8] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 3301005b..4f6a4f90 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 185
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-45bd51c1d7885bde620179da56671e3378571e301528c60975604c4fbaa2c800.yml
-openapi_spec_hash: e1355583b829f269875b6f800078a9e0
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-ee8607f0a2cdcaee420935050334a439db8dd097be83023fccdaf1d6f9a7de14.yml
+openapi_spec_hash: 0f21c68cdddb7c5bd99f42356d507393
config_hash: fb5070d41fcabdedbc084b83964b592a
From 056f3b627d14cc8bbaf469da0f9dd00365a24fb0 Mon Sep 17 00:00:00 2001
From: Marek Sychra
Date: Wed, 4 Mar 2026 08:07:04 -0500
Subject: [PATCH 6/8] Fix transaction amount in example
---
examples/transactions.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/transactions.ts b/examples/transactions.ts
index daded2f8..a93041a2 100755
--- a/examples/transactions.ts
+++ b/examples/transactions.ts
@@ -22,7 +22,7 @@ async function simulateAuthDeclined(card: Lithic.Cards.Card) {
const authResponse = await client.transactions.simulateAuthorization({
pan: card.pan!,
- amount: 999999999999,
+ amount: 2000000000,
descriptor: 'coffee shop',
});
From e159665256ba15bebdb4c4ddd7c27b57ce28e143 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 5 Mar 2026 13:05:19 +0000
Subject: [PATCH 7/8] chore(internal): codegen related update
---
packages/mcp-server/src/code-tool.ts | 2 +-
scripts/mock | 13 ++++++++++++-
src/client.ts | 6 +++---
3 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts
index 0d52a8a7..fe4376e8 100644
--- a/packages/mcp-server/src/code-tool.ts
+++ b/packages/mcp-server/src/code-tool.ts
@@ -155,7 +155,7 @@ const remoteStainlessHandler = async ({
headers: {
...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }),
'Content-Type': 'application/json',
- client_envs: JSON.stringify({
+ 'x-stainless-mcp-client-envs': JSON.stringify({
LITHIC_API_KEY: requireValue(
readEnv('LITHIC_API_KEY') ?? client.apiKey,
'set LITHIC_API_KEY environment variable or provide apiKey client option',
diff --git a/scripts/mock b/scripts/mock
index 0b28f6ea..bcf3b392 100755
--- a/scripts/mock
+++ b/scripts/mock
@@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}"
# Run prism mock on the given spec
if [ "$1" == "--daemon" ]; then
+ # Pre-install the package so the download doesn't eat into the startup timeout
+ npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version
+
npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log &
- # Wait for server to come online
+ # Wait for server to come online (max 30s)
echo -n "Waiting for server"
+ attempts=0
while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do
+ attempts=$((attempts + 1))
+ if [ "$attempts" -ge 300 ]; then
+ echo
+ echo "Timed out waiting for Prism server to start"
+ cat .prism.log
+ exit 1
+ fi
echo -n "."
sleep 0.1
done
diff --git a/src/client.ts b/src/client.ts
index 85f24559..c49a950f 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -959,9 +959,9 @@ export class Lithic {
}
}
- // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
- // just do what it says, but otherwise calculate a default
- if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
+ // If the API asks us to wait a certain amount of time, just do what it
+ // says, but otherwise calculate a default
+ if (timeoutMillis === undefined) {
const maxRetries = options.maxRetries ?? this.maxRetries;
timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
}
From 456146c20974d1e2499930dacbec20c4e7bee551 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 5 Mar 2026 13:05:46 +0000
Subject: [PATCH 8/8] release: 0.131.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 16 ++++++++++++++++
package.json | 2 +-
packages/mcp-server/manifest.json | 2 +-
packages/mcp-server/package.json | 2 +-
packages/mcp-server/src/server.ts | 2 +-
src/version.ts | 2 +-
7 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 90ea33ab..e074c76b 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.130.0"
+ ".": "0.131.0"
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 29d68c04..d2251d06 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Changelog
+## 0.131.0 (2026-03-05)
+
+Full Changelog: [v0.130.0...v0.131.0](https://github.com/lithic-com/lithic-node/compare/v0.130.0...v0.131.0)
+
+### Features
+
+* **api:** add action_counts to rule performance reports and code to authorization actions ([b721196](https://github.com/lithic-com/lithic-node/commit/b7211961ba92cc5cd68ad633592b5428060e8478))
+* **api:** Add Hold API for financial account fund reservations ([582aeb7](https://github.com/lithic-com/lithic-node/commit/582aeb7164a9e9523becb601a08e7393904cd4e5))
+* **api:** Remove deprecated beneficial owner entities field ([e0b8292](https://github.com/lithic-com/lithic-node/commit/e0b8292748ddb37a3758a909c5e7314c511985e4))
+
+
+### Chores
+
+* **internal:** codegen related update ([e159665](https://github.com/lithic-com/lithic-node/commit/e159665256ba15bebdb4c4ddd7c27b57ce28e143))
+* **internal:** codegen related update ([bccb03c](https://github.com/lithic-com/lithic-node/commit/bccb03cc6e6d046aa76dac2b77237233d1a614a7))
+
## 0.130.0 (2026-02-27)
Full Changelog: [v0.129.0...v0.130.0](https://github.com/lithic-com/lithic-node/compare/v0.129.0...v0.130.0)
diff --git a/package.json b/package.json
index a3cc6c7d..07f2a8e9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "lithic",
- "version": "0.130.0",
+ "version": "0.131.0",
"description": "The official TypeScript library for the Lithic API",
"author": "Lithic ",
"types": "dist/index.d.ts",
diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json
index bf005118..334377e5 100644
--- a/packages/mcp-server/manifest.json
+++ b/packages/mcp-server/manifest.json
@@ -1,7 +1,7 @@
{
"dxt_version": "0.2",
"name": "lithic-mcp",
- "version": "0.130.0",
+ "version": "0.131.0",
"description": "The official MCP Server for the Lithic API",
"author": {
"name": "Lithic",
diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json
index 2571b33c..5d4a8b47 100644
--- a/packages/mcp-server/package.json
+++ b/packages/mcp-server/package.json
@@ -1,6 +1,6 @@
{
"name": "lithic-mcp",
- "version": "0.130.0",
+ "version": "0.131.0",
"description": "The official MCP Server for the Lithic API",
"author": "Lithic ",
"types": "dist/index.d.ts",
diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts
index 8768a039..44a5f7ea 100644
--- a/packages/mcp-server/src/server.ts
+++ b/packages/mcp-server/src/server.ts
@@ -21,7 +21,7 @@ export const newMcpServer = async (stainlessApiKey: string | undefined) =>
new McpServer(
{
name: 'lithic_api',
- version: '0.130.0',
+ version: '0.131.0',
},
{
instructions: await getInstructions(stainlessApiKey),
diff --git a/src/version.ts b/src/version.ts
index bfde34bc..63a530b5 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const VERSION = '0.130.0'; // x-release-please-version
+export const VERSION = '0.131.0'; // x-release-please-version