@astrasyncai/verification-gateway 4.5.1 → 4.6.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 (134) hide show
  1. package/README.md +1 -1
  2. package/dist/adapter-interface/interface.d.mts +2 -2
  3. package/dist/adapter-interface/interface.d.ts +2 -2
  4. package/dist/adapters/express.d.mts +2 -2
  5. package/dist/adapters/express.d.ts +2 -2
  6. package/dist/adapters/express.js +6 -1
  7. package/dist/adapters/express.js.map +1 -1
  8. package/dist/adapters/express.mjs +6 -1
  9. package/dist/adapters/express.mjs.map +1 -1
  10. package/dist/adapters/mcp.d.mts +2 -2
  11. package/dist/adapters/mcp.d.ts +2 -2
  12. package/dist/adapters/mcp.js +6 -1
  13. package/dist/adapters/mcp.js.map +1 -1
  14. package/dist/adapters/mcp.mjs +6 -1
  15. package/dist/adapters/mcp.mjs.map +1 -1
  16. package/dist/adapters/nextjs.d.mts +2 -2
  17. package/dist/adapters/nextjs.d.ts +2 -2
  18. package/dist/adapters/nextjs.js +6 -1
  19. package/dist/adapters/nextjs.js.map +1 -1
  20. package/dist/adapters/nextjs.mjs +6 -1
  21. package/dist/adapters/nextjs.mjs.map +1 -1
  22. package/dist/adapters/sdk.d.mts +2 -2
  23. package/dist/adapters/sdk.d.ts +2 -2
  24. package/dist/adapters/sdk.js +6 -1
  25. package/dist/adapters/sdk.js.map +1 -1
  26. package/dist/adapters/sdk.mjs +6 -1
  27. package/dist/adapters/sdk.mjs.map +1 -1
  28. package/dist/agent/index.d.mts +2 -2
  29. package/dist/agent/index.d.ts +2 -2
  30. package/dist/agent/index.js +1 -1
  31. package/dist/agent/index.js.map +1 -1
  32. package/dist/agent/index.mjs +1 -1
  33. package/dist/agent/index.mjs.map +1 -1
  34. package/dist/bin/astrasync-claude-hook.js +60 -13
  35. package/dist/bin/astrasync-codex-hook.js +60 -13
  36. package/dist/bin/astrasync-guard.js +60 -13
  37. package/dist/bin/astrasync.js +67 -15
  38. package/dist/browser/background.js +60 -13
  39. package/dist/browser/background.js.map +1 -1
  40. package/dist/browser/background.mjs +60 -13
  41. package/dist/browser/background.mjs.map +1 -1
  42. package/dist/browser/browser-adapter.d.mts +2 -2
  43. package/dist/browser/browser-adapter.d.ts +2 -2
  44. package/dist/claude-code/claude-code-adapter.d.mts +2 -2
  45. package/dist/claude-code/claude-code-adapter.d.ts +2 -2
  46. package/dist/cli/index.d.mts +2 -2
  47. package/dist/cli/index.d.ts +2 -2
  48. package/dist/cli/index.js +33 -6
  49. package/dist/cli/index.js.map +1 -1
  50. package/dist/cli/index.mjs +33 -6
  51. package/dist/cli/index.mjs.map +1 -1
  52. package/dist/codex/index.d.mts +2 -2
  53. package/dist/codex/index.d.ts +2 -2
  54. package/dist/codex/index.js +60 -13
  55. package/dist/codex/index.js.map +1 -1
  56. package/dist/codex/index.mjs +60 -13
  57. package/dist/codex/index.mjs.map +1 -1
  58. package/dist/cursor/cursor-adapter.d.mts +2 -2
  59. package/dist/cursor/cursor-adapter.d.ts +2 -2
  60. package/dist/cursor/extension.d.mts +2 -2
  61. package/dist/cursor/extension.d.ts +2 -2
  62. package/dist/cursor/extension.js +60 -13
  63. package/dist/cursor/extension.js.map +1 -1
  64. package/dist/cursor/extension.mjs +60 -13
  65. package/dist/cursor/extension.mjs.map +1 -1
  66. package/dist/edge-config.d.mts +1 -1
  67. package/dist/edge-config.d.ts +1 -1
  68. package/dist/edge-config.js +1 -1
  69. package/dist/edge-config.js.map +1 -1
  70. package/dist/edge-config.mjs +1 -1
  71. package/dist/edge-config.mjs.map +1 -1
  72. package/dist/edge-core/index.d.mts +1 -1
  73. package/dist/edge-core/index.d.ts +1 -1
  74. package/dist/edge-core/index.js +6 -1
  75. package/dist/edge-core/index.js.map +1 -1
  76. package/dist/edge-core/index.mjs +6 -1
  77. package/dist/edge-core/index.mjs.map +1 -1
  78. package/dist/{express-DaqL11tx.d.ts → express-D-8Ks2Uo.d.ts} +1 -1
  79. package/dist/{express-CR6F3njD.d.mts → express-DBtPKXOL.d.mts} +1 -1
  80. package/dist/gateway/gateway.d.mts +2 -2
  81. package/dist/gateway/gateway.d.ts +2 -2
  82. package/dist/gateway/gateway.js +60 -13
  83. package/dist/gateway/gateway.js.map +1 -1
  84. package/dist/gateway/gateway.mjs +60 -13
  85. package/dist/gateway/gateway.mjs.map +1 -1
  86. package/dist/git-trigger/git-hooks.d.mts +2 -2
  87. package/dist/git-trigger/git-hooks.d.ts +2 -2
  88. package/dist/{index-BfIxCYIZ.d.ts → index-BND3kQev.d.ts} +1 -2
  89. package/dist/{index-CwAh7Tln.d.mts → index-CUfmJ1Dq.d.mts} +1 -2
  90. package/dist/{index-B5Ts1WtM.d.ts → index-DlZORQsb.d.ts} +1 -1
  91. package/dist/{index-Cub7lK-T.d.mts → index-kGCGWd5x.d.mts} +1 -1
  92. package/dist/index.d.mts +10 -10
  93. package/dist/index.d.ts +10 -10
  94. package/dist/index.js +6 -1
  95. package/dist/index.js.map +1 -1
  96. package/dist/index.mjs +6 -1
  97. package/dist/index.mjs.map +1 -1
  98. package/dist/local-evaluator/evaluator.d.mts +2 -2
  99. package/dist/local-evaluator/evaluator.d.ts +2 -2
  100. package/dist/local-evaluator/evaluator.js +22 -7
  101. package/dist/local-evaluator/evaluator.js.map +1 -1
  102. package/dist/local-evaluator/evaluator.mjs +22 -7
  103. package/dist/local-evaluator/evaluator.mjs.map +1 -1
  104. package/dist/{mcp--DgKOwfu.d.ts → mcp-DToTlwIn.d.ts} +1 -1
  105. package/dist/{mcp-BgBJu4Jl.d.mts → mcp-ZRN4kY3b.d.mts} +1 -1
  106. package/dist/{nextjs-DlX6xwbU.d.mts → nextjs-C0KASOy_.d.mts} +1 -1
  107. package/dist/{nextjs-DL6uE1ye.d.ts → nextjs-lwNvWYWT.d.ts} +1 -1
  108. package/dist/registration/index.d.mts +5 -1
  109. package/dist/registration/index.d.ts +5 -1
  110. package/dist/registration/index.js +1 -1
  111. package/dist/registration/index.js.map +1 -1
  112. package/dist/registration/index.mjs +1 -1
  113. package/dist/registration/index.mjs.map +1 -1
  114. package/dist/{sdk-C6SASmsh.d.ts → sdk-B4aodEwj.d.ts} +1 -1
  115. package/dist/{sdk-Bbh9B_dw.d.mts → sdk-B9dSwum7.d.mts} +1 -1
  116. package/dist/transport/index.d.mts +2 -2
  117. package/dist/transport/index.d.ts +2 -2
  118. package/dist/transport/index.js +1 -1
  119. package/dist/transport/index.js.map +1 -1
  120. package/dist/transport/index.mjs +1 -1
  121. package/dist/transport/index.mjs.map +1 -1
  122. package/dist/{types-DwSfO7Sb.d.ts → types-CGPU7HLi.d.ts} +8 -0
  123. package/dist/{types-nIh3HtuA.d.ts → types-CfSJLS4i.d.mts} +14 -1
  124. package/dist/{types-C0zfSXMB.d.mts → types-Cx9hTpKI.d.mts} +8 -0
  125. package/dist/{types-C7Rb-w0d.d.mts → types-DhhJxKIC.d.ts} +14 -1
  126. package/dist/ui/index.d.mts +1 -1
  127. package/dist/ui/index.d.ts +1 -1
  128. package/dist/verify.d.mts +1 -1
  129. package/dist/verify.d.ts +1 -1
  130. package/dist/verify.js +6 -1
  131. package/dist/verify.js.map +1 -1
  132. package/dist/verify.mjs +6 -1
  133. package/dist/verify.mjs.map +1 -1
  134. package/package.json +1 -1
@@ -260,9 +260,9 @@ var LocalEvaluator = class {
260
260
  if (scopeBlock) {
261
261
  return { recommendation: "DENY", reason: scopeBlock };
262
262
  }
263
- const limitViolation = this.checkLimits(context);
264
- if (limitViolation) {
265
- return { recommendation: "DENY", reason: limitViolation };
263
+ const limitDecision = this.checkLimits(context);
264
+ if (limitDecision) {
265
+ return limitDecision;
266
266
  }
267
267
  if (context.purpose === "sub_agent.spawn" && this.policy.selfInstantiation) {
268
268
  if (!this.policy.selfInstantiation.allowed) {
@@ -327,9 +327,21 @@ var LocalEvaluator = class {
327
327
  checkLimits(context) {
328
328
  const limits = this.policy.limits;
329
329
  if (!limits) return null;
330
- if (limits.maxTransactionAmount !== void 0 && context.transactionValue !== void 0) {
331
- if (context.transactionValue > limits.maxTransactionAmount) {
332
- return `Transaction value ${context.transactionValue} exceeds limit ${limits.maxTransactionAmount}`;
330
+ const value = context.transactionValue;
331
+ if (value !== void 0 && value > 0 && (limits.autonomousThreshold !== void 0 || limits.maxTransactionAmount !== void 0)) {
332
+ const autonomousThreshold = limits.autonomousThreshold ?? 0;
333
+ const hardLimit = limits.maxTransactionAmount ?? limits.autonomousThreshold ?? 0;
334
+ if (value > autonomousThreshold) {
335
+ if (value >= hardLimit) {
336
+ return {
337
+ recommendation: "DENY",
338
+ reason: `Transaction value ${value} at or above Hard Limit ${hardLimit}`
339
+ };
340
+ }
341
+ return {
342
+ recommendation: "MANUAL_REVIEW",
343
+ reason: `Transaction value ${value} is in the human-approval band (${autonomousThreshold}, ${hardLimit})`
344
+ };
333
345
  }
334
346
  }
335
347
  if (limits.maxRequestsPerHour !== void 0) {
@@ -342,7 +354,10 @@ var LocalEvaluator = class {
342
354
  } else {
343
355
  entry.count++;
344
356
  if (entry.count > limits.maxRequestsPerHour) {
345
- return `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`;
357
+ return {
358
+ recommendation: "DENY",
359
+ reason: `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`
360
+ };
346
361
  }
347
362
  }
348
363
  }
@@ -3551,10 +3566,16 @@ function validatePurpose(purpose, path) {
3551
3566
  errors.push({ path: `${path}.targets`, message: "targets must be an array of strings" });
3552
3567
  }
3553
3568
  if (p.blockedPatterns !== void 0 && !isStringArray(p.blockedPatterns)) {
3554
- errors.push({ path: `${path}.blockedPatterns`, message: "blockedPatterns must be an array of strings" });
3569
+ errors.push({
3570
+ path: `${path}.blockedPatterns`,
3571
+ message: "blockedPatterns must be an array of strings"
3572
+ });
3555
3573
  }
3556
3574
  if (p.requiresApproval !== void 0 && typeof p.requiresApproval !== "boolean") {
3557
- errors.push({ path: `${path}.requiresApproval`, message: "requiresApproval must be a boolean" });
3575
+ errors.push({
3576
+ path: `${path}.requiresApproval`,
3577
+ message: "requiresApproval must be a boolean"
3578
+ });
3558
3579
  }
3559
3580
  return errors;
3560
3581
  }
@@ -3577,11 +3598,29 @@ function validateLimits(limits, path) {
3577
3598
  return [{ path, message: "limits must be an object" }];
3578
3599
  }
3579
3600
  const l = limits;
3601
+ if (l.autonomousThreshold !== void 0 && typeof l.autonomousThreshold !== "number") {
3602
+ errors.push({
3603
+ path: `${path}.autonomousThreshold`,
3604
+ message: "autonomousThreshold must be a number"
3605
+ });
3606
+ }
3580
3607
  if (l.maxTransactionAmount !== void 0 && typeof l.maxTransactionAmount !== "number") {
3581
- errors.push({ path: `${path}.maxTransactionAmount`, message: "maxTransactionAmount must be a number" });
3608
+ errors.push({
3609
+ path: `${path}.maxTransactionAmount`,
3610
+ message: "maxTransactionAmount must be a number"
3611
+ });
3612
+ }
3613
+ if (typeof l.autonomousThreshold === "number" && typeof l.maxTransactionAmount === "number" && l.autonomousThreshold > l.maxTransactionAmount) {
3614
+ errors.push({
3615
+ path: `${path}.autonomousThreshold`,
3616
+ message: "autonomousThreshold (Autonomous Limit) must be <= maxTransactionAmount (Hard Limit)"
3617
+ });
3582
3618
  }
3583
3619
  if (l.maxRequestsPerHour !== void 0 && typeof l.maxRequestsPerHour !== "number") {
3584
- errors.push({ path: `${path}.maxRequestsPerHour`, message: "maxRequestsPerHour must be a number" });
3620
+ errors.push({
3621
+ path: `${path}.maxRequestsPerHour`,
3622
+ message: "maxRequestsPerHour must be a number"
3623
+ });
3585
3624
  }
3586
3625
  if (l.currency !== void 0 && typeof l.currency !== "string") {
3587
3626
  errors.push({ path: `${path}.currency`, message: "currency must be a string" });
@@ -3596,7 +3635,10 @@ function validateRiskThresholds(thresholds, path) {
3596
3635
  const t = thresholds;
3597
3636
  for (const range of ["autoAllow", "requireApproval", "autoBlock"]) {
3598
3637
  if (!t[range] || typeof t[range] !== "object") {
3599
- errors.push({ path: `${path}.${range}`, message: `${range} is required and must be an object with min and max` });
3638
+ errors.push({
3639
+ path: `${path}.${range}`,
3640
+ message: `${range} is required and must be an object with min and max`
3641
+ });
3600
3642
  continue;
3601
3643
  }
3602
3644
  const r = t[range];
@@ -3701,7 +3743,7 @@ function getTrustLevel(score) {
3701
3743
  }
3702
3744
 
3703
3745
  // src/version.ts
3704
- var SDK_VERSION = "4.5.1";
3746
+ var SDK_VERSION = "4.6.0";
3705
3747
 
3706
3748
  // src/http.ts
3707
3749
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -3925,6 +3967,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
3925
3967
  // 4.0.0: typed marker so adapters render the misconfig envelope (503 +
3926
3968
  // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
3927
3969
  ...isMisconfig && { misconfigured: true },
3970
+ // 4.6.0: a transient api_error is retryable — mark it so consumers surface
3971
+ // "temporarily unavailable, retry" (recommendation 'error') instead of
3972
+ // coercing the absent recommendation to a policy 'deny'. Misconfig is
3973
+ // deterministic and intentionally NOT marked retryable.
3974
+ ...isApiError && { retryable: true },
3928
3975
  correlationId: options.correlationId,
3929
3976
  attemptId: options.attemptId,
3930
3977
  verifiedAt: /* @__PURE__ */ new Date()
@@ -259,9 +259,9 @@ var LocalEvaluator = class {
259
259
  if (scopeBlock) {
260
260
  return { recommendation: "DENY", reason: scopeBlock };
261
261
  }
262
- const limitViolation = this.checkLimits(context);
263
- if (limitViolation) {
264
- return { recommendation: "DENY", reason: limitViolation };
262
+ const limitDecision = this.checkLimits(context);
263
+ if (limitDecision) {
264
+ return limitDecision;
265
265
  }
266
266
  if (context.purpose === "sub_agent.spawn" && this.policy.selfInstantiation) {
267
267
  if (!this.policy.selfInstantiation.allowed) {
@@ -326,9 +326,21 @@ var LocalEvaluator = class {
326
326
  checkLimits(context) {
327
327
  const limits = this.policy.limits;
328
328
  if (!limits) return null;
329
- if (limits.maxTransactionAmount !== void 0 && context.transactionValue !== void 0) {
330
- if (context.transactionValue > limits.maxTransactionAmount) {
331
- return `Transaction value ${context.transactionValue} exceeds limit ${limits.maxTransactionAmount}`;
329
+ const value = context.transactionValue;
330
+ if (value !== void 0 && value > 0 && (limits.autonomousThreshold !== void 0 || limits.maxTransactionAmount !== void 0)) {
331
+ const autonomousThreshold = limits.autonomousThreshold ?? 0;
332
+ const hardLimit = limits.maxTransactionAmount ?? limits.autonomousThreshold ?? 0;
333
+ if (value > autonomousThreshold) {
334
+ if (value >= hardLimit) {
335
+ return {
336
+ recommendation: "DENY",
337
+ reason: `Transaction value ${value} at or above Hard Limit ${hardLimit}`
338
+ };
339
+ }
340
+ return {
341
+ recommendation: "MANUAL_REVIEW",
342
+ reason: `Transaction value ${value} is in the human-approval band (${autonomousThreshold}, ${hardLimit})`
343
+ };
332
344
  }
333
345
  }
334
346
  if (limits.maxRequestsPerHour !== void 0) {
@@ -341,7 +353,10 @@ var LocalEvaluator = class {
341
353
  } else {
342
354
  entry.count++;
343
355
  if (entry.count > limits.maxRequestsPerHour) {
344
- return `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`;
356
+ return {
357
+ recommendation: "DENY",
358
+ reason: `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`
359
+ };
345
360
  }
346
361
  }
347
362
  }
@@ -3550,10 +3565,16 @@ function validatePurpose(purpose, path) {
3550
3565
  errors.push({ path: `${path}.targets`, message: "targets must be an array of strings" });
3551
3566
  }
3552
3567
  if (p.blockedPatterns !== void 0 && !isStringArray(p.blockedPatterns)) {
3553
- errors.push({ path: `${path}.blockedPatterns`, message: "blockedPatterns must be an array of strings" });
3568
+ errors.push({
3569
+ path: `${path}.blockedPatterns`,
3570
+ message: "blockedPatterns must be an array of strings"
3571
+ });
3554
3572
  }
3555
3573
  if (p.requiresApproval !== void 0 && typeof p.requiresApproval !== "boolean") {
3556
- errors.push({ path: `${path}.requiresApproval`, message: "requiresApproval must be a boolean" });
3574
+ errors.push({
3575
+ path: `${path}.requiresApproval`,
3576
+ message: "requiresApproval must be a boolean"
3577
+ });
3557
3578
  }
3558
3579
  return errors;
3559
3580
  }
@@ -3576,11 +3597,29 @@ function validateLimits(limits, path) {
3576
3597
  return [{ path, message: "limits must be an object" }];
3577
3598
  }
3578
3599
  const l = limits;
3600
+ if (l.autonomousThreshold !== void 0 && typeof l.autonomousThreshold !== "number") {
3601
+ errors.push({
3602
+ path: `${path}.autonomousThreshold`,
3603
+ message: "autonomousThreshold must be a number"
3604
+ });
3605
+ }
3579
3606
  if (l.maxTransactionAmount !== void 0 && typeof l.maxTransactionAmount !== "number") {
3580
- errors.push({ path: `${path}.maxTransactionAmount`, message: "maxTransactionAmount must be a number" });
3607
+ errors.push({
3608
+ path: `${path}.maxTransactionAmount`,
3609
+ message: "maxTransactionAmount must be a number"
3610
+ });
3611
+ }
3612
+ if (typeof l.autonomousThreshold === "number" && typeof l.maxTransactionAmount === "number" && l.autonomousThreshold > l.maxTransactionAmount) {
3613
+ errors.push({
3614
+ path: `${path}.autonomousThreshold`,
3615
+ message: "autonomousThreshold (Autonomous Limit) must be <= maxTransactionAmount (Hard Limit)"
3616
+ });
3581
3617
  }
3582
3618
  if (l.maxRequestsPerHour !== void 0 && typeof l.maxRequestsPerHour !== "number") {
3583
- errors.push({ path: `${path}.maxRequestsPerHour`, message: "maxRequestsPerHour must be a number" });
3619
+ errors.push({
3620
+ path: `${path}.maxRequestsPerHour`,
3621
+ message: "maxRequestsPerHour must be a number"
3622
+ });
3584
3623
  }
3585
3624
  if (l.currency !== void 0 && typeof l.currency !== "string") {
3586
3625
  errors.push({ path: `${path}.currency`, message: "currency must be a string" });
@@ -3595,7 +3634,10 @@ function validateRiskThresholds(thresholds, path) {
3595
3634
  const t = thresholds;
3596
3635
  for (const range of ["autoAllow", "requireApproval", "autoBlock"]) {
3597
3636
  if (!t[range] || typeof t[range] !== "object") {
3598
- errors.push({ path: `${path}.${range}`, message: `${range} is required and must be an object with min and max` });
3637
+ errors.push({
3638
+ path: `${path}.${range}`,
3639
+ message: `${range} is required and must be an object with min and max`
3640
+ });
3599
3641
  continue;
3600
3642
  }
3601
3643
  const r = t[range];
@@ -3700,7 +3742,7 @@ function getTrustLevel(score) {
3700
3742
  }
3701
3743
 
3702
3744
  // src/version.ts
3703
- var SDK_VERSION = "4.5.1";
3745
+ var SDK_VERSION = "4.6.0";
3704
3746
 
3705
3747
  // src/http.ts
3706
3748
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -3924,6 +3966,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
3924
3966
  // 4.0.0: typed marker so adapters render the misconfig envelope (503 +
3925
3967
  // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
3926
3968
  ...isMisconfig && { misconfigured: true },
3969
+ // 4.6.0: a transient api_error is retryable — mark it so consumers surface
3970
+ // "temporarily unavailable, retry" (recommendation 'error') instead of
3971
+ // coercing the absent recommendation to a policy 'deny'. Misconfig is
3972
+ // deterministic and intentionally NOT marked retryable.
3973
+ ...isApiError && { retryable: true },
3927
3974
  correlationId: options.correlationId,
3928
3975
  attemptId: options.attemptId,
3929
3976
  verifiedAt: /* @__PURE__ */ new Date()
@@ -3137,10 +3137,16 @@ function validatePurpose(purpose, path2) {
3137
3137
  errors.push({ path: `${path2}.targets`, message: "targets must be an array of strings" });
3138
3138
  }
3139
3139
  if (p.blockedPatterns !== void 0 && !isStringArray(p.blockedPatterns)) {
3140
- errors.push({ path: `${path2}.blockedPatterns`, message: "blockedPatterns must be an array of strings" });
3140
+ errors.push({
3141
+ path: `${path2}.blockedPatterns`,
3142
+ message: "blockedPatterns must be an array of strings"
3143
+ });
3141
3144
  }
3142
3145
  if (p.requiresApproval !== void 0 && typeof p.requiresApproval !== "boolean") {
3143
- errors.push({ path: `${path2}.requiresApproval`, message: "requiresApproval must be a boolean" });
3146
+ errors.push({
3147
+ path: `${path2}.requiresApproval`,
3148
+ message: "requiresApproval must be a boolean"
3149
+ });
3144
3150
  }
3145
3151
  return errors;
3146
3152
  }
@@ -3163,11 +3169,29 @@ function validateLimits(limits, path2) {
3163
3169
  return [{ path: path2, message: "limits must be an object" }];
3164
3170
  }
3165
3171
  const l = limits;
3172
+ if (l.autonomousThreshold !== void 0 && typeof l.autonomousThreshold !== "number") {
3173
+ errors.push({
3174
+ path: `${path2}.autonomousThreshold`,
3175
+ message: "autonomousThreshold must be a number"
3176
+ });
3177
+ }
3166
3178
  if (l.maxTransactionAmount !== void 0 && typeof l.maxTransactionAmount !== "number") {
3167
- errors.push({ path: `${path2}.maxTransactionAmount`, message: "maxTransactionAmount must be a number" });
3179
+ errors.push({
3180
+ path: `${path2}.maxTransactionAmount`,
3181
+ message: "maxTransactionAmount must be a number"
3182
+ });
3183
+ }
3184
+ if (typeof l.autonomousThreshold === "number" && typeof l.maxTransactionAmount === "number" && l.autonomousThreshold > l.maxTransactionAmount) {
3185
+ errors.push({
3186
+ path: `${path2}.autonomousThreshold`,
3187
+ message: "autonomousThreshold (Autonomous Limit) must be <= maxTransactionAmount (Hard Limit)"
3188
+ });
3168
3189
  }
3169
3190
  if (l.maxRequestsPerHour !== void 0 && typeof l.maxRequestsPerHour !== "number") {
3170
- errors.push({ path: `${path2}.maxRequestsPerHour`, message: "maxRequestsPerHour must be a number" });
3191
+ errors.push({
3192
+ path: `${path2}.maxRequestsPerHour`,
3193
+ message: "maxRequestsPerHour must be a number"
3194
+ });
3171
3195
  }
3172
3196
  if (l.currency !== void 0 && typeof l.currency !== "string") {
3173
3197
  errors.push({ path: `${path2}.currency`, message: "currency must be a string" });
@@ -3182,7 +3206,10 @@ function validateRiskThresholds(thresholds, path2) {
3182
3206
  const t = thresholds;
3183
3207
  for (const range of ["autoAllow", "requireApproval", "autoBlock"]) {
3184
3208
  if (!t[range] || typeof t[range] !== "object") {
3185
- errors.push({ path: `${path2}.${range}`, message: `${range} is required and must be an object with min and max` });
3209
+ errors.push({
3210
+ path: `${path2}.${range}`,
3211
+ message: `${range} is required and must be an object with min and max`
3212
+ });
3186
3213
  continue;
3187
3214
  }
3188
3215
  const r = t[range];
@@ -3678,7 +3705,7 @@ Policy saved to ${outputPath}`);
3678
3705
  };
3679
3706
 
3680
3707
  // src/version.ts
3681
- var SDK_VERSION = "4.5.1";
3708
+ var SDK_VERSION = "4.6.0";
3682
3709
 
3683
3710
  // src/http.ts
3684
3711
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -4419,9 +4446,9 @@ var LocalEvaluator = class {
4419
4446
  if (scopeBlock) {
4420
4447
  return { recommendation: "DENY", reason: scopeBlock };
4421
4448
  }
4422
- const limitViolation = this.checkLimits(context);
4423
- if (limitViolation) {
4424
- return { recommendation: "DENY", reason: limitViolation };
4449
+ const limitDecision = this.checkLimits(context);
4450
+ if (limitDecision) {
4451
+ return limitDecision;
4425
4452
  }
4426
4453
  if (context.purpose === "sub_agent.spawn" && this.policy.selfInstantiation) {
4427
4454
  if (!this.policy.selfInstantiation.allowed) {
@@ -4486,9 +4513,21 @@ var LocalEvaluator = class {
4486
4513
  checkLimits(context) {
4487
4514
  const limits = this.policy.limits;
4488
4515
  if (!limits) return null;
4489
- if (limits.maxTransactionAmount !== void 0 && context.transactionValue !== void 0) {
4490
- if (context.transactionValue > limits.maxTransactionAmount) {
4491
- return `Transaction value ${context.transactionValue} exceeds limit ${limits.maxTransactionAmount}`;
4516
+ const value = context.transactionValue;
4517
+ if (value !== void 0 && value > 0 && (limits.autonomousThreshold !== void 0 || limits.maxTransactionAmount !== void 0)) {
4518
+ const autonomousThreshold = limits.autonomousThreshold ?? 0;
4519
+ const hardLimit = limits.maxTransactionAmount ?? limits.autonomousThreshold ?? 0;
4520
+ if (value > autonomousThreshold) {
4521
+ if (value >= hardLimit) {
4522
+ return {
4523
+ recommendation: "DENY",
4524
+ reason: `Transaction value ${value} at or above Hard Limit ${hardLimit}`
4525
+ };
4526
+ }
4527
+ return {
4528
+ recommendation: "MANUAL_REVIEW",
4529
+ reason: `Transaction value ${value} is in the human-approval band (${autonomousThreshold}, ${hardLimit})`
4530
+ };
4492
4531
  }
4493
4532
  }
4494
4533
  if (limits.maxRequestsPerHour !== void 0) {
@@ -4501,7 +4540,10 @@ var LocalEvaluator = class {
4501
4540
  } else {
4502
4541
  entry.count++;
4503
4542
  if (entry.count > limits.maxRequestsPerHour) {
4504
- return `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`;
4543
+ return {
4544
+ recommendation: "DENY",
4545
+ reason: `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`
4546
+ };
4505
4547
  }
4506
4548
  }
4507
4549
  }
@@ -4833,6 +4875,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
4833
4875
  // 4.0.0: typed marker so adapters render the misconfig envelope (503 +
4834
4876
  // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
4835
4877
  ...isMisconfig && { misconfigured: true },
4878
+ // 4.6.0: a transient api_error is retryable — mark it so consumers surface
4879
+ // "temporarily unavailable, retry" (recommendation 'error') instead of
4880
+ // coercing the absent recommendation to a policy 'deny'. Misconfig is
4881
+ // deterministic and intentionally NOT marked retryable.
4882
+ ...isApiError && { retryable: true },
4836
4883
  correlationId: options.correlationId,
4837
4884
  attemptId: options.attemptId,
4838
4885
  verifiedAt: /* @__PURE__ */ new Date()
@@ -6,8 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __esm = (fn, res) => function __init() {
10
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
+ var __esm = (fn, res, err) => function __init() {
10
+ if (err) throw err[0];
11
+ try {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ } catch (e) {
14
+ throw err = [e], e;
15
+ }
11
16
  };
12
17
  var __copyProps = (to, from, except, desc) => {
13
18
  if (from && typeof from === "object" || typeof from === "function") {
@@ -31,7 +36,7 @@ var SDK_VERSION;
31
36
  var init_version = __esm({
32
37
  "src/version.ts"() {
33
38
  "use strict";
34
- SDK_VERSION = "4.5.1";
39
+ SDK_VERSION = "4.6.0";
35
40
  }
36
41
  });
37
42
 
@@ -3477,10 +3482,16 @@ function validatePurpose(purpose, path2) {
3477
3482
  errors.push({ path: `${path2}.targets`, message: "targets must be an array of strings" });
3478
3483
  }
3479
3484
  if (p.blockedPatterns !== void 0 && !isStringArray(p.blockedPatterns)) {
3480
- errors.push({ path: `${path2}.blockedPatterns`, message: "blockedPatterns must be an array of strings" });
3485
+ errors.push({
3486
+ path: `${path2}.blockedPatterns`,
3487
+ message: "blockedPatterns must be an array of strings"
3488
+ });
3481
3489
  }
3482
3490
  if (p.requiresApproval !== void 0 && typeof p.requiresApproval !== "boolean") {
3483
- errors.push({ path: `${path2}.requiresApproval`, message: "requiresApproval must be a boolean" });
3491
+ errors.push({
3492
+ path: `${path2}.requiresApproval`,
3493
+ message: "requiresApproval must be a boolean"
3494
+ });
3484
3495
  }
3485
3496
  return errors;
3486
3497
  }
@@ -3503,11 +3514,29 @@ function validateLimits(limits, path2) {
3503
3514
  return [{ path: path2, message: "limits must be an object" }];
3504
3515
  }
3505
3516
  const l = limits;
3517
+ if (l.autonomousThreshold !== void 0 && typeof l.autonomousThreshold !== "number") {
3518
+ errors.push({
3519
+ path: `${path2}.autonomousThreshold`,
3520
+ message: "autonomousThreshold must be a number"
3521
+ });
3522
+ }
3506
3523
  if (l.maxTransactionAmount !== void 0 && typeof l.maxTransactionAmount !== "number") {
3507
- errors.push({ path: `${path2}.maxTransactionAmount`, message: "maxTransactionAmount must be a number" });
3524
+ errors.push({
3525
+ path: `${path2}.maxTransactionAmount`,
3526
+ message: "maxTransactionAmount must be a number"
3527
+ });
3528
+ }
3529
+ if (typeof l.autonomousThreshold === "number" && typeof l.maxTransactionAmount === "number" && l.autonomousThreshold > l.maxTransactionAmount) {
3530
+ errors.push({
3531
+ path: `${path2}.autonomousThreshold`,
3532
+ message: "autonomousThreshold (Autonomous Limit) must be <= maxTransactionAmount (Hard Limit)"
3533
+ });
3508
3534
  }
3509
3535
  if (l.maxRequestsPerHour !== void 0 && typeof l.maxRequestsPerHour !== "number") {
3510
- errors.push({ path: `${path2}.maxRequestsPerHour`, message: "maxRequestsPerHour must be a number" });
3536
+ errors.push({
3537
+ path: `${path2}.maxRequestsPerHour`,
3538
+ message: "maxRequestsPerHour must be a number"
3539
+ });
3511
3540
  }
3512
3541
  if (l.currency !== void 0 && typeof l.currency !== "string") {
3513
3542
  errors.push({ path: `${path2}.currency`, message: "currency must be a string" });
@@ -3522,7 +3551,10 @@ function validateRiskThresholds(thresholds, path2) {
3522
3551
  const t = thresholds;
3523
3552
  for (const range of ["autoAllow", "requireApproval", "autoBlock"]) {
3524
3553
  if (!t[range] || typeof t[range] !== "object") {
3525
- errors.push({ path: `${path2}.${range}`, message: `${range} is required and must be an object with min and max` });
3554
+ errors.push({
3555
+ path: `${path2}.${range}`,
3556
+ message: `${range} is required and must be an object with min and max`
3557
+ });
3526
3558
  continue;
3527
3559
  }
3528
3560
  const r = t[range];
@@ -4807,9 +4839,9 @@ var init_evaluator = __esm({
4807
4839
  if (scopeBlock) {
4808
4840
  return { recommendation: "DENY", reason: scopeBlock };
4809
4841
  }
4810
- const limitViolation = this.checkLimits(context);
4811
- if (limitViolation) {
4812
- return { recommendation: "DENY", reason: limitViolation };
4842
+ const limitDecision = this.checkLimits(context);
4843
+ if (limitDecision) {
4844
+ return limitDecision;
4813
4845
  }
4814
4846
  if (context.purpose === "sub_agent.spawn" && this.policy.selfInstantiation) {
4815
4847
  if (!this.policy.selfInstantiation.allowed) {
@@ -4874,9 +4906,21 @@ var init_evaluator = __esm({
4874
4906
  checkLimits(context) {
4875
4907
  const limits = this.policy.limits;
4876
4908
  if (!limits) return null;
4877
- if (limits.maxTransactionAmount !== void 0 && context.transactionValue !== void 0) {
4878
- if (context.transactionValue > limits.maxTransactionAmount) {
4879
- return `Transaction value ${context.transactionValue} exceeds limit ${limits.maxTransactionAmount}`;
4909
+ const value = context.transactionValue;
4910
+ if (value !== void 0 && value > 0 && (limits.autonomousThreshold !== void 0 || limits.maxTransactionAmount !== void 0)) {
4911
+ const autonomousThreshold = limits.autonomousThreshold ?? 0;
4912
+ const hardLimit = limits.maxTransactionAmount ?? limits.autonomousThreshold ?? 0;
4913
+ if (value > autonomousThreshold) {
4914
+ if (value >= hardLimit) {
4915
+ return {
4916
+ recommendation: "DENY",
4917
+ reason: `Transaction value ${value} at or above Hard Limit ${hardLimit}`
4918
+ };
4919
+ }
4920
+ return {
4921
+ recommendation: "MANUAL_REVIEW",
4922
+ reason: `Transaction value ${value} is in the human-approval band (${autonomousThreshold}, ${hardLimit})`
4923
+ };
4880
4924
  }
4881
4925
  }
4882
4926
  if (limits.maxRequestsPerHour !== void 0) {
@@ -4889,7 +4933,10 @@ var init_evaluator = __esm({
4889
4933
  } else {
4890
4934
  entry.count++;
4891
4935
  if (entry.count > limits.maxRequestsPerHour) {
4892
- return `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`;
4936
+ return {
4937
+ recommendation: "DENY",
4938
+ reason: `Rate limit exceeded: ${entry.count}/${limits.maxRequestsPerHour} requests per hour`
4939
+ };
4893
4940
  }
4894
4941
  }
4895
4942
  }
@@ -5224,6 +5271,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
5224
5271
  // 4.0.0: typed marker so adapters render the misconfig envelope (503 +
5225
5272
  // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
5226
5273
  ...isMisconfig && { misconfigured: true },
5274
+ // 4.6.0: a transient api_error is retryable — mark it so consumers surface
5275
+ // "temporarily unavailable, retry" (recommendation 'error') instead of
5276
+ // coercing the absent recommendation to a policy 'deny'. Misconfig is
5277
+ // deterministic and intentionally NOT marked retryable.
5278
+ ...isApiError && { retryable: true },
5227
5279
  correlationId: options.correlationId,
5228
5280
  attemptId: options.attemptId,
5229
5281
  verifiedAt: /* @__PURE__ */ new Date()