@astrasyncai/verification-gateway 5.12.0 → 5.14.0

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.
Files changed (75) hide show
  1. package/dist/adapters/express.js +63 -19
  2. package/dist/adapters/express.js.map +1 -1
  3. package/dist/adapters/express.mjs +63 -19
  4. package/dist/adapters/express.mjs.map +1 -1
  5. package/dist/adapters/mcp.js +26 -9
  6. package/dist/adapters/mcp.js.map +1 -1
  7. package/dist/adapters/mcp.mjs +26 -9
  8. package/dist/adapters/mcp.mjs.map +1 -1
  9. package/dist/adapters/nextjs.js +63 -19
  10. package/dist/adapters/nextjs.js.map +1 -1
  11. package/dist/adapters/nextjs.mjs +63 -19
  12. package/dist/adapters/nextjs.mjs.map +1 -1
  13. package/dist/adapters/sdk.js +26 -9
  14. package/dist/adapters/sdk.js.map +1 -1
  15. package/dist/adapters/sdk.mjs +26 -9
  16. package/dist/adapters/sdk.mjs.map +1 -1
  17. package/dist/agent/index.js +1 -1
  18. package/dist/agent/index.js.map +1 -1
  19. package/dist/agent/index.mjs +1 -1
  20. package/dist/agent/index.mjs.map +1 -1
  21. package/dist/bin/astrasync-claude-hook.js +53 -18
  22. package/dist/bin/astrasync-codex-hook.js +53 -18
  23. package/dist/bin/astrasync-guard.js +53 -18
  24. package/dist/bin/astrasync.js +54 -19
  25. package/dist/browser/background.js +53 -18
  26. package/dist/browser/background.js.map +1 -1
  27. package/dist/browser/background.mjs +53 -18
  28. package/dist/browser/background.mjs.map +1 -1
  29. package/dist/cli/index.js +1 -1
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/index.mjs +1 -1
  32. package/dist/cli/index.mjs.map +1 -1
  33. package/dist/codex/index.js +53 -18
  34. package/dist/codex/index.js.map +1 -1
  35. package/dist/codex/index.mjs +53 -18
  36. package/dist/codex/index.mjs.map +1 -1
  37. package/dist/cursor/extension.js +53 -18
  38. package/dist/cursor/extension.js.map +1 -1
  39. package/dist/cursor/extension.mjs +53 -18
  40. package/dist/cursor/extension.mjs.map +1 -1
  41. package/dist/edge-config.js +1 -1
  42. package/dist/edge-config.js.map +1 -1
  43. package/dist/edge-config.mjs +1 -1
  44. package/dist/edge-config.mjs.map +1 -1
  45. package/dist/edge-core/index.d.mts +32 -4
  46. package/dist/edge-core/index.d.ts +32 -4
  47. package/dist/edge-core/index.js +53 -18
  48. package/dist/edge-core/index.js.map +1 -1
  49. package/dist/edge-core/index.mjs +53 -18
  50. package/dist/edge-core/index.mjs.map +1 -1
  51. package/dist/gateway/gateway.js +53 -18
  52. package/dist/gateway/gateway.js.map +1 -1
  53. package/dist/gateway/gateway.mjs +53 -18
  54. package/dist/gateway/gateway.mjs.map +1 -1
  55. package/dist/index.d.mts +2 -12
  56. package/dist/index.d.ts +2 -12
  57. package/dist/index.js +63 -19
  58. package/dist/index.js.map +1 -1
  59. package/dist/index.mjs +63 -19
  60. package/dist/index.mjs.map +1 -1
  61. package/dist/registration/index.js +1 -1
  62. package/dist/registration/index.js.map +1 -1
  63. package/dist/registration/index.mjs +1 -1
  64. package/dist/registration/index.mjs.map +1 -1
  65. package/dist/transport/index.js +1 -1
  66. package/dist/transport/index.js.map +1 -1
  67. package/dist/transport/index.mjs +1 -1
  68. package/dist/transport/index.mjs.map +1 -1
  69. package/dist/verify.d.mts +0 -10
  70. package/dist/verify.d.ts +0 -10
  71. package/dist/verify.js +36 -10
  72. package/dist/verify.js.map +1 -1
  73. package/dist/verify.mjs +36 -10
  74. package/dist/verify.mjs.map +1 -1
  75. package/package.json +3 -2
package/dist/index.d.mts CHANGED
@@ -1515,16 +1515,6 @@ interface ReportAttemptOptions {
1515
1515
  retried: boolean;
1516
1516
  }) => void;
1517
1517
  }
1518
- /**
1519
- * Fetch the per-route policy for an endpoint from the AstraSync backend.
1520
- * v2.9.7 moved policy authority into the dashboard — the SDK no longer
1521
- * accepts `routes` from merchant-side source code, it fetches them from
1522
- * here on init (and refreshes periodically).
1523
- *
1524
- * Returns `null` when the request fails for any reason — the caller decides
1525
- * how to fall back (the middleware allows-all when no policy is loaded so
1526
- * a misconfigured init doesn't take down the merchant's API).
1527
- */
1528
1518
  declare function fetchRoutes(config: GatewayConfig, counterpartyId: string): Promise<RouteAccessConfigShape[] | null>;
1529
1519
  /**
1530
1520
  * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the
@@ -4945,7 +4935,7 @@ declare function detectRuntime(userAgent: string | undefined | null): string | u
4945
4935
  * silently (never throwing), so this is a no-op there — which is correct:
4946
4936
  * in a browser the page's real UA is the honest identity.
4947
4937
  */
4948
- declare const SDK_USER_AGENT = "astrasync-sdk/5.12.0";
4938
+ declare const SDK_USER_AGENT = "astrasync-sdk/5.14.0";
4949
4939
  declare const sdkFetch: typeof fetch;
4950
4940
 
4951
4941
  interface LocalPolicy {
@@ -5063,6 +5053,6 @@ declare function parseYaml(yamlContent: string): ParseResult;
5063
5053
  * is fine — bumping both in the release-ceremony commit keeps them
5064
5054
  * lockstep.
5065
5055
  */
5066
- declare const SDK_VERSION = "5.12.0";
5056
+ declare const SDK_VERSION = "5.14.0";
5067
5057
 
5068
5058
  export { AgentClient, type AgentCredentials, type AgentProtocol, type AgentRecord, AstraSync, type AstraSyncConfig, type AstraSyncCredentials, AstraSyncError, type AttemptOutcome, type AttemptReport, AuthenticationError, type BuildGuidanceParams, CAPTURE_SCHEMA_VERSION, type CallerMetadata, ChallengeHandler, type CommerceArtifactsPayload, type CommerceContext, type CommercePipelineInput, type CommerceShieldProps, type ConsiderationItem, type ConsiderationSet, type CounterpartyType, DECLARED_SOURCE_MAX, DEFAULT_EDGE_CONFIG, type DynamicPlatformFingerprint, type EdgeConfig, type EdgeMode, type EdgePathRule, type EdgeVerificationDepth, type EnhancedVerificationResult, type ExpressMiddlewareOptions, type FetchEdgeConfigResult, type FetchEdgeConfigSuccess, type FiatSettlementBinding, type FrameworkConfig, type FulfilmentInfo, type GatewayConfig, type GuidanceEnvelope, type GuidanceInfo, type HealthResponse, KYDRequiredError, type ParseResult as LocalPolicyParseResult, type ValidationError as LocalPolicyValidationError, type ValidationResult as LocalPolicyValidationResult, MAX_HEADERS, MAX_HEADER_VALUE_BYTES, MAX_TOTAL_BYTES, MCP_VERIFIED_HOP_HEADER, MCP_VERIFIED_HOP_MAX_AGE_MS, type McpMiddlewareOptions, type MerchantSettlementToken, type ModelConfig, type NextJsMiddlewareOptions, type ObservedMetadata, type PDLSSConfig$1 as PDLSSConfig, type PDLSSDuration, type PDLSSInfo, type PDLSSLimits, type PDLSSPurpose, type PDLSSScope, type PDLSSSelfInstantiation, PLATFORM_AGENT_SIGNATURES, type PendingRegistrationResponse, type PlatformAgentVendor, type PlatformDetectionInput, type PlatformFingerprint, type PlatformSignatureDef, type PollRegistrationResult, type ProtocolTransport, RUNTIME_SIGNATURES, type RegisterOptions, type RegisterResult, RegistrationDeniedError, RegistrationExpiredError, type RegistrationResponse, RegistrationTimeoutError, type ReportAttemptOptions, type RouteAccessConfig, type RuntimeChallengeResult, type RuntimeSignature, type SDKOptions, SDK_USER_AGENT, type SanitizeHeadersResult, type SettlementArtifact, type SettlementArtifactBinding, type SettlementArtifactBindingBase, type SettlementDecision, type SettlementOutcomeInfo, type SettlementRequest, type StablecoinSettlementBinding, type StepUpApprovalInfo, type StepUpApprovalStatus, type StepUpOutcome, TRUST_LEVEL_RANGES, type TokenGuidance, type ToolGate, type ToolGateConfig, type TrustLevel, VERIFICATION_STATUS_HEADER, SDK_VERSION as VERSION, type VerificationInterstitialProps, type VerificationRequest, type VerificationResult, type VerifiedAgent, type VerifiedDeveloper, type VerifiedHopMarker, type VerifiedOrganization, type VerifyOptions, type VerifyResponse, type WaitForApprovalOptions, type WellKnownAgenticCommerce, _resetEdgeConfigCache, index as agent, authorizeSettlement, awaitStepUpApproval, buildGuidance, buildSdkObservedMetadata, buildVerificationUnavailableBody, clearCache, createMcpMiddleware, degradeToObserve, denyStatusFor, deriveConnectionFromHeaders, detectPlatformFingerprint, detectRuntime, express, extractApiKeyFormat, extractCredentials, extractMcpCredentials, extractPlatformHeaders, fetchEdgeConfig, fetchRoutes, getCachedWellKnownUrls, getEdgeConfig, getTrustLevel, getWellKnownUrls, hasCredentials, isEdgeConfig, isRejectedIdentityClaim, isVerificationUnavailable, isVerifiedHopValidFor, matchEdgePathRule, matchPlatformSignature, nextjs, normalizeDeclaredSource, parseYaml as parseLocalPolicyYaml, parseVerifiedHop, pollStepUpStatus, prefetchWellKnown, quickVerify, recordDecision, reportAttempt, reportUnregisteredAttempt, sanitizeHeaders, sdk, sdkFetch, serializeVerifiedHop, setMcpMeta, index$1 as transport, unavailableRetryAfterSeconds, validatePolicy as validateLocalPolicy, verify };
package/dist/index.d.ts CHANGED
@@ -1515,16 +1515,6 @@ interface ReportAttemptOptions {
1515
1515
  retried: boolean;
1516
1516
  }) => void;
1517
1517
  }
1518
- /**
1519
- * Fetch the per-route policy for an endpoint from the AstraSync backend.
1520
- * v2.9.7 moved policy authority into the dashboard — the SDK no longer
1521
- * accepts `routes` from merchant-side source code, it fetches them from
1522
- * here on init (and refreshes periodically).
1523
- *
1524
- * Returns `null` when the request fails for any reason — the caller decides
1525
- * how to fall back (the middleware allows-all when no policy is loaded so
1526
- * a misconfigured init doesn't take down the merchant's API).
1527
- */
1528
1518
  declare function fetchRoutes(config: GatewayConfig, counterpartyId: string): Promise<RouteAccessConfigShape[] | null>;
1529
1519
  /**
1530
1520
  * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the
@@ -4945,7 +4935,7 @@ declare function detectRuntime(userAgent: string | undefined | null): string | u
4945
4935
  * silently (never throwing), so this is a no-op there — which is correct:
4946
4936
  * in a browser the page's real UA is the honest identity.
4947
4937
  */
4948
- declare const SDK_USER_AGENT = "astrasync-sdk/5.12.0";
4938
+ declare const SDK_USER_AGENT = "astrasync-sdk/5.14.0";
4949
4939
  declare const sdkFetch: typeof fetch;
4950
4940
 
4951
4941
  interface LocalPolicy {
@@ -5063,6 +5053,6 @@ declare function parseYaml(yamlContent: string): ParseResult;
5063
5053
  * is fine — bumping both in the release-ceremony commit keeps them
5064
5054
  * lockstep.
5065
5055
  */
5066
- declare const SDK_VERSION = "5.12.0";
5056
+ declare const SDK_VERSION = "5.14.0";
5067
5057
 
5068
5058
  export { AgentClient, type AgentCredentials, type AgentProtocol, type AgentRecord, AstraSync, type AstraSyncConfig, type AstraSyncCredentials, AstraSyncError, type AttemptOutcome, type AttemptReport, AuthenticationError, type BuildGuidanceParams, CAPTURE_SCHEMA_VERSION, type CallerMetadata, ChallengeHandler, type CommerceArtifactsPayload, type CommerceContext, type CommercePipelineInput, type CommerceShieldProps, type ConsiderationItem, type ConsiderationSet, type CounterpartyType, DECLARED_SOURCE_MAX, DEFAULT_EDGE_CONFIG, type DynamicPlatformFingerprint, type EdgeConfig, type EdgeMode, type EdgePathRule, type EdgeVerificationDepth, type EnhancedVerificationResult, type ExpressMiddlewareOptions, type FetchEdgeConfigResult, type FetchEdgeConfigSuccess, type FiatSettlementBinding, type FrameworkConfig, type FulfilmentInfo, type GatewayConfig, type GuidanceEnvelope, type GuidanceInfo, type HealthResponse, KYDRequiredError, type ParseResult as LocalPolicyParseResult, type ValidationError as LocalPolicyValidationError, type ValidationResult as LocalPolicyValidationResult, MAX_HEADERS, MAX_HEADER_VALUE_BYTES, MAX_TOTAL_BYTES, MCP_VERIFIED_HOP_HEADER, MCP_VERIFIED_HOP_MAX_AGE_MS, type McpMiddlewareOptions, type MerchantSettlementToken, type ModelConfig, type NextJsMiddlewareOptions, type ObservedMetadata, type PDLSSConfig$1 as PDLSSConfig, type PDLSSDuration, type PDLSSInfo, type PDLSSLimits, type PDLSSPurpose, type PDLSSScope, type PDLSSSelfInstantiation, PLATFORM_AGENT_SIGNATURES, type PendingRegistrationResponse, type PlatformAgentVendor, type PlatformDetectionInput, type PlatformFingerprint, type PlatformSignatureDef, type PollRegistrationResult, type ProtocolTransport, RUNTIME_SIGNATURES, type RegisterOptions, type RegisterResult, RegistrationDeniedError, RegistrationExpiredError, type RegistrationResponse, RegistrationTimeoutError, type ReportAttemptOptions, type RouteAccessConfig, type RuntimeChallengeResult, type RuntimeSignature, type SDKOptions, SDK_USER_AGENT, type SanitizeHeadersResult, type SettlementArtifact, type SettlementArtifactBinding, type SettlementArtifactBindingBase, type SettlementDecision, type SettlementOutcomeInfo, type SettlementRequest, type StablecoinSettlementBinding, type StepUpApprovalInfo, type StepUpApprovalStatus, type StepUpOutcome, TRUST_LEVEL_RANGES, type TokenGuidance, type ToolGate, type ToolGateConfig, type TrustLevel, VERIFICATION_STATUS_HEADER, SDK_VERSION as VERSION, type VerificationInterstitialProps, type VerificationRequest, type VerificationResult, type VerifiedAgent, type VerifiedDeveloper, type VerifiedHopMarker, type VerifiedOrganization, type VerifyOptions, type VerifyResponse, type WaitForApprovalOptions, type WellKnownAgenticCommerce, _resetEdgeConfigCache, index as agent, authorizeSettlement, awaitStepUpApproval, buildGuidance, buildSdkObservedMetadata, buildVerificationUnavailableBody, clearCache, createMcpMiddleware, degradeToObserve, denyStatusFor, deriveConnectionFromHeaders, detectPlatformFingerprint, detectRuntime, express, extractApiKeyFormat, extractCredentials, extractMcpCredentials, extractPlatformHeaders, fetchEdgeConfig, fetchRoutes, getCachedWellKnownUrls, getEdgeConfig, getTrustLevel, getWellKnownUrls, hasCredentials, isEdgeConfig, isRejectedIdentityClaim, isVerificationUnavailable, isVerifiedHopValidFor, matchEdgePathRule, matchPlatformSignature, nextjs, normalizeDeclaredSource, parseYaml as parseLocalPolicyYaml, parseVerifiedHop, pollStepUpStatus, prefetchWellKnown, quickVerify, recordDecision, reportAttempt, reportUnregisteredAttempt, sanitizeHeaders, sdk, sdkFetch, serializeVerifiedHop, setMcpMeta, index$1 as transport, unavailableRetryAfterSeconds, validatePolicy as validateLocalPolicy, verify };
package/dist/index.js CHANGED
@@ -122,7 +122,7 @@ function getTrustLevel(score) {
122
122
  }
123
123
 
124
124
  // src/version.ts
125
- var SDK_VERSION = "5.12.0";
125
+ var SDK_VERSION = "5.14.0";
126
126
 
127
127
  // src/http.ts
128
128
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -266,7 +266,7 @@ var DEFAULT_CONFIG = {
266
266
  };
267
267
  var initCheckPerformed = false;
268
268
  var deprecationWarningShown = false;
269
- async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
269
+ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey, counterparty) {
270
270
  initCheckPerformed = true;
271
271
  try {
272
272
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
@@ -284,7 +284,8 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
284
284
  );
285
285
  }
286
286
  if (apiKey) {
287
- const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
287
+ const q = counterparty?.id ? `?counterpartyId=${encodeURIComponent(counterparty.id)}` : counterparty?.url ? `?counterpartyUrl=${encodeURIComponent(counterparty.url)}` : "";
288
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check${q}`, {
288
289
  headers: { Authorization: `Bearer ${apiKey}` }
289
290
  });
290
291
  if (selfCheck.status === 401) {
@@ -296,6 +297,13 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
296
297
  console.error(message);
297
298
  } else if (selfCheck.ok) {
298
299
  const body = await selfCheck.json().catch(() => ({}));
300
+ if (body.counterparty && body.counterparty.canVerify === false) {
301
+ const message = `[VerificationGateway] the configured AstraSync API key cannot verify for this endpoint (${body.counterparty.message ?? "endpoint not found or owned by another account"}). Every inbound agent will be turned away until the key or counterparty is corrected.`;
302
+ if (strictInit) {
303
+ throw new Error(`${message} (strictInit=true)`);
304
+ }
305
+ console.error(message);
306
+ }
299
307
  if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
300
308
  console.warn(
301
309
  `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
@@ -440,11 +448,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
440
448
  const isMisconfig = source === "merchant_misconfig";
441
449
  const urls = options.urls;
442
450
  const guidance = isMisconfig ? {
443
- message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
451
+ message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, rotated, or belongs to another account). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
444
452
  registrationUrl: urls?.registrationUrl ?? "",
445
453
  documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
446
454
  steps: [
447
- "Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
455
+ "Report the failure to the site operator \u2014 their AstraSync API key needs replacing",
448
456
  "Do not retry: the failure is deterministic until the operator updates their key"
449
457
  ]
450
458
  } : isApiError ? {
@@ -656,12 +664,13 @@ async function callVerifyAccessAPI(config, request) {
656
664
  };
657
665
  }
658
666
  if (!response.ok) {
659
- if (response.status === 401) {
667
+ const keyMismatch = response.status === 403 && data?.error === "COUNTERPARTY_KEY_MISMATCH";
668
+ if (response.status === 401 || keyMismatch) {
660
669
  return {
661
670
  success: false,
662
671
  error: data.message || data.error || "Integration API key rejected",
663
672
  misconfig: true,
664
- misconfigCode: typeof data?.code === "string" ? data.code : void 0,
673
+ misconfigCode: keyMismatch ? "counterparty_key_mismatch" : typeof data?.code === "string" ? data.code : void 0,
665
674
  remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
666
675
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
667
676
  attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
@@ -694,14 +703,22 @@ async function verify(config, request, options) {
694
703
  mergedConfig.apiBaseUrl,
695
704
  mergedConfig.debug,
696
705
  true,
697
- mergedConfig.apiKey
706
+ mergedConfig.apiKey,
707
+ {
708
+ id: mergedConfig.counterpartyId,
709
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
710
+ }
698
711
  );
699
712
  } else {
700
713
  void performInitCheck(
701
714
  mergedConfig.apiBaseUrl,
702
715
  mergedConfig.debug,
703
716
  false,
704
- mergedConfig.apiKey
717
+ mergedConfig.apiKey,
718
+ {
719
+ id: mergedConfig.counterpartyId,
720
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
721
+ }
705
722
  );
706
723
  }
707
724
  }
@@ -932,6 +949,7 @@ async function reportAttempt(config, report, options = {}) {
932
949
  timer.unref?.();
933
950
  }
934
951
  var ATTEMPT_REPORT_MAX_RETRY_DELAY_MS = 2e3;
952
+ var refusedPolicyReads = /* @__PURE__ */ new Set();
935
953
  async function fetchRoutes(config, counterpartyId) {
936
954
  if (!counterpartyId) return null;
937
955
  const headers = { "Content-Type": "application/json" };
@@ -944,7 +962,15 @@ async function fetchRoutes(config, counterpartyId) {
944
962
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
945
963
  { method: "GET", headers }
946
964
  );
947
- if (!response.ok) return null;
965
+ if (!response.ok) {
966
+ if ((response.status === 401 || response.status === 403 || response.status === 404) && !refusedPolicyReads.has(counterpartyId)) {
967
+ refusedPolicyReads.add(counterpartyId);
968
+ console.error(
969
+ `[VerificationGateway] the configured API key cannot read the route policy for ${counterpartyId} (HTTP ${response.status}). The key belongs to an account that does not own this endpoint, or the counterpartyId is wrong. The gateway is in PASS-THROUGH mode: no agent is being verified.`
970
+ );
971
+ }
972
+ return null;
973
+ }
948
974
  const body = await response.json();
949
975
  return body.data?.routes ?? [];
950
976
  } catch {
@@ -1891,6 +1917,11 @@ async function withBudget(promise, ms) {
1891
1917
  if (timer) clearTimeout(timer);
1892
1918
  }
1893
1919
  }
1920
+ var CONTAINER_ID = (() => {
1921
+ const c = globalThis.crypto;
1922
+ if (c?.randomUUID) return c.randomUUID();
1923
+ return `c-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
1924
+ })();
1894
1925
  var destKeyOf = (d) => `${d.apiBaseUrl}\0${d.apiKey ?? ""}\0${d.counterparty}\0${d.adapter ?? ""}`;
1895
1926
  var BeaconBuffer = class {
1896
1927
  constructor(options = {}) {
@@ -1898,6 +1929,7 @@ var BeaconBuffer = class {
1898
1929
  this.droppedSinceLast = 0;
1899
1930
  this.droppedTotal = 0;
1900
1931
  this.deliveredTotal = 0;
1932
+ this.enqueuedTotal = 0;
1901
1933
  this.backoffUntil = 0;
1902
1934
  this.collapse = /* @__PURE__ */ new Map();
1903
1935
  /** Keys the backend answered 401 for — later batches go unauthenticated. */
@@ -1910,13 +1942,16 @@ var BeaconBuffer = class {
1910
1942
  collapseMaxKeys: options.collapseMaxKeys ?? 1e3,
1911
1943
  requestTimeoutMs: options.requestTimeoutMs ?? 1e4,
1912
1944
  retryBackoffMs: options.retryBackoffMs ?? 1e3,
1945
+ holdRepeats: options.holdRepeats ?? false,
1946
+ containerId: options.containerId ?? CONTAINER_ID,
1913
1947
  now: options.now ?? Date.now
1914
1948
  };
1915
1949
  }
1916
1950
  /**
1917
1951
  * Queue one beacon. With a `collapseKey`, a repeat inside the window is
1918
- * merged into a held aggregate (sent when the window closes) instead of
1919
- * becoming its own item.
1952
+ * merged into this key's item while that item is still queued (not yet in
1953
+ * flight). Once it has left, the repeat becomes a new item, sendable on
1954
+ * this flush — nothing waits for a later invocation (round 27.6).
1920
1955
  */
1921
1956
  enqueue(dest, item, collapseKey) {
1922
1957
  const now = this.opts.now();
@@ -1929,12 +1964,15 @@ var BeaconBuffer = class {
1929
1964
  return;
1930
1965
  }
1931
1966
  }
1932
- const held = this.push(
1933
- dest,
1934
- { ...item, repeatCount: 1 },
1935
- entry.firstSeenAt + this.opts.collapseWindowMs
1936
- );
1937
- entry.held = held;
1967
+ if (this.opts.holdRepeats) {
1968
+ entry.held = this.push(
1969
+ dest,
1970
+ { ...item, repeatCount: 1 },
1971
+ entry.firstSeenAt + this.opts.collapseWindowMs
1972
+ );
1973
+ return;
1974
+ }
1975
+ entry.first = this.push(dest, { ...item, repeatCount: 1 }, now);
1938
1976
  return;
1939
1977
  }
1940
1978
  this.collapse.delete(collapseKey);
@@ -1970,6 +2008,7 @@ var BeaconBuffer = class {
1970
2008
  droppedSinceLast: this.droppedSinceLast,
1971
2009
  droppedTotal: this.droppedTotal,
1972
2010
  deliveredTotal: this.deliveredTotal,
2011
+ enqueuedTotal: this.enqueuedTotal,
1973
2012
  flushing: this.inFlight !== void 0
1974
2013
  };
1975
2014
  }
@@ -1984,6 +2023,7 @@ var BeaconBuffer = class {
1984
2023
  inFlight: false
1985
2024
  };
1986
2025
  this.queue.push(entry);
2026
+ this.enqueuedTotal += 1;
1987
2027
  return entry;
1988
2028
  }
1989
2029
  dropOldest() {
@@ -2029,7 +2069,11 @@ var BeaconBuffer = class {
2029
2069
  droppedSinceLast: reportedDropped,
2030
2070
  queueDepth: this.queue.length,
2031
2071
  adapter: dest.adapter ?? "edge-core",
2032
- version: SDK_VERSION
2072
+ version: SDK_VERSION,
2073
+ containerId: this.opts.containerId,
2074
+ enqueuedTotal: this.enqueuedTotal,
2075
+ deliveredTotal: this.deliveredTotal,
2076
+ droppedTotal: this.droppedTotal
2033
2077
  };
2034
2078
  const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
2035
2079
  const response = await withBudget(