@adcp/sdk 17.0.0-beta.0 → 17.0.0-beta.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/lib/adapters/version/3.1/bidding.js +1 -1
- package/dist/lib/adapters/version/3.1/bidding.mjs +1 -1
- package/dist/lib/core/ResponseValidator.js +1 -1
- package/dist/lib/core/ResponseValidator.mjs +1 -1
- package/dist/lib/core/SingleAgentClient.d.mts +7 -5
- package/dist/lib/core/SingleAgentClient.d.ts +7 -5
- package/dist/lib/core/SingleAgentClient.js +57 -32
- package/dist/lib/core/SingleAgentClient.mjs +59 -33
- package/dist/lib/core/TaskExecutor.js +5 -3
- package/dist/lib/core/TaskExecutor.mjs +5 -3
- package/dist/lib/errors/index.d.mts +22 -0
- package/dist/lib/errors/index.d.ts +22 -0
- package/dist/lib/errors/index.js +43 -0
- package/dist/lib/errors/index.mjs +42 -0
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/protocols/mcp-modern.d.mts +2 -0
- package/dist/lib/protocols/mcp-modern.d.ts +2 -0
- package/dist/lib/protocols/mcp-modern.js +31 -5
- package/dist/lib/protocols/mcp-modern.mjs +31 -5
- package/dist/lib/protocols/mcp-scope.d.mts +3 -1
- package/dist/lib/protocols/mcp-scope.d.ts +3 -1
- package/dist/lib/protocols/mcp-scope.js +19 -2
- package/dist/lib/protocols/mcp-scope.mjs +18 -2
- package/dist/lib/protocols/mcp.js +12 -6
- package/dist/lib/protocols/mcp.mjs +13 -6
- package/dist/lib/testing/client.d.mts +1 -0
- package/dist/lib/testing/client.d.ts +1 -0
- package/dist/lib/testing/client.js +6 -5
- package/dist/lib/testing/client.mjs +6 -5
- package/dist/lib/testing/storyboard/agent-routing.d.mts +5 -2
- package/dist/lib/testing/storyboard/agent-routing.d.ts +5 -2
- package/dist/lib/testing/storyboard/agent-routing.js +11 -4
- package/dist/lib/testing/storyboard/agent-routing.mjs +11 -4
- package/dist/lib/testing/storyboard/context.d.mts +13 -3
- package/dist/lib/testing/storyboard/context.d.ts +13 -3
- package/dist/lib/testing/storyboard/context.js +15 -10
- package/dist/lib/testing/storyboard/context.mjs +15 -10
- package/dist/lib/testing/storyboard/runner.js +141 -13
- package/dist/lib/testing/storyboard/runner.mjs +141 -13
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +4 -1
- package/dist/lib/testing/storyboard/validations.mjs +4 -1
- package/dist/lib/testing/test-controller.js +3 -0
- package/dist/lib/testing/test-controller.mjs +3 -0
- package/dist/lib/utils/envelope-status-compat.d.mts +18 -1
- package/dist/lib/utils/envelope-status-compat.d.ts +18 -1
- package/dist/lib/utils/envelope-status-compat.js +11 -5
- package/dist/lib/utils/envelope-status-compat.mjs +11 -5
- package/dist/lib/utils/response-unwrapper.js +12 -9
- package/dist/lib/utils/response-unwrapper.mjs +12 -9
- package/dist/lib/v2/projection/creative-delivery.js +56 -11
- package/dist/lib/v2/projection/creative-delivery.mjs +56 -11
- package/dist/lib/validation/schema-validator.js +1 -1
- package/dist/lib/validation/schema-validator.mjs +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +11 -0
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +12 -1
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-16-to-17.md +24 -1
- package/docs/migration-reporting-storage-package.md +1 -1
- package/package.json +1 -1
package/dist/lib/errors/index.js
CHANGED
|
@@ -28,6 +28,7 @@ __export(errors_exports, {
|
|
|
28
28
|
AccountSetupRequiredError: () => AccountSetupRequiredError,
|
|
29
29
|
ActionNotAllowedError: () => ActionNotAllowedError,
|
|
30
30
|
AgentNotFoundError: () => AgentNotFoundError,
|
|
31
|
+
AgentRateLimitedError: () => AgentRateLimitedError,
|
|
31
32
|
AuthenticationCredentialsRejectedError: () => AuthenticationCredentialsRejectedError,
|
|
32
33
|
AuthenticationRequiredError: () => AuthenticationRequiredError,
|
|
33
34
|
BuyerSetupError: () => BuyerSetupError,
|
|
@@ -474,6 +475,47 @@ class ResponseTooLargeError extends ADCPError {
|
|
|
474
475
|
contentLengthHeader;
|
|
475
476
|
code = "RESPONSE_TOO_LARGE";
|
|
476
477
|
}
|
|
478
|
+
class AgentRateLimitedError extends ADCPError {
|
|
479
|
+
constructor(agentUrl, status, retryAfter, cause) {
|
|
480
|
+
const safeAgentUrl = sanitizeAgentUrlForError(agentUrl);
|
|
481
|
+
const retryAfterMs = parseRetryAfterMs(retryAfter);
|
|
482
|
+
const validRetryAfter = retryAfterMs === void 0 ? void 0 : retryAfter?.trim();
|
|
483
|
+
const retryHint = retryAfterMs === void 0 ? "No usable Retry-After header; back off before retrying." : `Retry-After: ${validRetryAfter} (${Math.ceil(retryAfterMs / 1e3)}s).`;
|
|
484
|
+
super(
|
|
485
|
+
`Agent rate limited MCP endpoint discovery: HTTP ${status} from ${safeAgentUrl}. ${retryHint} Discovery stopped at this probe to avoid spending more of the agent's request budget; this does not indicate a wrong agent_uri.`
|
|
486
|
+
);
|
|
487
|
+
this.status = status;
|
|
488
|
+
this.agentUrl = safeAgentUrl;
|
|
489
|
+
if (retryAfterMs !== void 0) {
|
|
490
|
+
this.retryAfter = validRetryAfter;
|
|
491
|
+
this.retryAfterMs = retryAfterMs;
|
|
492
|
+
}
|
|
493
|
+
this.details = {
|
|
494
|
+
agentUrl: safeAgentUrl,
|
|
495
|
+
status,
|
|
496
|
+
...retryAfterMs !== void 0 && { retryAfter: validRetryAfter, retryAfterMs }
|
|
497
|
+
};
|
|
498
|
+
if (cause !== void 0) {
|
|
499
|
+
Object.defineProperty(this, "cause", { value: cause, enumerable: false, configurable: true });
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
status;
|
|
503
|
+
code = "RATE_LIMITED";
|
|
504
|
+
/** The probed URL, without credentials, query or fragment. */
|
|
505
|
+
agentUrl;
|
|
506
|
+
/** `Retry-After` as the agent sent it. Set only when it is valid delta-seconds or an HTTP-date. */
|
|
507
|
+
retryAfter;
|
|
508
|
+
/** Delay from `Retry-After`, in milliseconds. */
|
|
509
|
+
retryAfterMs;
|
|
510
|
+
}
|
|
511
|
+
function parseRetryAfterMs(value) {
|
|
512
|
+
const trimmed = value?.trim();
|
|
513
|
+
if (!trimmed) return void 0;
|
|
514
|
+
if (/^\d{1,10}$/.test(trimmed)) return Number(trimmed) * 1e3;
|
|
515
|
+
if (!/^[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(trimmed)) return void 0;
|
|
516
|
+
const date = Date.parse(trimmed);
|
|
517
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
518
|
+
}
|
|
477
519
|
class ActionNotAllowedError extends ADCPError {
|
|
478
520
|
code = "ACTION_NOT_ALLOWED";
|
|
479
521
|
attemptedAction;
|
|
@@ -677,6 +719,7 @@ class PreparedFixturesDeniedError extends ADCPError {
|
|
|
677
719
|
AccountSetupRequiredError,
|
|
678
720
|
ActionNotAllowedError,
|
|
679
721
|
AgentNotFoundError,
|
|
722
|
+
AgentRateLimitedError,
|
|
680
723
|
AuthenticationCredentialsRejectedError,
|
|
681
724
|
AuthenticationRequiredError,
|
|
682
725
|
BuyerSetupError,
|
|
@@ -413,6 +413,47 @@ class ResponseTooLargeError extends ADCPError {
|
|
|
413
413
|
contentLengthHeader;
|
|
414
414
|
code = "RESPONSE_TOO_LARGE";
|
|
415
415
|
}
|
|
416
|
+
class AgentRateLimitedError extends ADCPError {
|
|
417
|
+
constructor(agentUrl, status, retryAfter, cause) {
|
|
418
|
+
const safeAgentUrl = sanitizeAgentUrlForError(agentUrl);
|
|
419
|
+
const retryAfterMs = parseRetryAfterMs(retryAfter);
|
|
420
|
+
const validRetryAfter = retryAfterMs === void 0 ? void 0 : retryAfter?.trim();
|
|
421
|
+
const retryHint = retryAfterMs === void 0 ? "No usable Retry-After header; back off before retrying." : `Retry-After: ${validRetryAfter} (${Math.ceil(retryAfterMs / 1e3)}s).`;
|
|
422
|
+
super(
|
|
423
|
+
`Agent rate limited MCP endpoint discovery: HTTP ${status} from ${safeAgentUrl}. ${retryHint} Discovery stopped at this probe to avoid spending more of the agent's request budget; this does not indicate a wrong agent_uri.`
|
|
424
|
+
);
|
|
425
|
+
this.status = status;
|
|
426
|
+
this.agentUrl = safeAgentUrl;
|
|
427
|
+
if (retryAfterMs !== void 0) {
|
|
428
|
+
this.retryAfter = validRetryAfter;
|
|
429
|
+
this.retryAfterMs = retryAfterMs;
|
|
430
|
+
}
|
|
431
|
+
this.details = {
|
|
432
|
+
agentUrl: safeAgentUrl,
|
|
433
|
+
status,
|
|
434
|
+
...retryAfterMs !== void 0 && { retryAfter: validRetryAfter, retryAfterMs }
|
|
435
|
+
};
|
|
436
|
+
if (cause !== void 0) {
|
|
437
|
+
Object.defineProperty(this, "cause", { value: cause, enumerable: false, configurable: true });
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
status;
|
|
441
|
+
code = "RATE_LIMITED";
|
|
442
|
+
/** The probed URL, without credentials, query or fragment. */
|
|
443
|
+
agentUrl;
|
|
444
|
+
/** `Retry-After` as the agent sent it. Set only when it is valid delta-seconds or an HTTP-date. */
|
|
445
|
+
retryAfter;
|
|
446
|
+
/** Delay from `Retry-After`, in milliseconds. */
|
|
447
|
+
retryAfterMs;
|
|
448
|
+
}
|
|
449
|
+
function parseRetryAfterMs(value) {
|
|
450
|
+
const trimmed = value?.trim();
|
|
451
|
+
if (!trimmed) return void 0;
|
|
452
|
+
if (/^\d{1,10}$/.test(trimmed)) return Number(trimmed) * 1e3;
|
|
453
|
+
if (!/^[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(trimmed)) return void 0;
|
|
454
|
+
const date = Date.parse(trimmed);
|
|
455
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
456
|
+
}
|
|
416
457
|
class ActionNotAllowedError extends ADCPError {
|
|
417
458
|
code = "ACTION_NOT_ALLOWED";
|
|
418
459
|
attemptedAction;
|
|
@@ -615,6 +656,7 @@ export {
|
|
|
615
656
|
AccountSetupRequiredError,
|
|
616
657
|
ActionNotAllowedError,
|
|
617
658
|
AgentNotFoundError,
|
|
659
|
+
AgentRateLimitedError,
|
|
618
660
|
AuthenticationCredentialsRejectedError,
|
|
619
661
|
AuthenticationRequiredError,
|
|
620
662
|
BuyerSetupError,
|
package/dist/lib/index.d.mts
CHANGED
|
@@ -57,7 +57,7 @@ export * from './handlers/types.mjs';
|
|
|
57
57
|
export type { Storage, AtomicTakeStorage, DeferredTaskStorage, BatchStorage, PatternStorage, AgentCapabilities, ConversationState, DeferredTaskState, StorageConfig, StorageFactory, StorageMiddleware, } from './storage/interfaces.mjs';
|
|
58
58
|
export { MemoryStorage, createMemoryStorage, createMemoryStorageConfig } from './storage/MemoryStorage.mjs';
|
|
59
59
|
export { ADCPError, TaskTimeoutError, MaxClarificationError, DeferredTaskError, TaskAbortedError, AgentNotFoundError, UnsupportedTaskError, ProtocolError, ValidationError as ADCPValidationError, // Rename to avoid conflict
|
|
60
|
-
MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors/index.mjs';
|
|
60
|
+
MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, AgentRateLimitedError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors/index.mjs';
|
|
61
61
|
export type { OAuthMetadataInfo, ClientPreflightAdcpErrorInfo, ClientPreflightAdcpErrorRecovery, FeatureUnsupportedErrorOptions, ProtocolFeatureUnsupportedErrorOptions, ActionNotAllowedErrorDetails, ActionNotAllowedReasonValue, ActionNotAllowedAttemptedAction, ActionNotAllowedAvailableAction, ActionNotAllowedRecovery, } from './errors/index.mjs';
|
|
62
62
|
export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy/index.mjs';
|
|
63
63
|
export { ACTIONS_BY_FIELD, LEGACY_COARSE_ACTIONS, STRUCTURED_ONLY_MEDIA_BUY_ACTIONS, UPDATE_FIELDS_BY_ACTION, applyTargetingInput, hasTargetingClears, resolveTargetingInput, canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, findAvailableAction, getActionForMutation, getAvailableActions, getRollupParent, ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, preflightUpdateMediaBuy, recoveryForModeMismatch, validateProductsAgainstPropertyPolicy, } from './media-buy/index.mjs';
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export * from './handlers/types';
|
|
|
57
57
|
export type { Storage, AtomicTakeStorage, DeferredTaskStorage, BatchStorage, PatternStorage, AgentCapabilities, ConversationState, DeferredTaskState, StorageConfig, StorageFactory, StorageMiddleware, } from './storage/interfaces';
|
|
58
58
|
export { MemoryStorage, createMemoryStorage, createMemoryStorageConfig } from './storage/MemoryStorage';
|
|
59
59
|
export { ADCPError, TaskTimeoutError, MaxClarificationError, DeferredTaskError, TaskAbortedError, AgentNotFoundError, UnsupportedTaskError, ProtocolError, ValidationError as ADCPValidationError, // Rename to avoid conflict
|
|
60
|
-
MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors';
|
|
60
|
+
MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, AgentRateLimitedError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors';
|
|
61
61
|
export type { OAuthMetadataInfo, ClientPreflightAdcpErrorInfo, ClientPreflightAdcpErrorRecovery, FeatureUnsupportedErrorOptions, ProtocolFeatureUnsupportedErrorOptions, ActionNotAllowedErrorDetails, ActionNotAllowedReasonValue, ActionNotAllowedAttemptedAction, ActionNotAllowedAvailableAction, ActionNotAllowedRecovery, } from './errors';
|
|
62
62
|
export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy';
|
|
63
63
|
export { ACTIONS_BY_FIELD, LEGACY_COARSE_ACTIONS, STRUCTURED_ONLY_MEDIA_BUY_ACTIONS, UPDATE_FIELDS_BY_ACTION, applyTargetingInput, hasTargetingClears, resolveTargetingInput, canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, findAvailableAction, getActionForMutation, getAvailableActions, getRollupParent, ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, preflightUpdateMediaBuy, recoveryForModeMismatch, validateProductsAgainstPropertyPolicy, } from './media-buy';
|
package/dist/lib/index.js
CHANGED
|
@@ -49,6 +49,7 @@ __export(index_exports, {
|
|
|
49
49
|
AgentClient: () => import_AgentClient.AgentClient,
|
|
50
50
|
AgentNotFoundError: () => import_errors.AgentNotFoundError,
|
|
51
51
|
AgentOAuthClientCredentialsSchema: () => import_oauth4.AgentOAuthClientCredentialsSchema,
|
|
52
|
+
AgentRateLimitedError: () => import_errors.AgentRateLimitedError,
|
|
52
53
|
Asset: () => import_asset_builders.Asset,
|
|
53
54
|
AsyncHandler: () => import_AsyncHandler.AsyncHandler,
|
|
54
55
|
AuthenticationCredentialsRejectedError: () => import_errors.AuthenticationCredentialsRejectedError,
|
|
@@ -896,6 +897,7 @@ function createAdCPClientFromEnv() {
|
|
|
896
897
|
AgentClient,
|
|
897
898
|
AgentNotFoundError,
|
|
898
899
|
AgentOAuthClientCredentialsSchema,
|
|
900
|
+
AgentRateLimitedError,
|
|
899
901
|
Asset,
|
|
900
902
|
AsyncHandler,
|
|
901
903
|
AuthenticationCredentialsRejectedError,
|
package/dist/lib/index.mjs
CHANGED
|
@@ -234,6 +234,7 @@ import {
|
|
|
234
234
|
IdempotencyConflictError,
|
|
235
235
|
IdempotencyExpiredError,
|
|
236
236
|
ResponseTooLargeError,
|
|
237
|
+
AgentRateLimitedError,
|
|
237
238
|
ActionNotAllowedError,
|
|
238
239
|
PreparedFixturesDeniedError,
|
|
239
240
|
adcpErrorToTypedError,
|
|
@@ -858,6 +859,7 @@ export {
|
|
|
858
859
|
AgentClient,
|
|
859
860
|
AgentNotFoundError,
|
|
860
861
|
AgentOAuthClientCredentialsSchema,
|
|
862
|
+
AgentRateLimitedError,
|
|
861
863
|
Asset,
|
|
862
864
|
AsyncHandler,
|
|
863
865
|
AuthenticationCredentialsRejectedError,
|
|
@@ -41,6 +41,8 @@ export interface ModernMCPConnectionOptions {
|
|
|
41
41
|
/** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
|
|
42
42
|
handleLegacy?: boolean;
|
|
43
43
|
}
|
|
44
|
+
/** `Retry-After` recorded on an MCP connect error by {@link withRetryAfter}, if any. */
|
|
45
|
+
export declare function retryAfterOf(error: unknown): string | undefined;
|
|
44
46
|
/**
|
|
45
47
|
* Try a tool call using the MCP 2026-07-28 protocol era.
|
|
46
48
|
*
|
|
@@ -41,6 +41,8 @@ export interface ModernMCPConnectionOptions {
|
|
|
41
41
|
/** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
|
|
42
42
|
handleLegacy?: boolean;
|
|
43
43
|
}
|
|
44
|
+
/** `Retry-After` recorded on an MCP connect error by {@link withRetryAfter}, if any. */
|
|
45
|
+
export declare function retryAfterOf(error: unknown): string | undefined;
|
|
44
46
|
/**
|
|
45
47
|
* Try a tool call using the MCP 2026-07-28 protocol era.
|
|
46
48
|
*
|
|
@@ -20,6 +20,7 @@ var mcp_modern_exports = {};
|
|
|
20
20
|
__export(mcp_modern_exports, {
|
|
21
21
|
closeModernMCPConnections: () => closeModernMCPConnections,
|
|
22
22
|
probeModernMCPConnection: () => probeModernMCPConnection,
|
|
23
|
+
retryAfterOf: () => retryAfterOf,
|
|
23
24
|
tryCallModernMCPTool: () => tryCallModernMCPTool,
|
|
24
25
|
tryListModernMCPTools: () => tryListModernMCPTools
|
|
25
26
|
});
|
|
@@ -248,9 +249,15 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
|
|
|
248
249
|
getCapability: options.signingContext.getCapability,
|
|
249
250
|
adcpVersion: options.signingContext.adcpVersion
|
|
250
251
|
}) : diagnosticFetch;
|
|
252
|
+
const transportFetch = (0, import_rawResponseCapture.wrapFetchWithCapture)(withPerRequestTraceHeaders(signedFetch));
|
|
253
|
+
let throttleRetryAfter;
|
|
251
254
|
const transport = new import_client.StreamableHTTPClientTransport(new URL(options.agentUrl), {
|
|
252
255
|
requestInit: { headers: (0, import_mcp_call_context.splitConnectionHeaders)(authHeaders).identity, redirect: "manual" },
|
|
253
|
-
fetch: (
|
|
256
|
+
fetch: async (input, init) => {
|
|
257
|
+
const response = await transportFetch(input, init);
|
|
258
|
+
throttleRetryAfter = response.status === 429 || response.status === 503 ? response.headers.get("retry-after") ?? void 0 : void 0;
|
|
259
|
+
return response;
|
|
260
|
+
},
|
|
254
261
|
...options.authProvider && {
|
|
255
262
|
authProvider: options.authProvider
|
|
256
263
|
}
|
|
@@ -293,8 +300,22 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
|
|
|
293
300
|
if (isNegotiationAuthFailure(error) && !skipProbe && presentedStaticCredential(authHeaders, options.authProvider)) {
|
|
294
301
|
return createNegotiatedClient(cacheKey, options, authHeaders, useCachedDiscovery, true);
|
|
295
302
|
}
|
|
296
|
-
throw error;
|
|
303
|
+
throw withRetryAfter(error, throttleRetryAfter);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function withRetryAfter(error, retryAfter) {
|
|
307
|
+
if (retryAfter === void 0 || !error || typeof error !== "object") return error;
|
|
308
|
+
const status = httpStatusOf(error);
|
|
309
|
+
if (status !== 429 && status !== 503) return error;
|
|
310
|
+
try {
|
|
311
|
+
Object.defineProperty(error, "retryAfter", { value: retryAfter, enumerable: false, configurable: true });
|
|
312
|
+
} catch {
|
|
297
313
|
}
|
|
314
|
+
return error;
|
|
315
|
+
}
|
|
316
|
+
function retryAfterOf(error) {
|
|
317
|
+
const value = error && typeof error === "object" ? error.retryAfter : void 0;
|
|
318
|
+
return typeof value === "string" ? value : void 0;
|
|
298
319
|
}
|
|
299
320
|
async function getOrCreateModernConnection(cacheKey, options, authHeaders) {
|
|
300
321
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -314,12 +335,12 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
|
|
|
314
335
|
const promise = createNegotiatedClient(cacheKey, options, authHeaders).then(async (client) => {
|
|
315
336
|
if ((client.getProtocolEra() === "modern" || options.handleLegacy === true) && generation === connectionGeneration) {
|
|
316
337
|
modernConnections.set(cacheKey, client);
|
|
317
|
-
(0, import_mcp_scope.registerMCPConnectionScopeCleanup)("modern", cacheKey, async () => {
|
|
338
|
+
(0, import_mcp_scope.registerMCPConnectionScopeCleanup)("modern", cacheKey, async (terminateSession) => {
|
|
318
339
|
if (modernConnections.get(cacheKey) !== client) return;
|
|
319
340
|
modernConnections.delete(cacheKey);
|
|
320
341
|
legacyConnectionExpiresAt.delete(cacheKey);
|
|
321
342
|
modernDiscoveries.delete(cacheKey);
|
|
322
|
-
await closeModernClient(client);
|
|
343
|
+
await closeModernClient(client, terminateSession);
|
|
323
344
|
});
|
|
324
345
|
if (client.getProtocolEra() === "legacy") {
|
|
325
346
|
legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);
|
|
@@ -341,7 +362,10 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
|
|
|
341
362
|
return promise;
|
|
342
363
|
}
|
|
343
364
|
async function retireFailedConnection(cacheKey, client, error) {
|
|
344
|
-
if ((0, import_abort.isAbortOrTimeoutError)(error))
|
|
365
|
+
if ((0, import_abort.isAbortOrTimeoutError)(error)) {
|
|
366
|
+
(0, import_mcp_scope.markMCPConnectionScopeInterrupted)();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
345
369
|
if (modernConnections.get(cacheKey) === client) {
|
|
346
370
|
modernConnections.delete(cacheKey);
|
|
347
371
|
legacyConnectionExpiresAt.delete(cacheKey);
|
|
@@ -510,6 +534,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
|
|
|
510
534
|
options.allowPrivateIp
|
|
511
535
|
);
|
|
512
536
|
const scoped = (0, import_mcp_connection_policy.shouldReuseMCPConnection)(options.fetchFn !== void 0);
|
|
537
|
+
if (isKnownLegacy(cacheKey)) return { connected: false };
|
|
513
538
|
let client;
|
|
514
539
|
return (0, import_mcp_call_context.runWithMCPCallContext)(
|
|
515
540
|
callContextFor({ customHeaders, requestTimeoutMs: options.requestTimeoutMs }),
|
|
@@ -650,6 +675,7 @@ async function closeModernMCPConnections() {
|
|
|
650
675
|
0 && (module.exports = {
|
|
651
676
|
closeModernMCPConnections,
|
|
652
677
|
probeModernMCPConnection,
|
|
678
|
+
retryAfterOf,
|
|
653
679
|
tryCallModernMCPTool,
|
|
654
680
|
tryListModernMCPTools
|
|
655
681
|
});
|
|
@@ -16,6 +16,7 @@ import { is401Error } from "../errors/index.mjs";
|
|
|
16
16
|
import { withSpan, injectTraceHeaders } from "../observability/tracing.mjs";
|
|
17
17
|
import {
|
|
18
18
|
currentMCPConnectionScopeKey,
|
|
19
|
+
markMCPConnectionScopeInterrupted,
|
|
19
20
|
isMCPConnectionScopeCacheKeyActive,
|
|
20
21
|
registerMCPConnectionScopeCleanup,
|
|
21
22
|
registerMCPConnectionScopePending
|
|
@@ -255,9 +256,15 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
|
|
|
255
256
|
getCapability: options.signingContext.getCapability,
|
|
256
257
|
adcpVersion: options.signingContext.adcpVersion
|
|
257
258
|
}) : diagnosticFetch;
|
|
259
|
+
const transportFetch = wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch));
|
|
260
|
+
let throttleRetryAfter;
|
|
258
261
|
const transport = new StreamableHTTPClientTransport(new URL(options.agentUrl), {
|
|
259
262
|
requestInit: { headers: splitConnectionHeaders(authHeaders).identity, redirect: "manual" },
|
|
260
|
-
fetch:
|
|
263
|
+
fetch: async (input, init) => {
|
|
264
|
+
const response = await transportFetch(input, init);
|
|
265
|
+
throttleRetryAfter = response.status === 429 || response.status === 503 ? response.headers.get("retry-after") ?? void 0 : void 0;
|
|
266
|
+
return response;
|
|
267
|
+
},
|
|
261
268
|
...options.authProvider && {
|
|
262
269
|
authProvider: options.authProvider
|
|
263
270
|
}
|
|
@@ -300,8 +307,22 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
|
|
|
300
307
|
if (isNegotiationAuthFailure(error) && !skipProbe && presentedStaticCredential(authHeaders, options.authProvider)) {
|
|
301
308
|
return createNegotiatedClient(cacheKey, options, authHeaders, useCachedDiscovery, true);
|
|
302
309
|
}
|
|
303
|
-
throw error;
|
|
310
|
+
throw withRetryAfter(error, throttleRetryAfter);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function withRetryAfter(error, retryAfter) {
|
|
314
|
+
if (retryAfter === void 0 || !error || typeof error !== "object") return error;
|
|
315
|
+
const status = httpStatusOf(error);
|
|
316
|
+
if (status !== 429 && status !== 503) return error;
|
|
317
|
+
try {
|
|
318
|
+
Object.defineProperty(error, "retryAfter", { value: retryAfter, enumerable: false, configurable: true });
|
|
319
|
+
} catch {
|
|
304
320
|
}
|
|
321
|
+
return error;
|
|
322
|
+
}
|
|
323
|
+
function retryAfterOf(error) {
|
|
324
|
+
const value = error && typeof error === "object" ? error.retryAfter : void 0;
|
|
325
|
+
return typeof value === "string" ? value : void 0;
|
|
305
326
|
}
|
|
306
327
|
async function getOrCreateModernConnection(cacheKey, options, authHeaders) {
|
|
307
328
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -321,12 +342,12 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
|
|
|
321
342
|
const promise = createNegotiatedClient(cacheKey, options, authHeaders).then(async (client) => {
|
|
322
343
|
if ((client.getProtocolEra() === "modern" || options.handleLegacy === true) && generation === connectionGeneration) {
|
|
323
344
|
modernConnections.set(cacheKey, client);
|
|
324
|
-
registerMCPConnectionScopeCleanup("modern", cacheKey, async () => {
|
|
345
|
+
registerMCPConnectionScopeCleanup("modern", cacheKey, async (terminateSession) => {
|
|
325
346
|
if (modernConnections.get(cacheKey) !== client) return;
|
|
326
347
|
modernConnections.delete(cacheKey);
|
|
327
348
|
legacyConnectionExpiresAt.delete(cacheKey);
|
|
328
349
|
modernDiscoveries.delete(cacheKey);
|
|
329
|
-
await closeModernClient(client);
|
|
350
|
+
await closeModernClient(client, terminateSession);
|
|
330
351
|
});
|
|
331
352
|
if (client.getProtocolEra() === "legacy") {
|
|
332
353
|
legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);
|
|
@@ -348,7 +369,10 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
|
|
|
348
369
|
return promise;
|
|
349
370
|
}
|
|
350
371
|
async function retireFailedConnection(cacheKey, client, error) {
|
|
351
|
-
if (isAbortOrTimeoutError(error))
|
|
372
|
+
if (isAbortOrTimeoutError(error)) {
|
|
373
|
+
markMCPConnectionScopeInterrupted();
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
352
376
|
if (modernConnections.get(cacheKey) === client) {
|
|
353
377
|
modernConnections.delete(cacheKey);
|
|
354
378
|
legacyConnectionExpiresAt.delete(cacheKey);
|
|
@@ -517,6 +541,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
|
|
|
517
541
|
options.allowPrivateIp
|
|
518
542
|
);
|
|
519
543
|
const scoped = shouldReuseMCPConnection(options.fetchFn !== void 0);
|
|
544
|
+
if (isKnownLegacy(cacheKey)) return { connected: false };
|
|
520
545
|
let client;
|
|
521
546
|
return runWithMCPCallContext(
|
|
522
547
|
callContextFor({ customHeaders, requestTimeoutMs: options.requestTimeoutMs }),
|
|
@@ -656,6 +681,7 @@ async function closeModernMCPConnections() {
|
|
|
656
681
|
export {
|
|
657
682
|
closeModernMCPConnections,
|
|
658
683
|
probeModernMCPConnection,
|
|
684
|
+
retryAfterOf,
|
|
659
685
|
tryCallModernMCPTool,
|
|
660
686
|
tryListModernMCPTools
|
|
661
687
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
type ScopeCleanup = () => Promise<void>;
|
|
1
|
+
type ScopeCleanup = (terminateSession: boolean) => Promise<void>;
|
|
2
2
|
/** Cache-key suffix for the current caller-owned MCP workflow. */
|
|
3
3
|
export declare function currentMCPConnectionScopeKey(): string | undefined;
|
|
4
|
+
/** Preserve seller work even when a higher layer handles a request timeout. */
|
|
5
|
+
export declare function markMCPConnectionScopeInterrupted(): void;
|
|
4
6
|
/** Whether an LRU entry belongs to a workflow that has not finished yet. */
|
|
5
7
|
export declare function isMCPConnectionScopeCacheKeyActive(cacheKey: string): boolean;
|
|
6
8
|
/** Register one idempotent cache-entry cleanup with the current workflow. */
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
type ScopeCleanup = () => Promise<void>;
|
|
1
|
+
type ScopeCleanup = (terminateSession: boolean) => Promise<void>;
|
|
2
2
|
/** Cache-key suffix for the current caller-owned MCP workflow. */
|
|
3
3
|
export declare function currentMCPConnectionScopeKey(): string | undefined;
|
|
4
|
+
/** Preserve seller work even when a higher layer handles a request timeout. */
|
|
5
|
+
export declare function markMCPConnectionScopeInterrupted(): void;
|
|
4
6
|
/** Whether an LRU entry belongs to a workflow that has not finished yet. */
|
|
5
7
|
export declare function isMCPConnectionScopeCacheKeyActive(cacheKey: string): boolean;
|
|
6
8
|
/** Register one idempotent cache-entry cleanup with the current workflow. */
|
|
@@ -21,18 +21,24 @@ __export(mcp_scope_exports, {
|
|
|
21
21
|
closeCurrentMCPConnectionScope: () => closeCurrentMCPConnectionScope,
|
|
22
22
|
currentMCPConnectionScopeKey: () => currentMCPConnectionScopeKey,
|
|
23
23
|
isMCPConnectionScopeCacheKeyActive: () => isMCPConnectionScopeCacheKeyActive,
|
|
24
|
+
markMCPConnectionScopeInterrupted: () => markMCPConnectionScopeInterrupted,
|
|
24
25
|
registerMCPConnectionScopeCleanup: () => registerMCPConnectionScopeCleanup,
|
|
25
26
|
registerMCPConnectionScopePending: () => registerMCPConnectionScopePending,
|
|
26
27
|
withMCPConnectionScope: () => withMCPConnectionScope
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(mcp_scope_exports);
|
|
29
30
|
var import_node_async_hooks = require("node:async_hooks");
|
|
31
|
+
var import_abort = require('./abort.js');
|
|
30
32
|
const scopeStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
31
33
|
const activeScopeKeys = /* @__PURE__ */ new Set();
|
|
32
34
|
let nextScopeId = 0;
|
|
33
35
|
function currentMCPConnectionScopeKey() {
|
|
34
36
|
return scopeStorage.getStore()?.cacheKey;
|
|
35
37
|
}
|
|
38
|
+
function markMCPConnectionScopeInterrupted() {
|
|
39
|
+
const scope = scopeStorage.getStore();
|
|
40
|
+
if (scope?.preserveOnInterruption) scope.interrupted = true;
|
|
41
|
+
}
|
|
36
42
|
function isMCPConnectionScopeCacheKeyActive(cacheKey) {
|
|
37
43
|
const marker = cacheKey.lastIndexOf("::scope:");
|
|
38
44
|
return marker >= 0 && activeScopeKeys.has(cacheKey.slice(marker + 2));
|
|
@@ -55,17 +61,27 @@ async function closeCurrentMCPConnectionScope() {
|
|
|
55
61
|
}
|
|
56
62
|
const cleanups = [...scope.cleanups.values()];
|
|
57
63
|
scope.cleanups.clear();
|
|
58
|
-
await Promise.allSettled(cleanups.map((cleanup) => cleanup()));
|
|
64
|
+
await Promise.allSettled(cleanups.map((cleanup) => cleanup(!scope.signal?.aborted && !scope.interrupted)));
|
|
59
65
|
return true;
|
|
60
66
|
}
|
|
61
67
|
async function withMCPConnectionScope(fn, options = {}) {
|
|
62
68
|
if (scopeStorage.getStore() && options.isolate !== true) return fn();
|
|
63
69
|
const id = ++nextScopeId;
|
|
64
|
-
const scope = {
|
|
70
|
+
const scope = {
|
|
71
|
+
id,
|
|
72
|
+
cacheKey: `scope:${id}`,
|
|
73
|
+
pending: /* @__PURE__ */ new Set(),
|
|
74
|
+
cleanups: /* @__PURE__ */ new Map(),
|
|
75
|
+
signal: options.signal,
|
|
76
|
+
preserveOnInterruption: options.preserveOnInterruption
|
|
77
|
+
};
|
|
65
78
|
activeScopeKeys.add(scope.cacheKey);
|
|
66
79
|
return scopeStorage.run(scope, async () => {
|
|
67
80
|
try {
|
|
68
81
|
return await fn();
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if ((0, import_abort.isAbortOrTimeoutError)(error)) markMCPConnectionScopeInterrupted();
|
|
84
|
+
throw error;
|
|
69
85
|
} finally {
|
|
70
86
|
try {
|
|
71
87
|
await closeCurrentMCPConnectionScope();
|
|
@@ -80,6 +96,7 @@ async function withMCPConnectionScope(fn, options = {}) {
|
|
|
80
96
|
closeCurrentMCPConnectionScope,
|
|
81
97
|
currentMCPConnectionScopeKey,
|
|
82
98
|
isMCPConnectionScopeCacheKeyActive,
|
|
99
|
+
markMCPConnectionScopeInterrupted,
|
|
83
100
|
registerMCPConnectionScopeCleanup,
|
|
84
101
|
registerMCPConnectionScopePending,
|
|
85
102
|
withMCPConnectionScope
|
|
@@ -4,12 +4,17 @@ import { createRequire as __adcpCreateRequire } from "node:module";
|
|
|
4
4
|
const __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));
|
|
5
5
|
const require2 = __adcpCreateRequire(import.meta.url);
|
|
6
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
|
+
import { isAbortOrTimeoutError } from "./abort.mjs";
|
|
7
8
|
const scopeStorage = new AsyncLocalStorage();
|
|
8
9
|
const activeScopeKeys = /* @__PURE__ */ new Set();
|
|
9
10
|
let nextScopeId = 0;
|
|
10
11
|
function currentMCPConnectionScopeKey() {
|
|
11
12
|
return scopeStorage.getStore()?.cacheKey;
|
|
12
13
|
}
|
|
14
|
+
function markMCPConnectionScopeInterrupted() {
|
|
15
|
+
const scope = scopeStorage.getStore();
|
|
16
|
+
if (scope?.preserveOnInterruption) scope.interrupted = true;
|
|
17
|
+
}
|
|
13
18
|
function isMCPConnectionScopeCacheKeyActive(cacheKey) {
|
|
14
19
|
const marker = cacheKey.lastIndexOf("::scope:");
|
|
15
20
|
return marker >= 0 && activeScopeKeys.has(cacheKey.slice(marker + 2));
|
|
@@ -32,17 +37,27 @@ async function closeCurrentMCPConnectionScope() {
|
|
|
32
37
|
}
|
|
33
38
|
const cleanups = [...scope.cleanups.values()];
|
|
34
39
|
scope.cleanups.clear();
|
|
35
|
-
await Promise.allSettled(cleanups.map((cleanup) => cleanup()));
|
|
40
|
+
await Promise.allSettled(cleanups.map((cleanup) => cleanup(!scope.signal?.aborted && !scope.interrupted)));
|
|
36
41
|
return true;
|
|
37
42
|
}
|
|
38
43
|
async function withMCPConnectionScope(fn, options = {}) {
|
|
39
44
|
if (scopeStorage.getStore() && options.isolate !== true) return fn();
|
|
40
45
|
const id = ++nextScopeId;
|
|
41
|
-
const scope = {
|
|
46
|
+
const scope = {
|
|
47
|
+
id,
|
|
48
|
+
cacheKey: `scope:${id}`,
|
|
49
|
+
pending: /* @__PURE__ */ new Set(),
|
|
50
|
+
cleanups: /* @__PURE__ */ new Map(),
|
|
51
|
+
signal: options.signal,
|
|
52
|
+
preserveOnInterruption: options.preserveOnInterruption
|
|
53
|
+
};
|
|
42
54
|
activeScopeKeys.add(scope.cacheKey);
|
|
43
55
|
return scopeStorage.run(scope, async () => {
|
|
44
56
|
try {
|
|
45
57
|
return await fn();
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (isAbortOrTimeoutError(error)) markMCPConnectionScopeInterrupted();
|
|
60
|
+
throw error;
|
|
46
61
|
} finally {
|
|
47
62
|
try {
|
|
48
63
|
await closeCurrentMCPConnectionScope();
|
|
@@ -56,6 +71,7 @@ export {
|
|
|
56
71
|
closeCurrentMCPConnectionScope,
|
|
57
72
|
currentMCPConnectionScopeKey,
|
|
58
73
|
isMCPConnectionScopeCacheKeyActive,
|
|
74
|
+
markMCPConnectionScopeInterrupted,
|
|
59
75
|
registerMCPConnectionScopeCleanup,
|
|
60
76
|
registerMCPConnectionScopePending,
|
|
61
77
|
withMCPConnectionScope
|
|
@@ -207,10 +207,10 @@ async function getOrCreateConnection(cacheKey, baseUrl, authHeaders, debugLogs,
|
|
|
207
207
|
throw new Error(`MCP ${label} completed after connection teardown`);
|
|
208
208
|
}
|
|
209
209
|
connectionCache.set(cacheKey, client);
|
|
210
|
-
(0, import_mcp_scope.registerMCPConnectionScopeCleanup)("legacy", cacheKey, async () => {
|
|
210
|
+
(0, import_mcp_scope.registerMCPConnectionScopeCleanup)("legacy", cacheKey, async (terminateSession) => {
|
|
211
211
|
if (connectionCache.get(cacheKey) !== client) return;
|
|
212
212
|
connectionCache.delete(cacheKey);
|
|
213
|
-
await closeMCPClient(client);
|
|
213
|
+
await closeMCPClient(client, terminateSession);
|
|
214
214
|
});
|
|
215
215
|
evictLeastRecentlyUsed();
|
|
216
216
|
return client;
|
|
@@ -280,10 +280,10 @@ async function getOrCreateOAuthConnection(cacheKey, options) {
|
|
|
280
280
|
throw new Error("OAuth MCP connection completed after connection teardown");
|
|
281
281
|
}
|
|
282
282
|
oauthConnectionCache.set(cacheKey, client);
|
|
283
|
-
(0, import_mcp_scope.registerMCPConnectionScopeCleanup)("oauth", cacheKey, async () => {
|
|
283
|
+
(0, import_mcp_scope.registerMCPConnectionScopeCleanup)("oauth", cacheKey, async (terminateSession) => {
|
|
284
284
|
if (oauthConnectionCache.get(cacheKey) !== client) return;
|
|
285
285
|
oauthConnectionCache.delete(cacheKey);
|
|
286
|
-
await closeMCPClient(client);
|
|
286
|
+
await closeMCPClient(client, terminateSession);
|
|
287
287
|
});
|
|
288
288
|
evictLeastRecentlyUsedOAuth();
|
|
289
289
|
return client;
|
|
@@ -337,7 +337,10 @@ async function withCachedOAuthConnectionImpl(options, label, fn) {
|
|
|
337
337
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
338
338
|
error
|
|
339
339
|
});
|
|
340
|
-
if ((0, import_abort.isAbortOrTimeoutError)(error))
|
|
340
|
+
if ((0, import_abort.isAbortOrTimeoutError)(error)) {
|
|
341
|
+
(0, import_mcp_scope.markMCPConnectionScopeInterrupted)();
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
341
344
|
if ((0, import_errors.is401Error)(error)) {
|
|
342
345
|
options.debugLogs.push({
|
|
343
346
|
type: "warning",
|
|
@@ -405,7 +408,10 @@ async function withCachedConnectionImpl(agentUrl, authToken, authHeaders, debugL
|
|
|
405
408
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
406
409
|
error
|
|
407
410
|
});
|
|
408
|
-
if ((0, import_abort.isAbortOrTimeoutError)(error))
|
|
411
|
+
if ((0, import_abort.isAbortOrTimeoutError)(error)) {
|
|
412
|
+
(0, import_mcp_scope.markMCPConnectionScopeInterrupted)();
|
|
413
|
+
throw error;
|
|
414
|
+
}
|
|
409
415
|
if ((0, import_errors.is401Error)(error)) {
|
|
410
416
|
debugLogs.push({
|
|
411
417
|
type: "warning",
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import { closeModernMCPConnections, tryCallModernMCPTool } from "./mcp-modern.mjs";
|
|
36
36
|
import {
|
|
37
37
|
currentMCPConnectionScopeKey,
|
|
38
|
+
markMCPConnectionScopeInterrupted,
|
|
38
39
|
isMCPConnectionScopeCacheKeyActive,
|
|
39
40
|
registerMCPConnectionScopeCleanup,
|
|
40
41
|
registerMCPConnectionScopePending
|
|
@@ -208,10 +209,10 @@ async function getOrCreateConnection(cacheKey, baseUrl, authHeaders, debugLogs,
|
|
|
208
209
|
throw new Error(`MCP ${label} completed after connection teardown`);
|
|
209
210
|
}
|
|
210
211
|
connectionCache.set(cacheKey, client);
|
|
211
|
-
registerMCPConnectionScopeCleanup("legacy", cacheKey, async () => {
|
|
212
|
+
registerMCPConnectionScopeCleanup("legacy", cacheKey, async (terminateSession) => {
|
|
212
213
|
if (connectionCache.get(cacheKey) !== client) return;
|
|
213
214
|
connectionCache.delete(cacheKey);
|
|
214
|
-
await closeMCPClient(client);
|
|
215
|
+
await closeMCPClient(client, terminateSession);
|
|
215
216
|
});
|
|
216
217
|
evictLeastRecentlyUsed();
|
|
217
218
|
return client;
|
|
@@ -281,10 +282,10 @@ async function getOrCreateOAuthConnection(cacheKey, options) {
|
|
|
281
282
|
throw new Error("OAuth MCP connection completed after connection teardown");
|
|
282
283
|
}
|
|
283
284
|
oauthConnectionCache.set(cacheKey, client);
|
|
284
|
-
registerMCPConnectionScopeCleanup("oauth", cacheKey, async () => {
|
|
285
|
+
registerMCPConnectionScopeCleanup("oauth", cacheKey, async (terminateSession) => {
|
|
285
286
|
if (oauthConnectionCache.get(cacheKey) !== client) return;
|
|
286
287
|
oauthConnectionCache.delete(cacheKey);
|
|
287
|
-
await closeMCPClient(client);
|
|
288
|
+
await closeMCPClient(client, terminateSession);
|
|
288
289
|
});
|
|
289
290
|
evictLeastRecentlyUsedOAuth();
|
|
290
291
|
return client;
|
|
@@ -338,7 +339,10 @@ async function withCachedOAuthConnectionImpl(options, label, fn) {
|
|
|
338
339
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
339
340
|
error
|
|
340
341
|
});
|
|
341
|
-
if (isAbortOrTimeoutError(error))
|
|
342
|
+
if (isAbortOrTimeoutError(error)) {
|
|
343
|
+
markMCPConnectionScopeInterrupted();
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
342
346
|
if (is401Error(error)) {
|
|
343
347
|
options.debugLogs.push({
|
|
344
348
|
type: "warning",
|
|
@@ -406,7 +410,10 @@ async function withCachedConnectionImpl(agentUrl, authToken, authHeaders, debugL
|
|
|
406
410
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
407
411
|
error
|
|
408
412
|
});
|
|
409
|
-
if (isAbortOrTimeoutError(error))
|
|
413
|
+
if (isAbortOrTimeoutError(error)) {
|
|
414
|
+
markMCPConnectionScopeInterrupted();
|
|
415
|
+
throw error;
|
|
416
|
+
}
|
|
410
417
|
if (is401Error(error)) {
|
|
411
418
|
debugLogs.push({
|
|
412
419
|
type: "warning",
|