@astrasyncai/verification-gateway 3.8.0 → 3.10.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 (114) hide show
  1. package/dist/adapter-interface/interface.d.mts +3 -2
  2. package/dist/adapter-interface/interface.d.ts +3 -2
  3. package/dist/adapters/express.d.mts +3 -2
  4. package/dist/adapters/express.d.ts +3 -2
  5. package/dist/adapters/express.js +152 -2
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +152 -2
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/http-pdlss.d.mts +81 -0
  10. package/dist/adapters/http-pdlss.d.ts +81 -0
  11. package/dist/adapters/http-pdlss.js +117 -0
  12. package/dist/adapters/http-pdlss.js.map +1 -0
  13. package/dist/adapters/http-pdlss.mjs +87 -0
  14. package/dist/adapters/http-pdlss.mjs.map +1 -0
  15. package/dist/adapters/mcp.d.mts +2 -1
  16. package/dist/adapters/mcp.d.ts +2 -1
  17. package/dist/adapters/mcp.js +2 -1
  18. package/dist/adapters/mcp.js.map +1 -1
  19. package/dist/adapters/mcp.mjs +2 -1
  20. package/dist/adapters/mcp.mjs.map +1 -1
  21. package/dist/adapters/nextjs.d.mts +3 -2
  22. package/dist/adapters/nextjs.d.ts +3 -2
  23. package/dist/adapters/nextjs.js +152 -2
  24. package/dist/adapters/nextjs.js.map +1 -1
  25. package/dist/adapters/nextjs.mjs +152 -2
  26. package/dist/adapters/nextjs.mjs.map +1 -1
  27. package/dist/adapters/sdk.d.mts +3 -2
  28. package/dist/adapters/sdk.d.ts +3 -2
  29. package/dist/adapters/sdk.js +2 -1
  30. package/dist/adapters/sdk.js.map +1 -1
  31. package/dist/adapters/sdk.mjs +2 -1
  32. package/dist/adapters/sdk.mjs.map +1 -1
  33. package/dist/agent/index.d.mts +3 -2
  34. package/dist/agent/index.d.ts +3 -2
  35. package/dist/bin/astrasync-claude-hook.js +17 -1
  36. package/dist/bin/astrasync-guard.js +17 -1
  37. package/dist/bin/astrasync.js +43 -1
  38. package/dist/browser/background.js +17 -1
  39. package/dist/browser/background.js.map +1 -1
  40. package/dist/browser/background.mjs +17 -1
  41. package/dist/browser/background.mjs.map +1 -1
  42. package/dist/browser/browser-adapter.d.mts +3 -2
  43. package/dist/browser/browser-adapter.d.ts +3 -2
  44. package/dist/claude-code/claude-code-adapter.d.mts +3 -2
  45. package/dist/claude-code/claude-code-adapter.d.ts +3 -2
  46. package/dist/cli/index.d.mts +3 -2
  47. package/dist/cli/index.d.ts +3 -2
  48. package/dist/cursor/cursor-adapter.d.mts +3 -2
  49. package/dist/cursor/cursor-adapter.d.ts +3 -2
  50. package/dist/cursor/extension.d.mts +3 -2
  51. package/dist/cursor/extension.d.ts +3 -2
  52. package/dist/cursor/extension.js +17 -1
  53. package/dist/cursor/extension.js.map +1 -1
  54. package/dist/cursor/extension.mjs +17 -1
  55. package/dist/cursor/extension.mjs.map +1 -1
  56. package/dist/edge-config.d.mts +131 -0
  57. package/dist/edge-config.d.ts +131 -0
  58. package/dist/edge-config.js +162 -0
  59. package/dist/edge-config.js.map +1 -0
  60. package/dist/edge-config.mjs +131 -0
  61. package/dist/edge-config.mjs.map +1 -0
  62. package/dist/{express-C8nJGi5P.d.ts → express-ClNtDhhc.d.ts} +1 -1
  63. package/dist/{express-Di_hnZZS.d.mts → express-DCXa1oqj.d.mts} +1 -1
  64. package/dist/gateway/gateway.d.mts +3 -2
  65. package/dist/gateway/gateway.d.ts +3 -2
  66. package/dist/gateway/gateway.js +17 -1
  67. package/dist/gateway/gateway.js.map +1 -1
  68. package/dist/gateway/gateway.mjs +17 -1
  69. package/dist/gateway/gateway.mjs.map +1 -1
  70. package/dist/git-trigger/git-hooks.d.mts +3 -2
  71. package/dist/git-trigger/git-hooks.d.ts +3 -2
  72. package/dist/{index-CXcvO9Au.d.mts → index-BrNKDmiR.d.mts} +1 -1
  73. package/dist/{index-CuCkjT7B.d.ts → index-CfHurO1P.d.ts} +1 -1
  74. package/dist/{index-CBQr4FGs.d.ts → index-D2ztkumS.d.ts} +1 -1
  75. package/dist/{index-DALAqct7.d.mts → index-Dr_XiN65.d.mts} +1 -1
  76. package/dist/index.d.mts +27 -82
  77. package/dist/index.d.ts +27 -82
  78. package/dist/index.js +435 -12
  79. package/dist/index.js.map +1 -1
  80. package/dist/index.mjs +417 -12
  81. package/dist/index.mjs.map +1 -1
  82. package/dist/local-evaluator/evaluator.d.mts +3 -2
  83. package/dist/local-evaluator/evaluator.d.ts +3 -2
  84. package/dist/metadata-capture.d.mts +87 -0
  85. package/dist/metadata-capture.d.ts +87 -0
  86. package/dist/metadata-capture.js +184 -0
  87. package/dist/metadata-capture.js.map +1 -0
  88. package/dist/metadata-capture.mjs +154 -0
  89. package/dist/metadata-capture.mjs.map +1 -0
  90. package/dist/{nextjs-IyXWW2KL.d.ts → nextjs-CEBVBsdi.d.ts} +1 -1
  91. package/dist/{nextjs-BMAe8ode.d.mts → nextjs-DcQIk6Zj.d.mts} +1 -1
  92. package/dist/platform-signatures.d.mts +97 -0
  93. package/dist/platform-signatures.d.ts +97 -0
  94. package/dist/platform-signatures.js +116 -0
  95. package/dist/platform-signatures.js.map +1 -0
  96. package/dist/platform-signatures.mjs +89 -0
  97. package/dist/platform-signatures.mjs.map +1 -0
  98. package/dist/{sdk-Cn4KcZ5G.d.mts → sdk-CZkbSOeO.d.mts} +1 -1
  99. package/dist/{sdk-ThdA_NtL.d.ts → sdk-H0JCLW2y.d.ts} +1 -1
  100. package/dist/transport/index.d.mts +3 -2
  101. package/dist/transport/index.d.ts +3 -2
  102. package/dist/{types-DedAJbNI.d.mts → types-9tns4wyl.d.ts} +88 -1
  103. package/dist/{types-CSFci5zD.d.mts → types-D0lCtFQ7.d.mts} +1 -1
  104. package/dist/{types-D1kyMiml.d.ts → types-YbiXYKx1.d.ts} +1 -1
  105. package/dist/{types-DedAJbNI.d.ts → types-sy3tq8lp.d.mts} +88 -1
  106. package/dist/ui/index.d.mts +2 -1
  107. package/dist/ui/index.d.ts +2 -1
  108. package/dist/verify.d.mts +151 -0
  109. package/dist/verify.d.ts +151 -0
  110. package/dist/verify.js +593 -0
  111. package/dist/verify.js.map +1 -0
  112. package/dist/verify.mjs +557 -0
  113. package/dist/verify.mjs.map +1 -0
  114. package/package.json +26 -1
@@ -0,0 +1,131 @@
1
+ import { G as GatewayConfig } from './types-sy3tq8lp.mjs';
2
+ import './metadata-capture.mjs';
3
+
4
+ /**
5
+ * Edge verification config — the per-endpoint policy the Commerce Shield
6
+ * edge adapter (§7.4, `@astrasyncai/adapter-lambda`) fetches from the
7
+ * AstraSync dashboard to decide how much verification friction to apply
8
+ * to inbound traffic, and where.
9
+ *
10
+ * Fetch pattern mirrors `well-known.ts`: TTL cache + stale-while-revalidate
11
+ * + in-flight dedupe, with a `_reset*` hook for tests. Fail posture is
12
+ * deliberately asymmetric: this module can NEVER put a site into enforce
13
+ * mode on its own — enforce only ever originates from a successfully
14
+ * fetched config, and a config that has gone stale past `maxStaleMs`
15
+ * degrades back to observe.
16
+ */
17
+
18
+ /**
19
+ * Edge posture. Canonical Commerce Shield vocabulary (strategy doc /
20
+ * spec §33.5): `observe` ≈ the gateway's `passive` posture (verify +
21
+ * record, enforce nothing), `enforce` ≈ `active`. New value set on a new
22
+ * field name — do NOT reuse `GatewayPosture`'s `active`/`passive` here
23
+ * (different field, different meaning: posture governs an agent-side
24
+ * gateway; mode governs counterparty-side edge interception).
25
+ */
26
+ type EdgeMode = 'observe' | 'enforce';
27
+ /**
28
+ * How deep the edge checks each request — what is it → who is it → are
29
+ * they allowed:
30
+ * - `classify` — UA / platform-fingerprint classification only; no
31
+ * credential handling.
32
+ * - `authenticate` — establish who is calling: detect and parse agent
33
+ * credentials (X-Astra-*, VI SD-JWT, RFC 9421, ACP,
34
+ * UCP, AP2…) and verify presented AstraSync identities.
35
+ * - `authorize` — full policy decision: credentials cryptographically
36
+ * proven and PDLSS-evaluated via a verify-access round
37
+ * trip. (US spelling on the wire, matching
38
+ * `authorizeSettlement` and HTTP `Authorization`.)
39
+ */
40
+ type EdgeVerificationDepth = 'classify' | 'authenticate' | 'authorize';
41
+ interface EdgePathRule {
42
+ /**
43
+ * `*`-wildcard glob matched against the request path. Matching is
44
+ * case-INsensitive and all regex metacharacters except `*` are
45
+ * escaped. (Deliberately diverges from the express adapter's
46
+ * `matchRoute`, which is case-sensitive by default and mid-shadow-
47
+ * rollout of the F-A6-31 fix — new surface ships the fix as default.)
48
+ */
49
+ pattern: string;
50
+ /** Pass the request through untouched (static assets); mode/depth ignored. */
51
+ skip?: boolean;
52
+ /** Override the top-level mode for this path. */
53
+ mode?: EdgeMode;
54
+ /** Override the top-level depth for this path. */
55
+ depth?: EdgeVerificationDepth;
56
+ }
57
+ interface EdgeConfig {
58
+ /** Shape version — bump on breaking changes. */
59
+ version: 1;
60
+ /** Default posture for paths no rule matches. */
61
+ mode: EdgeMode;
62
+ /** Default check depth for paths no rule matches. */
63
+ depth: EdgeVerificationDepth;
64
+ /** Ordered, first-match-wins. */
65
+ pathRules: EdgePathRule[];
66
+ sampling: {
67
+ /** Fraction (0..1) of anonymous-bot requests that emit a beacon. */
68
+ anonymousBeaconRate: number;
69
+ };
70
+ /**
71
+ * v1: only 'open' is representable — an unreachable backend always
72
+ * means observe + pass-through, never a broken or silently-enforcing
73
+ * customer site.
74
+ */
75
+ failurePosture: 'open';
76
+ }
77
+ /**
78
+ * The safe default: observe-only, classification depth, nothing enforced.
79
+ * Served by the backend when an endpoint has never been configured, and
80
+ * used by `getEdgeConfig` whenever no config can be fetched.
81
+ */
82
+ declare const DEFAULT_EDGE_CONFIG: EdgeConfig;
83
+ /** Structural guard for configs arriving over the wire. */
84
+ declare function isEdgeConfig(value: unknown): value is EdgeConfig;
85
+ interface FetchEdgeConfigSuccess {
86
+ edgeConfig: EdgeConfig;
87
+ etag?: string;
88
+ }
89
+ type FetchEdgeConfigResult = FetchEdgeConfigSuccess | {
90
+ notModified: true;
91
+ } | null;
92
+ /**
93
+ * Fetch the edge config for an endpoint from the AstraSync backend.
94
+ * `GET {apiBaseUrl}/endpoints/:counterpartyId/edge-config` with the same
95
+ * auth headers as `fetchRoutes`. Pass the cached `etag` to get a cheap
96
+ * `{ notModified: true }` on 304. Returns `null` on any failure —
97
+ * the caller decides how to fall back.
98
+ */
99
+ declare function fetchEdgeConfig(config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>, counterpartyId: string, opts?: {
100
+ etag?: string;
101
+ timeoutMs?: number;
102
+ }): Promise<FetchEdgeConfigResult>;
103
+ /** Copy of `config` with every enforce (top-level and per-rule) degraded to observe. */
104
+ declare function degradeToObserve(config: EdgeConfig): EdgeConfig;
105
+ /**
106
+ * Get the edge config for an endpoint, cached. Never throws, never blocks
107
+ * longer than one fetch.
108
+ *
109
+ * - Fresh cache (within `ttlMs`) → cached config, no network.
110
+ * - Stale cache → cached config immediately + background revalidate
111
+ * (stale-while-revalidate). If the last successful fetch is older than
112
+ * `maxStaleMs` (default 24h), any enforce is degraded to observe — a
113
+ * long-dead backend can never keep a site enforcing.
114
+ * - No cache → await one fetch; on failure return `DEFAULT_EDGE_CONFIG`
115
+ * (observe-only). Defaults never enforce.
116
+ */
117
+ declare function getEdgeConfig(config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>, counterpartyId: string, opts?: {
118
+ ttlMs?: number;
119
+ maxStaleMs?: number;
120
+ }): Promise<EdgeConfig>;
121
+ /**
122
+ * First-match-wins path-rule lookup. Case-insensitive `*` globs with all
123
+ * other regex metacharacters escaped (a literal `.` in a pattern matches
124
+ * only `.`). Returns `undefined` when no rule matches — the caller applies
125
+ * the config's top-level mode/depth.
126
+ */
127
+ declare function matchEdgePathRule(rules: EdgePathRule[], path: string): EdgePathRule | undefined;
128
+ /** Reset cache — for testing only. */
129
+ declare function _resetEdgeConfigCache(): void;
130
+
131
+ export { DEFAULT_EDGE_CONFIG, type EdgeConfig, type EdgeMode, type EdgePathRule, type EdgeVerificationDepth, type FetchEdgeConfigResult, type FetchEdgeConfigSuccess, _resetEdgeConfigCache, degradeToObserve, fetchEdgeConfig, getEdgeConfig, isEdgeConfig, matchEdgePathRule };
@@ -0,0 +1,131 @@
1
+ import { G as GatewayConfig } from './types-9tns4wyl.js';
2
+ import './metadata-capture.js';
3
+
4
+ /**
5
+ * Edge verification config — the per-endpoint policy the Commerce Shield
6
+ * edge adapter (§7.4, `@astrasyncai/adapter-lambda`) fetches from the
7
+ * AstraSync dashboard to decide how much verification friction to apply
8
+ * to inbound traffic, and where.
9
+ *
10
+ * Fetch pattern mirrors `well-known.ts`: TTL cache + stale-while-revalidate
11
+ * + in-flight dedupe, with a `_reset*` hook for tests. Fail posture is
12
+ * deliberately asymmetric: this module can NEVER put a site into enforce
13
+ * mode on its own — enforce only ever originates from a successfully
14
+ * fetched config, and a config that has gone stale past `maxStaleMs`
15
+ * degrades back to observe.
16
+ */
17
+
18
+ /**
19
+ * Edge posture. Canonical Commerce Shield vocabulary (strategy doc /
20
+ * spec §33.5): `observe` ≈ the gateway's `passive` posture (verify +
21
+ * record, enforce nothing), `enforce` ≈ `active`. New value set on a new
22
+ * field name — do NOT reuse `GatewayPosture`'s `active`/`passive` here
23
+ * (different field, different meaning: posture governs an agent-side
24
+ * gateway; mode governs counterparty-side edge interception).
25
+ */
26
+ type EdgeMode = 'observe' | 'enforce';
27
+ /**
28
+ * How deep the edge checks each request — what is it → who is it → are
29
+ * they allowed:
30
+ * - `classify` — UA / platform-fingerprint classification only; no
31
+ * credential handling.
32
+ * - `authenticate` — establish who is calling: detect and parse agent
33
+ * credentials (X-Astra-*, VI SD-JWT, RFC 9421, ACP,
34
+ * UCP, AP2…) and verify presented AstraSync identities.
35
+ * - `authorize` — full policy decision: credentials cryptographically
36
+ * proven and PDLSS-evaluated via a verify-access round
37
+ * trip. (US spelling on the wire, matching
38
+ * `authorizeSettlement` and HTTP `Authorization`.)
39
+ */
40
+ type EdgeVerificationDepth = 'classify' | 'authenticate' | 'authorize';
41
+ interface EdgePathRule {
42
+ /**
43
+ * `*`-wildcard glob matched against the request path. Matching is
44
+ * case-INsensitive and all regex metacharacters except `*` are
45
+ * escaped. (Deliberately diverges from the express adapter's
46
+ * `matchRoute`, which is case-sensitive by default and mid-shadow-
47
+ * rollout of the F-A6-31 fix — new surface ships the fix as default.)
48
+ */
49
+ pattern: string;
50
+ /** Pass the request through untouched (static assets); mode/depth ignored. */
51
+ skip?: boolean;
52
+ /** Override the top-level mode for this path. */
53
+ mode?: EdgeMode;
54
+ /** Override the top-level depth for this path. */
55
+ depth?: EdgeVerificationDepth;
56
+ }
57
+ interface EdgeConfig {
58
+ /** Shape version — bump on breaking changes. */
59
+ version: 1;
60
+ /** Default posture for paths no rule matches. */
61
+ mode: EdgeMode;
62
+ /** Default check depth for paths no rule matches. */
63
+ depth: EdgeVerificationDepth;
64
+ /** Ordered, first-match-wins. */
65
+ pathRules: EdgePathRule[];
66
+ sampling: {
67
+ /** Fraction (0..1) of anonymous-bot requests that emit a beacon. */
68
+ anonymousBeaconRate: number;
69
+ };
70
+ /**
71
+ * v1: only 'open' is representable — an unreachable backend always
72
+ * means observe + pass-through, never a broken or silently-enforcing
73
+ * customer site.
74
+ */
75
+ failurePosture: 'open';
76
+ }
77
+ /**
78
+ * The safe default: observe-only, classification depth, nothing enforced.
79
+ * Served by the backend when an endpoint has never been configured, and
80
+ * used by `getEdgeConfig` whenever no config can be fetched.
81
+ */
82
+ declare const DEFAULT_EDGE_CONFIG: EdgeConfig;
83
+ /** Structural guard for configs arriving over the wire. */
84
+ declare function isEdgeConfig(value: unknown): value is EdgeConfig;
85
+ interface FetchEdgeConfigSuccess {
86
+ edgeConfig: EdgeConfig;
87
+ etag?: string;
88
+ }
89
+ type FetchEdgeConfigResult = FetchEdgeConfigSuccess | {
90
+ notModified: true;
91
+ } | null;
92
+ /**
93
+ * Fetch the edge config for an endpoint from the AstraSync backend.
94
+ * `GET {apiBaseUrl}/endpoints/:counterpartyId/edge-config` with the same
95
+ * auth headers as `fetchRoutes`. Pass the cached `etag` to get a cheap
96
+ * `{ notModified: true }` on 304. Returns `null` on any failure —
97
+ * the caller decides how to fall back.
98
+ */
99
+ declare function fetchEdgeConfig(config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>, counterpartyId: string, opts?: {
100
+ etag?: string;
101
+ timeoutMs?: number;
102
+ }): Promise<FetchEdgeConfigResult>;
103
+ /** Copy of `config` with every enforce (top-level and per-rule) degraded to observe. */
104
+ declare function degradeToObserve(config: EdgeConfig): EdgeConfig;
105
+ /**
106
+ * Get the edge config for an endpoint, cached. Never throws, never blocks
107
+ * longer than one fetch.
108
+ *
109
+ * - Fresh cache (within `ttlMs`) → cached config, no network.
110
+ * - Stale cache → cached config immediately + background revalidate
111
+ * (stale-while-revalidate). If the last successful fetch is older than
112
+ * `maxStaleMs` (default 24h), any enforce is degraded to observe — a
113
+ * long-dead backend can never keep a site enforcing.
114
+ * - No cache → await one fetch; on failure return `DEFAULT_EDGE_CONFIG`
115
+ * (observe-only). Defaults never enforce.
116
+ */
117
+ declare function getEdgeConfig(config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>, counterpartyId: string, opts?: {
118
+ ttlMs?: number;
119
+ maxStaleMs?: number;
120
+ }): Promise<EdgeConfig>;
121
+ /**
122
+ * First-match-wins path-rule lookup. Case-insensitive `*` globs with all
123
+ * other regex metacharacters escaped (a literal `.` in a pattern matches
124
+ * only `.`). Returns `undefined` when no rule matches — the caller applies
125
+ * the config's top-level mode/depth.
126
+ */
127
+ declare function matchEdgePathRule(rules: EdgePathRule[], path: string): EdgePathRule | undefined;
128
+ /** Reset cache — for testing only. */
129
+ declare function _resetEdgeConfigCache(): void;
130
+
131
+ export { DEFAULT_EDGE_CONFIG, type EdgeConfig, type EdgeMode, type EdgePathRule, type EdgeVerificationDepth, type FetchEdgeConfigResult, type FetchEdgeConfigSuccess, _resetEdgeConfigCache, degradeToObserve, fetchEdgeConfig, getEdgeConfig, isEdgeConfig, matchEdgePathRule };
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/edge-config.ts
21
+ var edge_config_exports = {};
22
+ __export(edge_config_exports, {
23
+ DEFAULT_EDGE_CONFIG: () => DEFAULT_EDGE_CONFIG,
24
+ _resetEdgeConfigCache: () => _resetEdgeConfigCache,
25
+ degradeToObserve: () => degradeToObserve,
26
+ fetchEdgeConfig: () => fetchEdgeConfig,
27
+ getEdgeConfig: () => getEdgeConfig,
28
+ isEdgeConfig: () => isEdgeConfig,
29
+ matchEdgePathRule: () => matchEdgePathRule
30
+ });
31
+ module.exports = __toCommonJS(edge_config_exports);
32
+ var DEFAULT_EDGE_CONFIG = Object.freeze({
33
+ version: 1,
34
+ mode: "observe",
35
+ depth: "classify",
36
+ pathRules: [],
37
+ sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
38
+ failurePosture: "open"
39
+ });
40
+ var EDGE_MODES = ["observe", "enforce"];
41
+ var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
42
+ function isEdgeConfig(value) {
43
+ if (typeof value !== "object" || value === null) return false;
44
+ const v = value;
45
+ if (v.version !== 1) return false;
46
+ if (!EDGE_MODES.includes(v.mode)) return false;
47
+ if (!EDGE_DEPTHS.includes(v.depth)) return false;
48
+ if (!Array.isArray(v.pathRules)) return false;
49
+ for (const rule of v.pathRules) {
50
+ if (typeof rule !== "object" || rule === null) return false;
51
+ const r = rule;
52
+ if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
53
+ if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
54
+ if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
55
+ }
56
+ const sampling = v.sampling;
57
+ if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
58
+ return false;
59
+ }
60
+ return v.failurePosture === "open";
61
+ }
62
+ async function fetchEdgeConfig(config, counterpartyId, opts) {
63
+ if (!counterpartyId) return null;
64
+ const headers = { Accept: "application/json" };
65
+ if (config.apiKey) {
66
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
67
+ headers["X-API-Key"] = config.apiKey;
68
+ }
69
+ if (opts?.etag) headers["If-None-Match"] = opts.etag;
70
+ try {
71
+ const response = await fetch(
72
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
73
+ { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
74
+ );
75
+ if (response.status === 304) return { notModified: true };
76
+ if (!response.ok) return null;
77
+ const body = await response.json();
78
+ const edgeConfig = body.data?.edgeConfig;
79
+ if (!isEdgeConfig(edgeConfig)) return null;
80
+ return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
81
+ } catch {
82
+ return null;
83
+ }
84
+ }
85
+ var DEFAULT_TTL_MS = 60 * 1e3;
86
+ var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
87
+ var cache = /* @__PURE__ */ new Map();
88
+ var inflight = /* @__PURE__ */ new Map();
89
+ function cacheKey(apiBaseUrl, counterpartyId) {
90
+ return `${apiBaseUrl}|${counterpartyId}`;
91
+ }
92
+ function degradeToObserve(config) {
93
+ if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
94
+ return config;
95
+ }
96
+ return {
97
+ ...config,
98
+ mode: "observe",
99
+ pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
100
+ };
101
+ }
102
+ async function revalidate(config, counterpartyId) {
103
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
104
+ const existing = inflight.get(key);
105
+ if (existing) return existing;
106
+ const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache.get(key)?.etag }).then((result) => {
107
+ if (result === null) return;
108
+ const now = Date.now();
109
+ if ("notModified" in result) {
110
+ const entry = cache.get(key);
111
+ if (entry) entry.lastSuccessAt = now;
112
+ return;
113
+ }
114
+ cache.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
115
+ }).finally(() => {
116
+ inflight.delete(key);
117
+ });
118
+ inflight.set(key, promise);
119
+ return promise;
120
+ }
121
+ async function getEdgeConfig(config, counterpartyId, opts) {
122
+ const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
123
+ const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
124
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
125
+ const entry = cache.get(key);
126
+ if (entry) {
127
+ const age = Date.now() - entry.lastSuccessAt;
128
+ if (age > ttlMs) {
129
+ revalidate(config, counterpartyId).catch(() => {
130
+ });
131
+ }
132
+ return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
133
+ }
134
+ await revalidate(config, counterpartyId).catch(() => {
135
+ });
136
+ return cache.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
137
+ }
138
+ function matchEdgePathRule(rules, path) {
139
+ for (const rule of rules) {
140
+ if (globToRegExp(rule.pattern).test(path)) return rule;
141
+ }
142
+ return void 0;
143
+ }
144
+ function globToRegExp(pattern) {
145
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
146
+ return new RegExp(`^${escaped}$`, "i");
147
+ }
148
+ function _resetEdgeConfigCache() {
149
+ cache.clear();
150
+ inflight.clear();
151
+ }
152
+ // Annotate the CommonJS export names for ESM import in node:
153
+ 0 && (module.exports = {
154
+ DEFAULT_EDGE_CONFIG,
155
+ _resetEdgeConfigCache,
156
+ degradeToObserve,
157
+ fetchEdgeConfig,
158
+ getEdgeConfig,
159
+ isEdgeConfig,
160
+ matchEdgePathRule
161
+ });
162
+ //# sourceMappingURL=edge-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/edge-config.ts"],"sourcesContent":["/**\n * Edge verification config — the per-endpoint policy the Commerce Shield\n * edge adapter (§7.4, `@astrasyncai/adapter-lambda`) fetches from the\n * AstraSync dashboard to decide how much verification friction to apply\n * to inbound traffic, and where.\n *\n * Fetch pattern mirrors `well-known.ts`: TTL cache + stale-while-revalidate\n * + in-flight dedupe, with a `_reset*` hook for tests. Fail posture is\n * deliberately asymmetric: this module can NEVER put a site into enforce\n * mode on its own — enforce only ever originates from a successfully\n * fetched config, and a config that has gone stale past `maxStaleMs`\n * degrades back to observe.\n */\n\nimport type { GatewayConfig } from './types';\n\n/**\n * Edge posture. Canonical Commerce Shield vocabulary (strategy doc /\n * spec §33.5): `observe` ≈ the gateway's `passive` posture (verify +\n * record, enforce nothing), `enforce` ≈ `active`. New value set on a new\n * field name — do NOT reuse `GatewayPosture`'s `active`/`passive` here\n * (different field, different meaning: posture governs an agent-side\n * gateway; mode governs counterparty-side edge interception).\n */\nexport type EdgeMode = 'observe' | 'enforce';\n\n/**\n * How deep the edge checks each request — what is it → who is it → are\n * they allowed:\n * - `classify` — UA / platform-fingerprint classification only; no\n * credential handling.\n * - `authenticate` — establish who is calling: detect and parse agent\n * credentials (X-Astra-*, VI SD-JWT, RFC 9421, ACP,\n * UCP, AP2…) and verify presented AstraSync identities.\n * - `authorize` — full policy decision: credentials cryptographically\n * proven and PDLSS-evaluated via a verify-access round\n * trip. (US spelling on the wire, matching\n * `authorizeSettlement` and HTTP `Authorization`.)\n */\nexport type EdgeVerificationDepth = 'classify' | 'authenticate' | 'authorize';\n\nexport interface EdgePathRule {\n /**\n * `*`-wildcard glob matched against the request path. Matching is\n * case-INsensitive and all regex metacharacters except `*` are\n * escaped. (Deliberately diverges from the express adapter's\n * `matchRoute`, which is case-sensitive by default and mid-shadow-\n * rollout of the F-A6-31 fix — new surface ships the fix as default.)\n */\n pattern: string;\n /** Pass the request through untouched (static assets); mode/depth ignored. */\n skip?: boolean;\n /** Override the top-level mode for this path. */\n mode?: EdgeMode;\n /** Override the top-level depth for this path. */\n depth?: EdgeVerificationDepth;\n}\n\nexport interface EdgeConfig {\n /** Shape version — bump on breaking changes. */\n version: 1;\n /** Default posture for paths no rule matches. */\n mode: EdgeMode;\n /** Default check depth for paths no rule matches. */\n depth: EdgeVerificationDepth;\n /** Ordered, first-match-wins. */\n pathRules: EdgePathRule[];\n sampling: {\n /** Fraction (0..1) of anonymous-bot requests that emit a beacon. */\n anonymousBeaconRate: number;\n };\n /**\n * v1: only 'open' is representable — an unreachable backend always\n * means observe + pass-through, never a broken or silently-enforcing\n * customer site.\n */\n failurePosture: 'open';\n}\n\n/**\n * The safe default: observe-only, classification depth, nothing enforced.\n * Served by the backend when an endpoint has never been configured, and\n * used by `getEdgeConfig` whenever no config can be fetched.\n */\nexport const DEFAULT_EDGE_CONFIG: EdgeConfig = Object.freeze({\n version: 1,\n mode: 'observe',\n depth: 'classify',\n pathRules: [],\n sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),\n failurePosture: 'open',\n}) as EdgeConfig;\n\nconst EDGE_MODES: readonly string[] = ['observe', 'enforce'];\nconst EDGE_DEPTHS: readonly string[] = ['classify', 'authenticate', 'authorize'];\n\n/** Structural guard for configs arriving over the wire. */\nexport function isEdgeConfig(value: unknown): value is EdgeConfig {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n if (v.version !== 1) return false;\n if (!EDGE_MODES.includes(v.mode as string)) return false;\n if (!EDGE_DEPTHS.includes(v.depth as string)) return false;\n if (!Array.isArray(v.pathRules)) return false;\n for (const rule of v.pathRules) {\n if (typeof rule !== 'object' || rule === null) return false;\n const r = rule as Record<string, unknown>;\n if (typeof r.pattern !== 'string' || r.pattern.length === 0) return false;\n if (r.mode !== undefined && !EDGE_MODES.includes(r.mode as string)) return false;\n if (r.depth !== undefined && !EDGE_DEPTHS.includes(r.depth as string)) return false;\n }\n const sampling = v.sampling as Record<string, unknown> | undefined;\n if (\n typeof sampling !== 'object' ||\n sampling === null ||\n typeof sampling.anonymousBeaconRate !== 'number' ||\n sampling.anonymousBeaconRate < 0 ||\n sampling.anonymousBeaconRate > 1\n ) {\n return false;\n }\n return v.failurePosture === 'open';\n}\n\nexport interface FetchEdgeConfigSuccess {\n edgeConfig: EdgeConfig;\n etag?: string;\n}\n\nexport type FetchEdgeConfigResult = FetchEdgeConfigSuccess | { notModified: true } | null;\n\n/**\n * Fetch the edge config for an endpoint from the AstraSync backend.\n * `GET {apiBaseUrl}/endpoints/:counterpartyId/edge-config` with the same\n * auth headers as `fetchRoutes`. Pass the cached `etag` to get a cheap\n * `{ notModified: true }` on 304. Returns `null` on any failure —\n * the caller decides how to fall back.\n */\nexport async function fetchEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { etag?: string; timeoutMs?: number }\n): Promise<FetchEdgeConfigResult> {\n if (!counterpartyId) return null;\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n if (opts?.etag) headers['If-None-Match'] = opts.etag;\n try {\n const response = await fetch(\n `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,\n { method: 'GET', headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5000) }\n );\n if (response.status === 304) return { notModified: true };\n if (!response.ok) return null;\n const body = (await response.json()) as { data?: { edgeConfig?: unknown } };\n const edgeConfig = body.data?.edgeConfig;\n if (!isEdgeConfig(edgeConfig)) return null;\n return { edgeConfig, etag: response.headers.get('etag') ?? undefined };\n } catch {\n return null;\n }\n}\n\ninterface CacheEntry {\n config: EdgeConfig;\n etag?: string;\n /** When the entry was last confirmed fresh (fetch or 304). */\n lastSuccessAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 1000;\nconst DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1000;\n\nconst cache = new Map<string, CacheEntry>();\nconst inflight = new Map<string, Promise<void>>();\n\nfunction cacheKey(apiBaseUrl: string, counterpartyId: string): string {\n return `${apiBaseUrl}|${counterpartyId}`;\n}\n\n/** Copy of `config` with every enforce (top-level and per-rule) degraded to observe. */\nexport function degradeToObserve(config: EdgeConfig): EdgeConfig {\n if (config.mode !== 'enforce' && !config.pathRules.some((r) => r.mode === 'enforce')) {\n return config;\n }\n return {\n ...config,\n mode: 'observe',\n pathRules: config.pathRules.map((r) => (r.mode === 'enforce' ? { ...r, mode: 'observe' } : r)),\n };\n}\n\nasync function revalidate(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string\n): Promise<void> {\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n const existing = inflight.get(key);\n if (existing) return existing;\n\n const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache.get(key)?.etag })\n .then((result) => {\n if (result === null) return; // failure — cache untouched, caller falls back\n const now = Date.now();\n if ('notModified' in result) {\n const entry = cache.get(key);\n if (entry) entry.lastSuccessAt = now;\n return;\n }\n cache.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });\n })\n .finally(() => {\n inflight.delete(key);\n });\n\n inflight.set(key, promise);\n return promise;\n}\n\n/**\n * Get the edge config for an endpoint, cached. Never throws, never blocks\n * longer than one fetch.\n *\n * - Fresh cache (within `ttlMs`) → cached config, no network.\n * - Stale cache → cached config immediately + background revalidate\n * (stale-while-revalidate). If the last successful fetch is older than\n * `maxStaleMs` (default 24h), any enforce is degraded to observe — a\n * long-dead backend can never keep a site enforcing.\n * - No cache → await one fetch; on failure return `DEFAULT_EDGE_CONFIG`\n * (observe-only). Defaults never enforce.\n */\nexport async function getEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { ttlMs?: number; maxStaleMs?: number }\n): Promise<EdgeConfig> {\n const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;\n const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n\n const entry = cache.get(key);\n if (entry) {\n const age = Date.now() - entry.lastSuccessAt;\n if (age > ttlMs) {\n revalidate(config, counterpartyId).catch(() => {\n // background refresh failed — stale entry remains until next call\n });\n }\n return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;\n }\n\n await revalidate(config, counterpartyId).catch(() => {\n // fetch failed — fall through to defaults\n });\n return cache.get(key)?.config ?? DEFAULT_EDGE_CONFIG;\n}\n\n/**\n * First-match-wins path-rule lookup. Case-insensitive `*` globs with all\n * other regex metacharacters escaped (a literal `.` in a pattern matches\n * only `.`). Returns `undefined` when no rule matches — the caller applies\n * the config's top-level mode/depth.\n */\nexport function matchEdgePathRule(rules: EdgePathRule[], path: string): EdgePathRule | undefined {\n for (const rule of rules) {\n if (globToRegExp(rule.pattern).test(path)) return rule;\n }\n return undefined;\n}\n\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`, 'i');\n}\n\n/** Reset cache — for testing only. */\nexport function _resetEdgeConfigCache(): void {\n cache.clear();\n inflight.clear();\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,131 @@
1
+ // src/edge-config.ts
2
+ var DEFAULT_EDGE_CONFIG = Object.freeze({
3
+ version: 1,
4
+ mode: "observe",
5
+ depth: "classify",
6
+ pathRules: [],
7
+ sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
8
+ failurePosture: "open"
9
+ });
10
+ var EDGE_MODES = ["observe", "enforce"];
11
+ var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
12
+ function isEdgeConfig(value) {
13
+ if (typeof value !== "object" || value === null) return false;
14
+ const v = value;
15
+ if (v.version !== 1) return false;
16
+ if (!EDGE_MODES.includes(v.mode)) return false;
17
+ if (!EDGE_DEPTHS.includes(v.depth)) return false;
18
+ if (!Array.isArray(v.pathRules)) return false;
19
+ for (const rule of v.pathRules) {
20
+ if (typeof rule !== "object" || rule === null) return false;
21
+ const r = rule;
22
+ if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
23
+ if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
24
+ if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
25
+ }
26
+ const sampling = v.sampling;
27
+ if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
28
+ return false;
29
+ }
30
+ return v.failurePosture === "open";
31
+ }
32
+ async function fetchEdgeConfig(config, counterpartyId, opts) {
33
+ if (!counterpartyId) return null;
34
+ const headers = { Accept: "application/json" };
35
+ if (config.apiKey) {
36
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
37
+ headers["X-API-Key"] = config.apiKey;
38
+ }
39
+ if (opts?.etag) headers["If-None-Match"] = opts.etag;
40
+ try {
41
+ const response = await fetch(
42
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
43
+ { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
44
+ );
45
+ if (response.status === 304) return { notModified: true };
46
+ if (!response.ok) return null;
47
+ const body = await response.json();
48
+ const edgeConfig = body.data?.edgeConfig;
49
+ if (!isEdgeConfig(edgeConfig)) return null;
50
+ return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+ var DEFAULT_TTL_MS = 60 * 1e3;
56
+ var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
57
+ var cache = /* @__PURE__ */ new Map();
58
+ var inflight = /* @__PURE__ */ new Map();
59
+ function cacheKey(apiBaseUrl, counterpartyId) {
60
+ return `${apiBaseUrl}|${counterpartyId}`;
61
+ }
62
+ function degradeToObserve(config) {
63
+ if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
64
+ return config;
65
+ }
66
+ return {
67
+ ...config,
68
+ mode: "observe",
69
+ pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
70
+ };
71
+ }
72
+ async function revalidate(config, counterpartyId) {
73
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
74
+ const existing = inflight.get(key);
75
+ if (existing) return existing;
76
+ const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache.get(key)?.etag }).then((result) => {
77
+ if (result === null) return;
78
+ const now = Date.now();
79
+ if ("notModified" in result) {
80
+ const entry = cache.get(key);
81
+ if (entry) entry.lastSuccessAt = now;
82
+ return;
83
+ }
84
+ cache.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
85
+ }).finally(() => {
86
+ inflight.delete(key);
87
+ });
88
+ inflight.set(key, promise);
89
+ return promise;
90
+ }
91
+ async function getEdgeConfig(config, counterpartyId, opts) {
92
+ const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
93
+ const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
94
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
95
+ const entry = cache.get(key);
96
+ if (entry) {
97
+ const age = Date.now() - entry.lastSuccessAt;
98
+ if (age > ttlMs) {
99
+ revalidate(config, counterpartyId).catch(() => {
100
+ });
101
+ }
102
+ return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
103
+ }
104
+ await revalidate(config, counterpartyId).catch(() => {
105
+ });
106
+ return cache.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
107
+ }
108
+ function matchEdgePathRule(rules, path) {
109
+ for (const rule of rules) {
110
+ if (globToRegExp(rule.pattern).test(path)) return rule;
111
+ }
112
+ return void 0;
113
+ }
114
+ function globToRegExp(pattern) {
115
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
116
+ return new RegExp(`^${escaped}$`, "i");
117
+ }
118
+ function _resetEdgeConfigCache() {
119
+ cache.clear();
120
+ inflight.clear();
121
+ }
122
+ export {
123
+ DEFAULT_EDGE_CONFIG,
124
+ _resetEdgeConfigCache,
125
+ degradeToObserve,
126
+ fetchEdgeConfig,
127
+ getEdgeConfig,
128
+ isEdgeConfig,
129
+ matchEdgePathRule
130
+ };
131
+ //# sourceMappingURL=edge-config.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/edge-config.ts"],"sourcesContent":["/**\n * Edge verification config — the per-endpoint policy the Commerce Shield\n * edge adapter (§7.4, `@astrasyncai/adapter-lambda`) fetches from the\n * AstraSync dashboard to decide how much verification friction to apply\n * to inbound traffic, and where.\n *\n * Fetch pattern mirrors `well-known.ts`: TTL cache + stale-while-revalidate\n * + in-flight dedupe, with a `_reset*` hook for tests. Fail posture is\n * deliberately asymmetric: this module can NEVER put a site into enforce\n * mode on its own — enforce only ever originates from a successfully\n * fetched config, and a config that has gone stale past `maxStaleMs`\n * degrades back to observe.\n */\n\nimport type { GatewayConfig } from './types';\n\n/**\n * Edge posture. Canonical Commerce Shield vocabulary (strategy doc /\n * spec §33.5): `observe` ≈ the gateway's `passive` posture (verify +\n * record, enforce nothing), `enforce` ≈ `active`. New value set on a new\n * field name — do NOT reuse `GatewayPosture`'s `active`/`passive` here\n * (different field, different meaning: posture governs an agent-side\n * gateway; mode governs counterparty-side edge interception).\n */\nexport type EdgeMode = 'observe' | 'enforce';\n\n/**\n * How deep the edge checks each request — what is it → who is it → are\n * they allowed:\n * - `classify` — UA / platform-fingerprint classification only; no\n * credential handling.\n * - `authenticate` — establish who is calling: detect and parse agent\n * credentials (X-Astra-*, VI SD-JWT, RFC 9421, ACP,\n * UCP, AP2…) and verify presented AstraSync identities.\n * - `authorize` — full policy decision: credentials cryptographically\n * proven and PDLSS-evaluated via a verify-access round\n * trip. (US spelling on the wire, matching\n * `authorizeSettlement` and HTTP `Authorization`.)\n */\nexport type EdgeVerificationDepth = 'classify' | 'authenticate' | 'authorize';\n\nexport interface EdgePathRule {\n /**\n * `*`-wildcard glob matched against the request path. Matching is\n * case-INsensitive and all regex metacharacters except `*` are\n * escaped. (Deliberately diverges from the express adapter's\n * `matchRoute`, which is case-sensitive by default and mid-shadow-\n * rollout of the F-A6-31 fix — new surface ships the fix as default.)\n */\n pattern: string;\n /** Pass the request through untouched (static assets); mode/depth ignored. */\n skip?: boolean;\n /** Override the top-level mode for this path. */\n mode?: EdgeMode;\n /** Override the top-level depth for this path. */\n depth?: EdgeVerificationDepth;\n}\n\nexport interface EdgeConfig {\n /** Shape version — bump on breaking changes. */\n version: 1;\n /** Default posture for paths no rule matches. */\n mode: EdgeMode;\n /** Default check depth for paths no rule matches. */\n depth: EdgeVerificationDepth;\n /** Ordered, first-match-wins. */\n pathRules: EdgePathRule[];\n sampling: {\n /** Fraction (0..1) of anonymous-bot requests that emit a beacon. */\n anonymousBeaconRate: number;\n };\n /**\n * v1: only 'open' is representable — an unreachable backend always\n * means observe + pass-through, never a broken or silently-enforcing\n * customer site.\n */\n failurePosture: 'open';\n}\n\n/**\n * The safe default: observe-only, classification depth, nothing enforced.\n * Served by the backend when an endpoint has never been configured, and\n * used by `getEdgeConfig` whenever no config can be fetched.\n */\nexport const DEFAULT_EDGE_CONFIG: EdgeConfig = Object.freeze({\n version: 1,\n mode: 'observe',\n depth: 'classify',\n pathRules: [],\n sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),\n failurePosture: 'open',\n}) as EdgeConfig;\n\nconst EDGE_MODES: readonly string[] = ['observe', 'enforce'];\nconst EDGE_DEPTHS: readonly string[] = ['classify', 'authenticate', 'authorize'];\n\n/** Structural guard for configs arriving over the wire. */\nexport function isEdgeConfig(value: unknown): value is EdgeConfig {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n if (v.version !== 1) return false;\n if (!EDGE_MODES.includes(v.mode as string)) return false;\n if (!EDGE_DEPTHS.includes(v.depth as string)) return false;\n if (!Array.isArray(v.pathRules)) return false;\n for (const rule of v.pathRules) {\n if (typeof rule !== 'object' || rule === null) return false;\n const r = rule as Record<string, unknown>;\n if (typeof r.pattern !== 'string' || r.pattern.length === 0) return false;\n if (r.mode !== undefined && !EDGE_MODES.includes(r.mode as string)) return false;\n if (r.depth !== undefined && !EDGE_DEPTHS.includes(r.depth as string)) return false;\n }\n const sampling = v.sampling as Record<string, unknown> | undefined;\n if (\n typeof sampling !== 'object' ||\n sampling === null ||\n typeof sampling.anonymousBeaconRate !== 'number' ||\n sampling.anonymousBeaconRate < 0 ||\n sampling.anonymousBeaconRate > 1\n ) {\n return false;\n }\n return v.failurePosture === 'open';\n}\n\nexport interface FetchEdgeConfigSuccess {\n edgeConfig: EdgeConfig;\n etag?: string;\n}\n\nexport type FetchEdgeConfigResult = FetchEdgeConfigSuccess | { notModified: true } | null;\n\n/**\n * Fetch the edge config for an endpoint from the AstraSync backend.\n * `GET {apiBaseUrl}/endpoints/:counterpartyId/edge-config` with the same\n * auth headers as `fetchRoutes`. Pass the cached `etag` to get a cheap\n * `{ notModified: true }` on 304. Returns `null` on any failure —\n * the caller decides how to fall back.\n */\nexport async function fetchEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { etag?: string; timeoutMs?: number }\n): Promise<FetchEdgeConfigResult> {\n if (!counterpartyId) return null;\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n if (opts?.etag) headers['If-None-Match'] = opts.etag;\n try {\n const response = await fetch(\n `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,\n { method: 'GET', headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5000) }\n );\n if (response.status === 304) return { notModified: true };\n if (!response.ok) return null;\n const body = (await response.json()) as { data?: { edgeConfig?: unknown } };\n const edgeConfig = body.data?.edgeConfig;\n if (!isEdgeConfig(edgeConfig)) return null;\n return { edgeConfig, etag: response.headers.get('etag') ?? undefined };\n } catch {\n return null;\n }\n}\n\ninterface CacheEntry {\n config: EdgeConfig;\n etag?: string;\n /** When the entry was last confirmed fresh (fetch or 304). */\n lastSuccessAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 1000;\nconst DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1000;\n\nconst cache = new Map<string, CacheEntry>();\nconst inflight = new Map<string, Promise<void>>();\n\nfunction cacheKey(apiBaseUrl: string, counterpartyId: string): string {\n return `${apiBaseUrl}|${counterpartyId}`;\n}\n\n/** Copy of `config` with every enforce (top-level and per-rule) degraded to observe. */\nexport function degradeToObserve(config: EdgeConfig): EdgeConfig {\n if (config.mode !== 'enforce' && !config.pathRules.some((r) => r.mode === 'enforce')) {\n return config;\n }\n return {\n ...config,\n mode: 'observe',\n pathRules: config.pathRules.map((r) => (r.mode === 'enforce' ? { ...r, mode: 'observe' } : r)),\n };\n}\n\nasync function revalidate(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string\n): Promise<void> {\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n const existing = inflight.get(key);\n if (existing) return existing;\n\n const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache.get(key)?.etag })\n .then((result) => {\n if (result === null) return; // failure — cache untouched, caller falls back\n const now = Date.now();\n if ('notModified' in result) {\n const entry = cache.get(key);\n if (entry) entry.lastSuccessAt = now;\n return;\n }\n cache.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });\n })\n .finally(() => {\n inflight.delete(key);\n });\n\n inflight.set(key, promise);\n return promise;\n}\n\n/**\n * Get the edge config for an endpoint, cached. Never throws, never blocks\n * longer than one fetch.\n *\n * - Fresh cache (within `ttlMs`) → cached config, no network.\n * - Stale cache → cached config immediately + background revalidate\n * (stale-while-revalidate). If the last successful fetch is older than\n * `maxStaleMs` (default 24h), any enforce is degraded to observe — a\n * long-dead backend can never keep a site enforcing.\n * - No cache → await one fetch; on failure return `DEFAULT_EDGE_CONFIG`\n * (observe-only). Defaults never enforce.\n */\nexport async function getEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { ttlMs?: number; maxStaleMs?: number }\n): Promise<EdgeConfig> {\n const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;\n const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n\n const entry = cache.get(key);\n if (entry) {\n const age = Date.now() - entry.lastSuccessAt;\n if (age > ttlMs) {\n revalidate(config, counterpartyId).catch(() => {\n // background refresh failed — stale entry remains until next call\n });\n }\n return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;\n }\n\n await revalidate(config, counterpartyId).catch(() => {\n // fetch failed — fall through to defaults\n });\n return cache.get(key)?.config ?? DEFAULT_EDGE_CONFIG;\n}\n\n/**\n * First-match-wins path-rule lookup. Case-insensitive `*` globs with all\n * other regex metacharacters escaped (a literal `.` in a pattern matches\n * only `.`). Returns `undefined` when no rule matches — the caller applies\n * the config's top-level mode/depth.\n */\nexport function matchEdgePathRule(rules: EdgePathRule[], path: string): EdgePathRule | undefined {\n for (const rule of rules) {\n if (globToRegExp(rule.pattern).test(path)) return rule;\n }\n return undefined;\n}\n\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`, 'i');\n}\n\n/** Reset cache — for testing only. */\nexport function _resetEdgeConfigCache(): void {\n cache.clear();\n inflight.clear();\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler, Request } from 'express';
2
- import { q as VerificationResult, e as ExpressMiddlewareOptions, c as AstraSyncCredentials } from './types-DedAJbNI.js';
2
+ import { r as VerificationResult, f as ExpressMiddlewareOptions, c as AstraSyncCredentials } from './types-9tns4wyl.js';
3
3
 
4
4
  /**
5
5
  * AstraSync Universal Verification Gateway - Express Middleware
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler, Request } from 'express';
2
- import { q as VerificationResult, e as ExpressMiddlewareOptions, c as AstraSyncCredentials } from './types-DedAJbNI.mjs';
2
+ import { r as VerificationResult, f as ExpressMiddlewareOptions, c as AstraSyncCredentials } from './types-sy3tq8lp.mjs';
3
3
 
4
4
  /**
5
5
  * AstraSync Universal Verification Gateway - Express Middleware
@@ -1,5 +1,6 @@
1
- import { a as AstraSyncGatewayConfig, P as PDLSSContext, V as VerificationDecision } from '../types-CSFci5zD.mjs';
2
- import '../types-DedAJbNI.mjs';
1
+ import { a as AstraSyncGatewayConfig, P as PDLSSContext, V as VerificationDecision } from '../types-D0lCtFQ7.mjs';
2
+ import '../types-sy3tq8lp.mjs';
3
+ import '../metadata-capture.mjs';
3
4
 
4
5
  /**
5
6
  * AstraSyncGateway — Primary API surface for agent verification.
@@ -1,5 +1,6 @@
1
- import { a as AstraSyncGatewayConfig, P as PDLSSContext, V as VerificationDecision } from '../types-D1kyMiml.js';
2
- import '../types-DedAJbNI.js';
1
+ import { a as AstraSyncGatewayConfig, P as PDLSSContext, V as VerificationDecision } from '../types-YbiXYKx1.js';
2
+ import '../types-9tns4wyl.js';
3
+ import '../metadata-capture.js';
3
4
 
4
5
  /**
5
6
  * AstraSyncGateway — Primary API surface for agent verification.