@astrasyncai/verification-gateway 5.11.0 → 5.12.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 (98) hide show
  1. package/README.md +4 -0
  2. package/dist/adapters/express.d.mts +1 -1
  3. package/dist/adapters/express.d.ts +1 -1
  4. package/dist/adapters/express.js +359 -30
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +359 -30
  7. package/dist/adapters/express.mjs.map +1 -1
  8. package/dist/adapters/mcp.d.mts +5 -1
  9. package/dist/adapters/mcp.d.ts +5 -1
  10. package/dist/adapters/mcp.js +168 -41
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +168 -41
  13. package/dist/adapters/mcp.mjs.map +1 -1
  14. package/dist/adapters/nextjs.d.mts +1 -1
  15. package/dist/adapters/nextjs.d.ts +1 -1
  16. package/dist/adapters/nextjs.js +352 -13
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +352 -13
  19. package/dist/adapters/nextjs.mjs.map +1 -1
  20. package/dist/adapters/sdk.d.mts +9 -1
  21. package/dist/adapters/sdk.d.ts +9 -1
  22. package/dist/adapters/sdk.js +100 -8
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +100 -8
  25. package/dist/adapters/sdk.mjs.map +1 -1
  26. package/dist/agent/index.js +1 -1
  27. package/dist/agent/index.js.map +1 -1
  28. package/dist/agent/index.mjs +1 -1
  29. package/dist/agent/index.mjs.map +1 -1
  30. package/dist/bin/astrasync-claude-hook.js +284 -7
  31. package/dist/bin/astrasync-codex-hook.js +284 -7
  32. package/dist/bin/astrasync-guard.js +284 -7
  33. package/dist/bin/astrasync.js +297 -9
  34. package/dist/browser/background.js +284 -7
  35. package/dist/browser/background.js.map +1 -1
  36. package/dist/browser/background.mjs +284 -7
  37. package/dist/browser/background.mjs.map +1 -1
  38. package/dist/cli/index.js +1 -1
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/index.mjs +1 -1
  41. package/dist/cli/index.mjs.map +1 -1
  42. package/dist/codex/index.js +284 -7
  43. package/dist/codex/index.js.map +1 -1
  44. package/dist/codex/index.mjs +284 -7
  45. package/dist/codex/index.mjs.map +1 -1
  46. package/dist/cursor/extension.js +284 -7
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +284 -7
  49. package/dist/cursor/extension.mjs.map +1 -1
  50. package/dist/edge-config.d.mts +1 -1
  51. package/dist/edge-config.d.ts +1 -1
  52. package/dist/edge-config.js +1 -1
  53. package/dist/edge-config.js.map +1 -1
  54. package/dist/edge-config.mjs +1 -1
  55. package/dist/edge-config.mjs.map +1 -1
  56. package/dist/edge-core/index.d.mts +128 -13
  57. package/dist/edge-core/index.d.ts +128 -13
  58. package/dist/edge-core/index.js +337 -55
  59. package/dist/edge-core/index.js.map +1 -1
  60. package/dist/edge-core/index.mjs +334 -55
  61. package/dist/edge-core/index.mjs.map +1 -1
  62. package/dist/gateway/gateway.js +284 -7
  63. package/dist/gateway/gateway.js.map +1 -1
  64. package/dist/gateway/gateway.mjs +284 -7
  65. package/dist/gateway/gateway.mjs.map +1 -1
  66. package/dist/git-trigger/git-hooks.d.mts +1 -1
  67. package/dist/git-trigger/git-hooks.d.ts +1 -1
  68. package/dist/index.d.mts +118 -5
  69. package/dist/index.d.ts +118 -5
  70. package/dist/index.js +486 -63
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +480 -63
  73. package/dist/index.mjs.map +1 -1
  74. package/dist/platform-signatures.js +4 -1
  75. package/dist/platform-signatures.js.map +1 -1
  76. package/dist/platform-signatures.mjs +4 -1
  77. package/dist/platform-signatures.mjs.map +1 -1
  78. package/dist/registration/index.js +1 -1
  79. package/dist/registration/index.js.map +1 -1
  80. package/dist/registration/index.mjs +1 -1
  81. package/dist/registration/index.mjs.map +1 -1
  82. package/dist/transport/index.js +1 -1
  83. package/dist/transport/index.js.map +1 -1
  84. package/dist/transport/index.mjs +1 -1
  85. package/dist/transport/index.mjs.map +1 -1
  86. package/dist/{types-CTmUpNpS.d.mts → types-BCkwBA84.d.mts} +12 -0
  87. package/dist/{types-CTmUpNpS.d.ts → types-BCkwBA84.d.ts} +12 -0
  88. package/dist/{types-CtFXmDzm.d.ts → types-C_b4QTyO.d.ts} +18 -0
  89. package/dist/{types-DQrn_kei.d.mts → types-DlshIIR-.d.mts} +18 -0
  90. package/dist/ui/index.d.mts +1 -1
  91. package/dist/ui/index.d.ts +1 -1
  92. package/dist/verify.d.mts +35 -4
  93. package/dist/verify.d.ts +35 -4
  94. package/dist/verify.js +130 -16
  95. package/dist/verify.js.map +1 -1
  96. package/dist/verify.mjs +129 -16
  97. package/dist/verify.mjs.map +1 -1
  98. package/package.json +1 -1
@@ -36,7 +36,7 @@ var SDK_VERSION;
36
36
  var init_version = __esm({
37
37
  "src/version.ts"() {
38
38
  "use strict";
39
- SDK_VERSION = "5.11.0";
39
+ SDK_VERSION = "5.12.0";
40
40
  }
41
41
  });
42
42
 
@@ -5057,6 +5057,20 @@ var init_well_known = __esm({
5057
5057
  }
5058
5058
  });
5059
5059
 
5060
+ // src/failure-posture.ts
5061
+ var REJECTED_IDENTITY_DIMENSIONS, UNKNOWN_AGENT_GUIDANCE;
5062
+ var init_failure_posture = __esm({
5063
+ "src/failure-posture.ts"() {
5064
+ "use strict";
5065
+ REJECTED_IDENTITY_DIMENSIONS = /* @__PURE__ */ new Set([
5066
+ "identity.invalid_agent_id",
5067
+ "identity.unknown_agent",
5068
+ "agent.lookup"
5069
+ ]);
5070
+ UNKNOWN_AGENT_GUIDANCE = "Register your agent with AstraSync (or, inside an MCP host, add the AstraSync MCP connector for keyless, human-approved registration), then present the canonical ASTRA-* id issued after owner approval.";
5071
+ }
5072
+ });
5073
+
5060
5074
  // src/verify.ts
5061
5075
  async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
5062
5076
  initCheckPerformed = true;
@@ -5255,11 +5269,43 @@ function createGuidanceResponse(_config, reason, options = {}) {
5255
5269
  // coercing the absent recommendation to a policy 'deny'. Misconfig is
5256
5270
  // deterministic and intentionally NOT marked retryable.
5257
5271
  ...isApiError && { retryable: true },
5272
+ ...options.httpStatus !== void 0 && { httpStatus: options.httpStatus },
5273
+ ...options.retryAfterMs !== void 0 && { retryAfterMs: options.retryAfterMs },
5258
5274
  correlationId: options.correlationId,
5259
5275
  attemptId: options.attemptId,
5260
5276
  verifiedAt: /* @__PURE__ */ new Date()
5261
5277
  };
5262
5278
  }
5279
+ async function readJsonSafe(response) {
5280
+ try {
5281
+ const parsed = await response.json();
5282
+ return parsed && typeof parsed === "object" ? parsed : {};
5283
+ } catch {
5284
+ return {};
5285
+ }
5286
+ }
5287
+ function rejectedIdentityGuidance(failures) {
5288
+ const f = failures?.find((x) => REJECTED_IDENTITY_DIMENSIONS.has(x.dimension));
5289
+ if (!f) return void 0;
5290
+ if (f.dimension === "agent.lookup") {
5291
+ return `The presented agent identifier is not registered with AstraSync. ${UNKNOWN_AGENT_GUIDANCE}`;
5292
+ }
5293
+ return f.guidance ? `${f.message} ${f.guidance}` : f.message;
5294
+ }
5295
+ function parseRetryAfterMs(response) {
5296
+ const raw = response.headers?.get?.("retry-after");
5297
+ if (!raw) return void 0;
5298
+ const trimmed = raw.trim();
5299
+ let ms;
5300
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
5301
+ ms = Number(trimmed) * 1e3;
5302
+ } else {
5303
+ const at = Date.parse(trimmed);
5304
+ if (Number.isNaN(at)) return void 0;
5305
+ ms = at - Date.now();
5306
+ }
5307
+ return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, Math.round(ms)));
5308
+ }
5263
5309
  async function callVerifyAccessAPI(config, request2) {
5264
5310
  const { credentials, ...requestData } = request2;
5265
5311
  const body = {
@@ -5316,7 +5362,8 @@ async function callVerifyAccessAPI(config, request2) {
5316
5362
  body: JSON.stringify(body),
5317
5363
  signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
5318
5364
  });
5319
- const data = await response.json();
5365
+ const data = await readJsonSafe(response);
5366
+ const retryAfterMs = parseRetryAfterMs(response);
5320
5367
  if (response.status === 410) {
5321
5368
  return {
5322
5369
  success: true,
@@ -5354,6 +5401,23 @@ async function callVerifyAccessAPI(config, request2) {
5354
5401
  }
5355
5402
  };
5356
5403
  }
5404
+ if (response.status === 404 && credentials.astraId && (data?.error === "AGENT_NOT_FOUND" || typeof data?.message === "string" && /agent/i.test(data.message))) {
5405
+ return {
5406
+ success: true,
5407
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
5408
+ access: {
5409
+ allowed: false,
5410
+ reason: "unknown_agent",
5411
+ failures: [
5412
+ {
5413
+ dimension: "identity.unknown_agent",
5414
+ message: "The presented agent identifier is not registered with AstraSync.",
5415
+ guidance: UNKNOWN_AGENT_GUIDANCE
5416
+ }
5417
+ ]
5418
+ }
5419
+ };
5420
+ }
5357
5421
  if (!response.ok) {
5358
5422
  if (response.status === 401) {
5359
5423
  return {
@@ -5368,9 +5432,11 @@ async function callVerifyAccessAPI(config, request2) {
5368
5432
  }
5369
5433
  return {
5370
5434
  success: false,
5371
- error: data.message || data.error || `API returned ${response.status}`,
5435
+ error: typeof data?.message === "string" && data.message || typeof data?.error === "string" && data.error || `API returned ${response.status}`,
5372
5436
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
5373
- attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
5437
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
5438
+ httpStatus: response.status,
5439
+ ...retryAfterMs !== void 0 && { retryAfterMs }
5374
5440
  };
5375
5441
  }
5376
5442
  return data;
@@ -5442,12 +5508,14 @@ async function verify(config, request2, options) {
5442
5508
  correlationId: apiResponse.correlationId,
5443
5509
  attemptId: apiResponse.attemptId,
5444
5510
  remediation: apiResponse.remediation,
5511
+ httpStatus: apiResponse.httpStatus,
5512
+ retryAfterMs: apiResponse.retryAfterMs,
5445
5513
  urls
5446
5514
  });
5447
5515
  }
5448
5516
  if (!apiResponse.access?.allowed) {
5449
5517
  const aggregatedFailures = apiResponse.access?.failures;
5450
- const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true;
5518
+ const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
5451
5519
  const result2 = {
5452
5520
  identityVerified: idVerifiedFromBackend,
5453
5521
  policyAllowed: false,
@@ -5459,7 +5527,10 @@ async function verify(config, request2, options) {
5459
5527
  requiresStepUp: apiResponse.access?.requiresStepUp,
5460
5528
  requiresApproval: apiResponse.access?.requiresApproval,
5461
5529
  guidance: {
5462
- message: apiResponse.access?.reason || "Access denied by PDLSS policy",
5530
+ // 5.12.0: a presented-but-rejected id (malformed / unknown) carries
5531
+ // actionable registration guidance on its failure — surface it
5532
+ // instead of the bare machine reason ('unknown_agent').
5533
+ message: rejectedIdentityGuidance(aggregatedFailures) ?? (apiResponse.access?.reason || "Access denied by PDLSS policy"),
5463
5534
  registrationUrl: urls?.registrationUrl ?? "",
5464
5535
  documentationUrl: urls?.documentationUrl ?? "",
5465
5536
  // 5.1.0: anonymous callers land on this branch — steer MCP-hosted
@@ -5559,7 +5630,7 @@ async function verify(config, request2, options) {
5559
5630
  registrationUrl: urls?.registrationUrl ?? "",
5560
5631
  documentationUrl: urls?.documentationUrl ?? ""
5561
5632
  };
5562
- } else if (result.recommendation === "step_up_required") {
5633
+ } else if (result.recommendation === "step_up_required" && result.identityVerified) {
5563
5634
  result.requiresStepUp = true;
5564
5635
  result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
5565
5636
  }
@@ -5569,7 +5640,7 @@ async function verify(config, request2, options) {
5569
5640
  }
5570
5641
  return result;
5571
5642
  }
5572
- var DEFAULT_CONFIG, initCheckPerformed, deprecationWarningShown, verificationCache, DEFAULT_CACHE_TTL_SECONDS;
5643
+ var DEFAULT_CONFIG, initCheckPerformed, deprecationWarningShown, verificationCache, DEFAULT_CACHE_TTL_SECONDS, MAX_RETRY_AFTER_MS;
5573
5644
  var init_verify = __esm({
5574
5645
  "src/verify.ts"() {
5575
5646
  "use strict";
@@ -5577,6 +5648,7 @@ var init_verify = __esm({
5577
5648
  init_trust_levels();
5578
5649
  init_version();
5579
5650
  init_well_known();
5651
+ init_failure_posture();
5580
5652
  DEFAULT_CONFIG = {
5581
5653
  apiBaseUrl: "https://astrasync.ai/api",
5582
5654
  // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
@@ -5590,6 +5662,7 @@ var init_verify = __esm({
5590
5662
  deprecationWarningShown = false;
5591
5663
  verificationCache = /* @__PURE__ */ new Map();
5592
5664
  DEFAULT_CACHE_TTL_SECONDS = 60;
5665
+ MAX_RETRY_AFTER_MS = 15 * 60 * 1e3;
5593
5666
  }
5594
5667
  });
5595
5668
 
@@ -5712,12 +5785,223 @@ var init_classify = __esm({
5712
5785
  });
5713
5786
 
5714
5787
  // src/edge-core/events.ts
5788
+ async function withBudget(promise, ms) {
5789
+ let timer;
5790
+ try {
5791
+ return await Promise.race([
5792
+ promise,
5793
+ new Promise((resolve) => {
5794
+ timer = setTimeout(() => resolve(void 0), ms);
5795
+ })
5796
+ ]);
5797
+ } catch {
5798
+ return void 0;
5799
+ } finally {
5800
+ if (timer) clearTimeout(timer);
5801
+ }
5802
+ }
5803
+ var destKeyOf, BeaconBuffer, beaconBuffer;
5715
5804
  var init_events = __esm({
5716
5805
  "src/edge-core/events.ts"() {
5717
5806
  "use strict";
5807
+ init_http();
5718
5808
  init_metadata_capture();
5719
- init_verify();
5809
+ init_version();
5720
5810
  init_request();
5811
+ destKeyOf = (d) => `${d.apiBaseUrl}\0${d.apiKey ?? ""}\0${d.counterparty}\0${d.adapter ?? ""}`;
5812
+ BeaconBuffer = class {
5813
+ constructor(options = {}) {
5814
+ this.queue = [];
5815
+ this.droppedSinceLast = 0;
5816
+ this.droppedTotal = 0;
5817
+ this.deliveredTotal = 0;
5818
+ this.backoffUntil = 0;
5819
+ this.collapse = /* @__PURE__ */ new Map();
5820
+ /** Keys the backend answered 401 for — later batches go unauthenticated. */
5821
+ this.rejectedKeys = /* @__PURE__ */ new Set();
5822
+ this.opts = {
5823
+ maxItems: options.maxItems ?? 1e3,
5824
+ maxBatch: options.maxBatch ?? 100,
5825
+ maxAttempts: options.maxAttempts ?? 3,
5826
+ collapseWindowMs: options.collapseWindowMs ?? 6e4,
5827
+ collapseMaxKeys: options.collapseMaxKeys ?? 1e3,
5828
+ requestTimeoutMs: options.requestTimeoutMs ?? 1e4,
5829
+ retryBackoffMs: options.retryBackoffMs ?? 1e3,
5830
+ now: options.now ?? Date.now
5831
+ };
5832
+ }
5833
+ /**
5834
+ * Queue one beacon. With a `collapseKey`, a repeat inside the window is
5835
+ * merged into a held aggregate (sent when the window closes) instead of
5836
+ * becoming its own item.
5837
+ */
5838
+ enqueue(dest, item, collapseKey) {
5839
+ const now = this.opts.now();
5840
+ if (collapseKey) {
5841
+ const entry = this.collapse.get(collapseKey);
5842
+ if (entry && now - entry.firstSeenAt < this.opts.collapseWindowMs) {
5843
+ for (const target of [entry.first, entry.held]) {
5844
+ if (target && !target.inFlight && this.queue.includes(target)) {
5845
+ target.item.repeatCount = (target.item.repeatCount ?? 1) + 1;
5846
+ return;
5847
+ }
5848
+ }
5849
+ const held = this.push(
5850
+ dest,
5851
+ { ...item, repeatCount: 1 },
5852
+ entry.firstSeenAt + this.opts.collapseWindowMs
5853
+ );
5854
+ entry.held = held;
5855
+ return;
5856
+ }
5857
+ this.collapse.delete(collapseKey);
5858
+ if (this.collapse.size >= this.opts.collapseMaxKeys) {
5859
+ const oldest = this.collapse.keys().next().value;
5860
+ if (oldest !== void 0) this.collapse.delete(oldest);
5861
+ }
5862
+ const fresh = { firstSeenAt: now };
5863
+ this.collapse.set(collapseKey, fresh);
5864
+ fresh.first = this.push(dest, item, now);
5865
+ return;
5866
+ }
5867
+ this.push(dest, item, now);
5868
+ }
5869
+ /**
5870
+ * Deliver every eligible queued item. Concurrent callers share ONE
5871
+ * in-flight drain (it survives the caller's budget and a Lambda freeze),
5872
+ * so nothing in flight is ever sent twice; items queued while it runs are
5873
+ * picked up by the same drain.
5874
+ */
5875
+ flush() {
5876
+ if (!this.inFlight) {
5877
+ this.inFlight = this.drain().finally(() => {
5878
+ this.inFlight = void 0;
5879
+ });
5880
+ }
5881
+ return this.inFlight;
5882
+ }
5883
+ /** Counters for tests and diagnostics. */
5884
+ stats() {
5885
+ return {
5886
+ queueDepth: this.queue.length,
5887
+ droppedSinceLast: this.droppedSinceLast,
5888
+ droppedTotal: this.droppedTotal,
5889
+ deliveredTotal: this.deliveredTotal,
5890
+ flushing: this.inFlight !== void 0
5891
+ };
5892
+ }
5893
+ push(dest, item, eligibleAt) {
5894
+ while (this.queue.length >= this.opts.maxItems) this.dropOldest();
5895
+ const entry = {
5896
+ dest,
5897
+ destKey: destKeyOf(dest),
5898
+ item,
5899
+ attempts: 0,
5900
+ eligibleAt,
5901
+ inFlight: false
5902
+ };
5903
+ this.queue.push(entry);
5904
+ return entry;
5905
+ }
5906
+ dropOldest() {
5907
+ if (this.queue.shift()) this.countDropped(1);
5908
+ }
5909
+ countDropped(n) {
5910
+ this.droppedSinceLast += n;
5911
+ this.droppedTotal += n;
5912
+ }
5913
+ async drain() {
5914
+ for (; ; ) {
5915
+ const now = this.opts.now();
5916
+ if (now < this.backoffUntil) return;
5917
+ const batch = this.takeBatch(now);
5918
+ if (batch.length === 0) return;
5919
+ const ok = await this.send(batch);
5920
+ if (!ok) return;
5921
+ }
5922
+ }
5923
+ /** Oldest eligible item + up to maxBatch-1 more for the same destination. */
5924
+ takeBatch(now) {
5925
+ const first = this.queue.find((q) => q.eligibleAt <= now);
5926
+ if (!first) return [];
5927
+ const batch = [];
5928
+ const rest = [];
5929
+ for (const q of this.queue) {
5930
+ if (batch.length < this.opts.maxBatch && q.destKey === first.destKey && q.eligibleAt <= now) {
5931
+ q.inFlight = true;
5932
+ batch.push(q);
5933
+ } else {
5934
+ rest.push(q);
5935
+ }
5936
+ }
5937
+ this.queue = rest;
5938
+ return batch;
5939
+ }
5940
+ /** POST one batch. Returns false when the drain should pause (backoff). */
5941
+ async send(batch) {
5942
+ const dest = batch[0].dest;
5943
+ const useKey = dest.apiKey && !this.rejectedKeys.has(dest.apiKey) ? dest.apiKey : void 0;
5944
+ const reportedDropped = this.droppedSinceLast;
5945
+ const meta = {
5946
+ droppedSinceLast: reportedDropped,
5947
+ queueDepth: this.queue.length,
5948
+ adapter: dest.adapter ?? "edge-core",
5949
+ version: SDK_VERSION
5950
+ };
5951
+ const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
5952
+ const response = await withBudget(
5953
+ sdkFetch(`${dest.apiBaseUrl}/verification-activity/edge-events`, {
5954
+ method: "POST",
5955
+ headers: {
5956
+ "Content-Type": "application/json",
5957
+ ...useKey && { Authorization: `Bearer ${useKey}` }
5958
+ },
5959
+ body: JSON.stringify({ events: batch.map((q) => q.item), meta }),
5960
+ ...controller && { signal: controller.signal }
5961
+ }),
5962
+ this.opts.requestTimeoutMs
5963
+ );
5964
+ if (!response) controller?.abort();
5965
+ const status = response?.status;
5966
+ for (const q of batch) q.inFlight = false;
5967
+ if (status !== void 0 && status >= 200 && status < 300) {
5968
+ this.droppedSinceLast = Math.max(0, this.droppedSinceLast - reportedDropped);
5969
+ this.deliveredTotal += batch.length;
5970
+ return true;
5971
+ }
5972
+ if (status === 401 && useKey) {
5973
+ this.rejectedKeys.add(useKey);
5974
+ this.requeue(batch, false);
5975
+ return true;
5976
+ }
5977
+ if (status === 429) {
5978
+ const retryAfter = Number(response?.headers.get("retry-after"));
5979
+ const waitMs = Number.isFinite(retryAfter) && retryAfter > 0 ? Math.min(retryAfter, 120) * 1e3 : 3e4;
5980
+ this.backoffUntil = this.opts.now() + waitMs;
5981
+ this.requeue(batch, false);
5982
+ return false;
5983
+ }
5984
+ if (status !== void 0 && status >= 400 && status < 500) {
5985
+ this.countDropped(batch.length);
5986
+ return true;
5987
+ }
5988
+ this.backoffUntil = this.opts.now() + this.opts.retryBackoffMs;
5989
+ this.requeue(batch, true);
5990
+ return false;
5991
+ }
5992
+ /** Put a failed batch back at the head of the queue (order preserved). */
5993
+ requeue(batch, countAttempt) {
5994
+ const keep = [];
5995
+ for (const q of batch) {
5996
+ if (countAttempt) q.attempts += 1;
5997
+ if (q.attempts >= this.opts.maxAttempts) this.countDropped(1);
5998
+ else keep.push(q);
5999
+ }
6000
+ this.queue = [...keep, ...this.queue];
6001
+ while (this.queue.length > this.opts.maxItems) this.dropOldest();
6002
+ }
6003
+ };
6004
+ beaconBuffer = new BeaconBuffer();
5721
6005
  }
5722
6006
  });
5723
6007
 
@@ -5749,6 +6033,7 @@ var init_express = __esm({
5749
6033
  init_well_known();
5750
6034
  init_metadata_capture();
5751
6035
  init_anonymous_beacon();
6036
+ init_failure_posture();
5752
6037
  DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
5753
6038
  }
5754
6039
  });
@@ -5764,6 +6049,7 @@ var init_nextjs = __esm({
5764
6049
  init_pdlss_pre_check();
5765
6050
  init_metadata_capture();
5766
6051
  init_anonymous_beacon();
6052
+ init_failure_posture();
5767
6053
  init_http_pdlss();
5768
6054
  init_approval_gate();
5769
6055
  init_verified_hop();
@@ -6085,6 +6371,7 @@ var init_mcp2 = __esm({
6085
6371
  init_approval_gate();
6086
6372
  init_stepup_poll();
6087
6373
  init_well_known();
6374
+ init_failure_posture();
6088
6375
  init_mcp_server();
6089
6376
  }
6090
6377
  });
@@ -6173,6 +6460,7 @@ var init_src = __esm({
6173
6460
  "use strict";
6174
6461
  init_trust_levels();
6175
6462
  init_verify();
6463
+ init_failure_posture();
6176
6464
  init_stepup_poll();
6177
6465
  init_settlement();
6178
6466
  init_express();