@astrasyncai/verification-gateway 3.12.0 → 4.1.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.
- package/README.md +106 -29
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +482 -22
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +482 -22
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/http-pdlss.d.mts +3 -3
- package/dist/adapters/http-pdlss.d.ts +3 -3
- package/dist/adapters/http-pdlss.js.map +1 -1
- package/dist/adapters/http-pdlss.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +56 -36
- package/dist/adapters/mcp.d.ts +56 -36
- package/dist/adapters/mcp.js +309 -10
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +309 -10
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +518 -25
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +518 -25
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +72 -9
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +72 -9
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +83 -20
- package/dist/bin/astrasync-codex-hook.js +83 -20
- package/dist/bin/astrasync-guard.js +83 -20
- package/dist/bin/astrasync.js +150 -33
- package/dist/browser/background.js +83 -20
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +83 -20
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/claude-code/claude-code-adapter.d.mts +2 -2
- package/dist/claude-code/claude-code-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/codex/index.d.mts +3 -3
- package/dist/codex/index.d.ts +3 -3
- package/dist/codex/index.js +83 -20
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +83 -20
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +83 -20
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +83 -20
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +22 -7
- package/dist/edge-config.d.ts +22 -7
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +425 -0
- package/dist/edge-core/index.d.ts +425 -0
- package/dist/edge-core/index.js +1482 -0
- package/dist/edge-core/index.js.map +1 -0
- package/dist/edge-core/index.mjs +1437 -0
- package/dist/edge-core/index.mjs.map +1 -0
- package/dist/{express-B39o89gf.d.mts → express-BVd1_3FE.d.ts} +9 -7
- package/dist/{express-BuxKNO_q.d.ts → express-D_4hTn5Z.d.mts} +9 -7
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +83 -20
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +83 -20
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-CLHdqs2M.d.ts → index-B0YHu_SP.d.ts} +30 -27
- package/dist/{index-DME3w3lf.d.mts → index-BPEBlOsE.d.mts} +30 -27
- package/dist/{index-CqydB4ks.d.mts → index-DQb5-_1X.d.mts} +1 -1
- package/dist/{index-BG62SXso.d.ts → index-T1aBoUcc.d.ts} +1 -1
- package/dist/index.d.mts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +595 -272
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +592 -272
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/metadata-capture.d.mts +63 -4
- package/dist/metadata-capture.d.ts +63 -4
- package/dist/metadata-capture.js +67 -0
- package/dist/metadata-capture.js.map +1 -1
- package/dist/metadata-capture.mjs +64 -0
- package/dist/metadata-capture.mjs.map +1 -1
- package/dist/{nextjs-D74W7wt-.d.mts → nextjs-WyeVr2Kp.d.mts} +3 -3
- package/dist/{nextjs-Ddlw_J1J.d.ts → nextjs-w7RTbP1P.d.ts} +3 -3
- package/dist/platform-signatures.d.mts +5 -6
- package/dist/platform-signatures.d.ts +5 -6
- package/dist/platform-signatures.js.map +1 -1
- package/dist/platform-signatures.mjs.map +1 -1
- package/dist/registration/index.d.mts +10 -11
- package/dist/registration/index.d.ts +10 -11
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/{sdk-CT7gdkfR.d.ts → sdk-CbTNIkAa.d.mts} +4 -4
- package/dist/{sdk-Bn6bj7kt.d.mts → sdk-QeX0Z8Ho.d.ts} +4 -4
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-DHu7m9HI.d.ts → types-BLUx92FJ.d.ts} +1 -1
- package/dist/{types-Djw4GLtz.d.mts → types-DqfPU5Bl.d.mts} +1 -1
- package/dist/{types-BntuzEEn.d.mts → types-r850cOt0.d.mts} +121 -88
- package/dist/{types-SDu4Llbe.d.ts → types-sMxBT-nM.d.ts} +121 -88
- package/dist/ui/index.d.mts +11 -7
- package/dist/ui/index.d.ts +11 -7
- package/dist/ui/index.js +13 -9
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/index.mjs +10 -8
- package/dist/ui/index.mjs.map +1 -1
- package/dist/verify.d.mts +11 -8
- package/dist/verify.d.ts +11 -8
- package/dist/verify.js +76 -8
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +75 -8
- package/dist/verify.mjs.map +1 -1
- package/package.json +8 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared purpose/action resolver for the HTTP adapters (express + nextjs) —
|
|
3
|
-
* vocabulary-unification
|
|
3
|
+
* the vocabulary-unification layer.
|
|
4
4
|
*
|
|
5
5
|
* The PDLSS two-axis contract: `purpose` = bare category noun (`shopping`,
|
|
6
6
|
* `data`, custom nouns like `trading`); `action` = dotted verb
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* duplicated here and pinned strictly equal by a monorepo CI test
|
|
14
14
|
* (vocab-equality.test.ts). Change them in BOTH places or that test fails.
|
|
15
15
|
*/
|
|
16
|
-
/** Pinned method→action derivation table
|
|
16
|
+
/** Pinned method→action derivation table. */
|
|
17
17
|
declare const HTTP_METHOD_ACTION_TABLE: Readonly<Record<string, string>>;
|
|
18
18
|
/** Unknown methods are treated as mutating until proven otherwise. */
|
|
19
19
|
declare const DEFAULT_HTTP_ACTION = "data.write";
|
|
@@ -63,7 +63,7 @@ declare function normalizePurposeHeader(value: string): {
|
|
|
63
63
|
/**
|
|
64
64
|
* Resolve the {purpose, action} pair for one HTTP request.
|
|
65
65
|
*
|
|
66
|
-
* Precedence (both axes
|
|
66
|
+
* Precedence (both axes):
|
|
67
67
|
* action: route mapping → extractAction option → X-Astra-Action header →
|
|
68
68
|
* candidate from a dotted X-Astra-Purpose → pinned method table
|
|
69
69
|
* purpose: route mapping → extractPurpose option → X-Astra-Purpose →
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared purpose/action resolver for the HTTP adapters (express + nextjs) —
|
|
3
|
-
* vocabulary-unification
|
|
3
|
+
* the vocabulary-unification layer.
|
|
4
4
|
*
|
|
5
5
|
* The PDLSS two-axis contract: `purpose` = bare category noun (`shopping`,
|
|
6
6
|
* `data`, custom nouns like `trading`); `action` = dotted verb
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* duplicated here and pinned strictly equal by a monorepo CI test
|
|
14
14
|
* (vocab-equality.test.ts). Change them in BOTH places or that test fails.
|
|
15
15
|
*/
|
|
16
|
-
/** Pinned method→action derivation table
|
|
16
|
+
/** Pinned method→action derivation table. */
|
|
17
17
|
declare const HTTP_METHOD_ACTION_TABLE: Readonly<Record<string, string>>;
|
|
18
18
|
/** Unknown methods are treated as mutating until proven otherwise. */
|
|
19
19
|
declare const DEFAULT_HTTP_ACTION = "data.write";
|
|
@@ -63,7 +63,7 @@ declare function normalizePurposeHeader(value: string): {
|
|
|
63
63
|
/**
|
|
64
64
|
* Resolve the {purpose, action} pair for one HTTP request.
|
|
65
65
|
*
|
|
66
|
-
* Precedence (both axes
|
|
66
|
+
* Precedence (both axes):
|
|
67
67
|
* action: route mapping → extractAction option → X-Astra-Action header →
|
|
68
68
|
* candidate from a dotted X-Astra-Purpose → pinned method table
|
|
69
69
|
* purpose: route mapping → extractPurpose option → X-Astra-Purpose →
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/http-pdlss.ts"],"sourcesContent":["/**\n * Shared purpose/action resolver for the HTTP adapters (express + nextjs) —\n * vocabulary-unification
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/http-pdlss.ts"],"sourcesContent":["/**\n * Shared purpose/action resolver for the HTTP adapters (express + nextjs) —\n * the vocabulary-unification layer.\n *\n * The PDLSS two-axis contract: `purpose` = bare category noun (`shopping`,\n * `data`, custom nouns like `trading`); `action` = dotted verb\n * (`shopping.search`) or an enumerated transport token. Transport verbs\n * (GET/POST/...) NEVER travel as PDLSS actions — they map through the pinned\n * method table below.\n *\n * SELF-CONTAINED on purpose: this published package cannot depend on the\n * private @astrasyncai/pdlss-vocab workspace package, so the constants are\n * duplicated here and pinned strictly equal by a monorepo CI test\n * (vocab-equality.test.ts). Change them in BOTH places or that test fails.\n */\n\n/** Pinned method→action derivation table. */\nexport const HTTP_METHOD_ACTION_TABLE: Readonly<Record<string, string>> = {\n GET: 'data.read',\n HEAD: 'data.read',\n OPTIONS: 'data.read',\n POST: 'data.write',\n PUT: 'data.write',\n PATCH: 'data.write',\n DELETE: 'data.delete',\n};\n\n/** Unknown methods are treated as mutating until proven otherwise. */\nexport const DEFAULT_HTTP_ACTION = 'data.write';\n\n/** Generic category emitted when nothing supplies a domain purpose. */\nexport const DEFAULT_HTTP_PURPOSE = 'data';\n\nexport function actionForHttpMethod(method: string): string {\n return HTTP_METHOD_ACTION_TABLE[method.toUpperCase()] ?? DEFAULT_HTTP_ACTION;\n}\n\nexport type HttpPurposeSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'legacy_header'\n | 'query'\n | 'action_derived'\n | 'transport_default';\n\nexport type HttpActionSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'purpose_header_derived'\n | 'method_table';\n\nexport interface HttpPdlssInput {\n method: string;\n /** `X-Astra-Purpose` header value (agent's declaration). */\n astraPurpose?: string;\n /** `X-Astra-Action` header value (agent's declaration, symmetric with MCP). */\n astraAction?: string;\n /** Legacy `x-purpose` header — deprecated, removal scheduled for 4.0.0. */\n legacyPurpose?: string;\n /** Legacy `?purpose` query param (express only) — deprecated, removal 4.0.0. */\n queryPurpose?: string;\n /** Dashboard route config send-mapping (RouteAccessConfig.purpose/.action). */\n routePurpose?: string;\n routeAction?: string;\n /** Results of the merchant's extractPurpose/extractAction options. */\n customPurpose?: string;\n hasCustomPurposeExtractor?: boolean;\n customAction?: string;\n hasCustomActionExtractor?: boolean;\n}\n\nexport interface HttpPdlssResolution {\n purpose: string;\n action: string;\n purposeSource: HttpPurposeSource;\n actionSource: HttpActionSource;\n}\n\n/**\n * Normalize an `X-Astra-Purpose` header value.\n * - colon form `\"category:action\"` (legacy wire shape): take the prefix; the\n * remainder is free-text and exists in no vocabulary — discard it and let\n * the method table supply the action (matches pre-3.1.0 discard behavior).\n * - dotted form `\"shopping.purchase\"` (the shape older docs taught): prefix\n * becomes the purpose, the WHOLE token becomes an action candidate.\n * - bare token: purpose verbatim.\n */\nexport function normalizePurposeHeader(value: string): {\n purpose: string;\n actionCandidate?: string;\n} {\n const colon = value.indexOf(':');\n if (colon >= 0) {\n return { purpose: value.slice(0, colon) };\n }\n const dot = value.indexOf('.');\n if (dot > 0 && dot < value.length - 1) {\n return { purpose: value.slice(0, dot), actionCandidate: value };\n }\n return { purpose: value };\n}\n\n/**\n * Resolve the {purpose, action} pair for one HTTP request.\n *\n * Precedence (both axes):\n * action: route mapping → extractAction option → X-Astra-Action header →\n * candidate from a dotted X-Astra-Purpose → pinned method table\n * purpose: route mapping → extractPurpose option → X-Astra-Purpose →\n * legacy x-purpose / ?purpose → category prefix of the resolved\n * action → 'data'\n *\n * A configured custom extractor masks the header/legacy/query steps of its\n * axis (it replaces the default chain, as extractPurpose always has); when it\n * returns undefined the axis falls through to the table/prefix fallback.\n * The route mapping is merchant policy fetched from the dashboard — it\n * outranks agent-supplied headers the way MCP toolGates do.\n */\nexport function resolveHttpPdlss(input: HttpPdlssInput): HttpPdlssResolution {\n const fromHeader = input.astraPurpose ? normalizePurposeHeader(input.astraPurpose) : undefined;\n\n // ── Action axis ──\n let action: string;\n let actionSource: HttpActionSource;\n if (input.routeAction) {\n action = input.routeAction;\n actionSource = 'route_config';\n } else if (input.hasCustomActionExtractor && input.customAction) {\n action = input.customAction;\n actionSource = 'custom_extractor';\n } else if (!input.hasCustomActionExtractor && input.astraAction) {\n action = input.astraAction;\n actionSource = 'header';\n } else if (!input.hasCustomActionExtractor && fromHeader?.actionCandidate) {\n action = fromHeader.actionCandidate;\n actionSource = 'purpose_header_derived';\n } else {\n action = actionForHttpMethod(input.method);\n actionSource = 'method_table';\n }\n\n // ── Purpose axis ──\n let purpose: string | undefined;\n let purposeSource: HttpPurposeSource | undefined;\n if (input.routePurpose) {\n purpose = input.routePurpose;\n purposeSource = 'route_config';\n } else if (input.hasCustomPurposeExtractor) {\n if (input.customPurpose) {\n purpose = input.customPurpose;\n purposeSource = 'custom_extractor';\n }\n } else if (fromHeader) {\n purpose = fromHeader.purpose;\n purposeSource = 'header';\n } else if (input.legacyPurpose) {\n purpose = input.legacyPurpose;\n purposeSource = 'legacy_header';\n } else if (input.queryPurpose) {\n purpose = input.queryPurpose;\n purposeSource = 'query';\n }\n\n if (!purpose) {\n // Keep the pair coherent: an agent that sent only X-Astra-Action (or a\n // route that mapped only the action) gets that action's own category.\n const dot = action.indexOf('.');\n if (dot > 0) {\n purpose = action.slice(0, dot);\n purposeSource = 'action_derived';\n } else {\n purpose = DEFAULT_HTTP_PURPOSE;\n purposeSource = 'transport_default';\n }\n }\n\n return { purpose, action, purposeSource: purposeSource!, actionSource };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBO,IAAM,2BAA6D;AAAA,EACxE,KAAK;AAAA,EACL,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AACV;AAGO,IAAM,sBAAsB;AAG5B,IAAM,uBAAuB;AAE7B,SAAS,oBAAoB,QAAwB;AAC1D,SAAO,yBAAyB,OAAO,YAAY,CAAC,KAAK;AAC3D;AAsDO,SAAS,uBAAuB,OAGrC;AACA,QAAM,QAAQ,MAAM,QAAQ,GAAG;AAC/B,MAAI,SAAS,GAAG;AACd,WAAO,EAAE,SAAS,MAAM,MAAM,GAAG,KAAK,EAAE;AAAA,EAC1C;AACA,QAAM,MAAM,MAAM,QAAQ,GAAG;AAC7B,MAAI,MAAM,KAAK,MAAM,MAAM,SAAS,GAAG;AACrC,WAAO,EAAE,SAAS,MAAM,MAAM,GAAG,GAAG,GAAG,iBAAiB,MAAM;AAAA,EAChE;AACA,SAAO,EAAE,SAAS,MAAM;AAC1B;AAkBO,SAAS,iBAAiB,OAA4C;AAC3E,QAAM,aAAa,MAAM,eAAe,uBAAuB,MAAM,YAAY,IAAI;AAGrF,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,aAAa;AACrB,aAAS,MAAM;AACf,mBAAe;AAAA,EACjB,WAAW,MAAM,4BAA4B,MAAM,cAAc;AAC/D,aAAS,MAAM;AACf,mBAAe;AAAA,EACjB,WAAW,CAAC,MAAM,4BAA4B,MAAM,aAAa;AAC/D,aAAS,MAAM;AACf,mBAAe;AAAA,EACjB,WAAW,CAAC,MAAM,4BAA4B,YAAY,iBAAiB;AACzE,aAAS,WAAW;AACpB,mBAAe;AAAA,EACjB,OAAO;AACL,aAAS,oBAAoB,MAAM,MAAM;AACzC,mBAAe;AAAA,EACjB;AAGA,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,cAAc;AACtB,cAAU,MAAM;AAChB,oBAAgB;AAAA,EAClB,WAAW,MAAM,2BAA2B;AAC1C,QAAI,MAAM,eAAe;AACvB,gBAAU,MAAM;AAChB,sBAAgB;AAAA,IAClB;AAAA,EACF,WAAW,YAAY;AACrB,cAAU,WAAW;AACrB,oBAAgB;AAAA,EAClB,WAAW,MAAM,eAAe;AAC9B,cAAU,MAAM;AAChB,oBAAgB;AAAA,EAClB,WAAW,MAAM,cAAc;AAC7B,cAAU,MAAM;AAChB,oBAAgB;AAAA,EAClB;AAEA,MAAI,CAAC,SAAS;AAGZ,UAAM,MAAM,OAAO,QAAQ,GAAG;AAC9B,QAAI,MAAM,GAAG;AACX,gBAAU,OAAO,MAAM,GAAG,GAAG;AAC7B,sBAAgB;AAAA,IAClB,OAAO;AACL,gBAAU;AACV,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ,eAA+B,aAAa;AACxE;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/http-pdlss.ts"],"sourcesContent":["/**\n * Shared purpose/action resolver for the HTTP adapters (express + nextjs) —\n * vocabulary-unification
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/http-pdlss.ts"],"sourcesContent":["/**\n * Shared purpose/action resolver for the HTTP adapters (express + nextjs) —\n * the vocabulary-unification layer.\n *\n * The PDLSS two-axis contract: `purpose` = bare category noun (`shopping`,\n * `data`, custom nouns like `trading`); `action` = dotted verb\n * (`shopping.search`) or an enumerated transport token. Transport verbs\n * (GET/POST/...) NEVER travel as PDLSS actions — they map through the pinned\n * method table below.\n *\n * SELF-CONTAINED on purpose: this published package cannot depend on the\n * private @astrasyncai/pdlss-vocab workspace package, so the constants are\n * duplicated here and pinned strictly equal by a monorepo CI test\n * (vocab-equality.test.ts). Change them in BOTH places or that test fails.\n */\n\n/** Pinned method→action derivation table. */\nexport const HTTP_METHOD_ACTION_TABLE: Readonly<Record<string, string>> = {\n GET: 'data.read',\n HEAD: 'data.read',\n OPTIONS: 'data.read',\n POST: 'data.write',\n PUT: 'data.write',\n PATCH: 'data.write',\n DELETE: 'data.delete',\n};\n\n/** Unknown methods are treated as mutating until proven otherwise. */\nexport const DEFAULT_HTTP_ACTION = 'data.write';\n\n/** Generic category emitted when nothing supplies a domain purpose. */\nexport const DEFAULT_HTTP_PURPOSE = 'data';\n\nexport function actionForHttpMethod(method: string): string {\n return HTTP_METHOD_ACTION_TABLE[method.toUpperCase()] ?? DEFAULT_HTTP_ACTION;\n}\n\nexport type HttpPurposeSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'legacy_header'\n | 'query'\n | 'action_derived'\n | 'transport_default';\n\nexport type HttpActionSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'purpose_header_derived'\n | 'method_table';\n\nexport interface HttpPdlssInput {\n method: string;\n /** `X-Astra-Purpose` header value (agent's declaration). */\n astraPurpose?: string;\n /** `X-Astra-Action` header value (agent's declaration, symmetric with MCP). */\n astraAction?: string;\n /** Legacy `x-purpose` header — deprecated, removal scheduled for 4.0.0. */\n legacyPurpose?: string;\n /** Legacy `?purpose` query param (express only) — deprecated, removal 4.0.0. */\n queryPurpose?: string;\n /** Dashboard route config send-mapping (RouteAccessConfig.purpose/.action). */\n routePurpose?: string;\n routeAction?: string;\n /** Results of the merchant's extractPurpose/extractAction options. */\n customPurpose?: string;\n hasCustomPurposeExtractor?: boolean;\n customAction?: string;\n hasCustomActionExtractor?: boolean;\n}\n\nexport interface HttpPdlssResolution {\n purpose: string;\n action: string;\n purposeSource: HttpPurposeSource;\n actionSource: HttpActionSource;\n}\n\n/**\n * Normalize an `X-Astra-Purpose` header value.\n * - colon form `\"category:action\"` (legacy wire shape): take the prefix; the\n * remainder is free-text and exists in no vocabulary — discard it and let\n * the method table supply the action (matches pre-3.1.0 discard behavior).\n * - dotted form `\"shopping.purchase\"` (the shape older docs taught): prefix\n * becomes the purpose, the WHOLE token becomes an action candidate.\n * - bare token: purpose verbatim.\n */\nexport function normalizePurposeHeader(value: string): {\n purpose: string;\n actionCandidate?: string;\n} {\n const colon = value.indexOf(':');\n if (colon >= 0) {\n return { purpose: value.slice(0, colon) };\n }\n const dot = value.indexOf('.');\n if (dot > 0 && dot < value.length - 1) {\n return { purpose: value.slice(0, dot), actionCandidate: value };\n }\n return { purpose: value };\n}\n\n/**\n * Resolve the {purpose, action} pair for one HTTP request.\n *\n * Precedence (both axes):\n * action: route mapping → extractAction option → X-Astra-Action header →\n * candidate from a dotted X-Astra-Purpose → pinned method table\n * purpose: route mapping → extractPurpose option → X-Astra-Purpose →\n * legacy x-purpose / ?purpose → category prefix of the resolved\n * action → 'data'\n *\n * A configured custom extractor masks the header/legacy/query steps of its\n * axis (it replaces the default chain, as extractPurpose always has); when it\n * returns undefined the axis falls through to the table/prefix fallback.\n * The route mapping is merchant policy fetched from the dashboard — it\n * outranks agent-supplied headers the way MCP toolGates do.\n */\nexport function resolveHttpPdlss(input: HttpPdlssInput): HttpPdlssResolution {\n const fromHeader = input.astraPurpose ? normalizePurposeHeader(input.astraPurpose) : undefined;\n\n // ── Action axis ──\n let action: string;\n let actionSource: HttpActionSource;\n if (input.routeAction) {\n action = input.routeAction;\n actionSource = 'route_config';\n } else if (input.hasCustomActionExtractor && input.customAction) {\n action = input.customAction;\n actionSource = 'custom_extractor';\n } else if (!input.hasCustomActionExtractor && input.astraAction) {\n action = input.astraAction;\n actionSource = 'header';\n } else if (!input.hasCustomActionExtractor && fromHeader?.actionCandidate) {\n action = fromHeader.actionCandidate;\n actionSource = 'purpose_header_derived';\n } else {\n action = actionForHttpMethod(input.method);\n actionSource = 'method_table';\n }\n\n // ── Purpose axis ──\n let purpose: string | undefined;\n let purposeSource: HttpPurposeSource | undefined;\n if (input.routePurpose) {\n purpose = input.routePurpose;\n purposeSource = 'route_config';\n } else if (input.hasCustomPurposeExtractor) {\n if (input.customPurpose) {\n purpose = input.customPurpose;\n purposeSource = 'custom_extractor';\n }\n } else if (fromHeader) {\n purpose = fromHeader.purpose;\n purposeSource = 'header';\n } else if (input.legacyPurpose) {\n purpose = input.legacyPurpose;\n purposeSource = 'legacy_header';\n } else if (input.queryPurpose) {\n purpose = input.queryPurpose;\n purposeSource = 'query';\n }\n\n if (!purpose) {\n // Keep the pair coherent: an agent that sent only X-Astra-Action (or a\n // route that mapped only the action) gets that action's own category.\n const dot = action.indexOf('.');\n if (dot > 0) {\n purpose = action.slice(0, dot);\n purposeSource = 'action_derived';\n } else {\n purpose = DEFAULT_HTTP_PURPOSE;\n purposeSource = 'transport_default';\n }\n }\n\n return { purpose, action, purposeSource: purposeSource!, actionSource };\n}\n"],"mappings":";AAiBO,IAAM,2BAA6D;AAAA,EACxE,KAAK;AAAA,EACL,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AACV;AAGO,IAAM,sBAAsB;AAG5B,IAAM,uBAAuB;AAE7B,SAAS,oBAAoB,QAAwB;AAC1D,SAAO,yBAAyB,OAAO,YAAY,CAAC,KAAK;AAC3D;AAsDO,SAAS,uBAAuB,OAGrC;AACA,QAAM,QAAQ,MAAM,QAAQ,GAAG;AAC/B,MAAI,SAAS,GAAG;AACd,WAAO,EAAE,SAAS,MAAM,MAAM,GAAG,KAAK,EAAE;AAAA,EAC1C;AACA,QAAM,MAAM,MAAM,QAAQ,GAAG;AAC7B,MAAI,MAAM,KAAK,MAAM,MAAM,SAAS,GAAG;AACrC,WAAO,EAAE,SAAS,MAAM,MAAM,GAAG,GAAG,GAAG,iBAAiB,MAAM;AAAA,EAChE;AACA,SAAO,EAAE,SAAS,MAAM;AAC1B;AAkBO,SAAS,iBAAiB,OAA4C;AAC3E,QAAM,aAAa,MAAM,eAAe,uBAAuB,MAAM,YAAY,IAAI;AAGrF,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,aAAa;AACrB,aAAS,MAAM;AACf,mBAAe;AAAA,EACjB,WAAW,MAAM,4BAA4B,MAAM,cAAc;AAC/D,aAAS,MAAM;AACf,mBAAe;AAAA,EACjB,WAAW,CAAC,MAAM,4BAA4B,MAAM,aAAa;AAC/D,aAAS,MAAM;AACf,mBAAe;AAAA,EACjB,WAAW,CAAC,MAAM,4BAA4B,YAAY,iBAAiB;AACzE,aAAS,WAAW;AACpB,mBAAe;AAAA,EACjB,OAAO;AACL,aAAS,oBAAoB,MAAM,MAAM;AACzC,mBAAe;AAAA,EACjB;AAGA,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,cAAc;AACtB,cAAU,MAAM;AAChB,oBAAgB;AAAA,EAClB,WAAW,MAAM,2BAA2B;AAC1C,QAAI,MAAM,eAAe;AACvB,gBAAU,MAAM;AAChB,sBAAgB;AAAA,IAClB;AAAA,EACF,WAAW,YAAY;AACrB,cAAU,WAAW;AACrB,oBAAgB;AAAA,EAClB,WAAW,MAAM,eAAe;AAC9B,cAAU,MAAM;AAChB,oBAAgB;AAAA,EAClB,WAAW,MAAM,cAAc;AAC7B,cAAU,MAAM;AAChB,oBAAgB;AAAA,EAClB;AAEA,MAAI,CAAC,SAAS;AAGZ,UAAM,MAAM,OAAO,QAAQ,GAAG;AAC9B,QAAI,MAAM,GAAG;AACX,gBAAU,OAAO,MAAM,GAAG,GAAG;AAC7B,sBAAgB;AAAA,IAClB,OAAO;AACL,gBAAU;AACV,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ,eAA+B,aAAa;AACxE;","names":[]}
|
package/dist/adapters/mcp.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Request, Response, RequestHandler } from 'express';
|
|
2
|
-
import { a as AccessLevel, G as GatewayConfig,
|
|
2
|
+
import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from '../types-r850cOt0.mjs';
|
|
3
3
|
import '../metadata-capture.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -81,7 +81,7 @@ interface ParsedMcpRequest {
|
|
|
81
81
|
*/
|
|
82
82
|
agentIdFromBody?: string;
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
84
|
+
* Purpose extracted from the MCP body
|
|
85
85
|
* with the symmetric precedence chain. Sourced from `_meta.astrasync.purpose`
|
|
86
86
|
* (canonical SDK location) OR `params.arguments.purpose` (legacy /
|
|
87
87
|
* conventional callers). The discriminator is on `purposeSourceFromBody`.
|
|
@@ -92,7 +92,7 @@ interface ParsedMcpRequest {
|
|
|
92
92
|
/** Which body location resolved `purposeFromBody`. */
|
|
93
93
|
purposeSourceFromBody?: 'meta' | 'tool_argument';
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
95
|
+
* Action extracted from the MCP body with the same
|
|
96
96
|
* symmetric chain as purpose. Sourced from `_meta.astrasync.action`
|
|
97
97
|
* (canonical) OR `params.arguments.action` (legacy). Adapter combines
|
|
98
98
|
* with the `X-Astra-Action` header (header wins) before mapping; final
|
|
@@ -130,15 +130,24 @@ declare function parseMcpJsonRpc(body: unknown): ParsedMcpRequest | null;
|
|
|
130
130
|
* - `purpose` defaults to `undefined` (backend evaluator applies
|
|
131
131
|
* skip-when-undefined). Per-tool overrides via `toolGates` config let
|
|
132
132
|
* merchants declare the semantic purpose each tool fulfils.
|
|
133
|
-
* - `action`
|
|
134
|
-
*
|
|
133
|
+
* - `action` comes only from declarations (toolGate config, header, or
|
|
134
|
+
* body). For `tools/call` with none declared it is `undefined` —
|
|
135
|
+
* evaluation is purpose-only, because a raw tool name is a transport
|
|
136
|
+
* token, not a PDLSS action, and sending it as one guarantees an
|
|
137
|
+
* action-policy mismatch. For other JSON-RPC methods the method string
|
|
138
|
+
* is used.
|
|
135
139
|
*/
|
|
136
140
|
interface McpPdlssMapping {
|
|
137
141
|
purpose: string | undefined;
|
|
138
|
-
|
|
142
|
+
/**
|
|
143
|
+
* `undefined` when a `tools/call` request declared no action anywhere —
|
|
144
|
+
* the verify-access call then evaluates purpose-only. Tool names never
|
|
145
|
+
* travel as PDLSS actions.
|
|
146
|
+
*/
|
|
147
|
+
action: string | undefined;
|
|
139
148
|
resource: string;
|
|
140
149
|
purposeSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | undefined;
|
|
141
|
-
actionSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | 'transport_layer';
|
|
150
|
+
actionSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | 'transport_layer' | undefined;
|
|
142
151
|
}
|
|
143
152
|
/**
|
|
144
153
|
* v2.5.0 — PDLSS field derivation for MCP requests.
|
|
@@ -150,11 +159,13 @@ interface McpPdlssMapping {
|
|
|
150
159
|
* Resource precedence:
|
|
151
160
|
* - `toolGate.resource` if provided, else `requestPath`.
|
|
152
161
|
*
|
|
153
|
-
* Action precedence (3.1.0
|
|
154
|
-
* symmetry with purpose
|
|
162
|
+
* Action precedence (3.1.0 — toolGate override added for
|
|
163
|
+
* symmetry with purpose; 4.1.0 — the bare-tool-name fallback for
|
|
164
|
+
* `tools/call` was removed):
|
|
155
165
|
* - `toolGate.action` authoritative → header → body `_meta` → body
|
|
156
|
-
* `arguments` →
|
|
157
|
-
*
|
|
166
|
+
* `arguments` → then: `undefined` for `tools/call` (purpose-only
|
|
167
|
+
* evaluation — tool names are transport tokens, never PDLSS actions),
|
|
168
|
+
* or the JSON-RPC method string for other methods (transport_layer).
|
|
158
169
|
*
|
|
159
170
|
* @param requestPath The HTTP request path (e.g. '/mcp'). Required.
|
|
160
171
|
* @param toolGate Resolved per-tool config from `toolGates`, if present.
|
|
@@ -167,7 +178,7 @@ declare function mcpToPdlss(parsed: ParsedMcpRequest, requestPath: string, heade
|
|
|
167
178
|
/**
|
|
168
179
|
* Recommended minimum access level per method type. The MCP middleware uses
|
|
169
180
|
* this to split low-risk handshake / introspection traffic from high-risk
|
|
170
|
-
* tool execution
|
|
181
|
+
* tool execution.
|
|
171
182
|
*
|
|
172
183
|
* - `initialize` / `notifications/initialized` → `none` (handshake must work for unregistered probes)
|
|
173
184
|
* - `tools/list` / `prompts/list` / `resources/list` → `none` (introspection is public-surface)
|
|
@@ -218,12 +229,16 @@ declare function mcpRiskTier(parsed: ParsedMcpRequest): AccessLevel;
|
|
|
218
229
|
* createMcpMiddleware({
|
|
219
230
|
* apiBaseUrl: 'https://astrasync.ai/api',
|
|
220
231
|
* apiKey: process.env.ASTRASYNC_API_KEY,
|
|
221
|
-
* //
|
|
222
|
-
* //
|
|
232
|
+
* // Per-tool gates — tools not listed get the default tier from
|
|
233
|
+
* // `mcpRiskTier` (`tools/call` → 'standard'). Use the object form:
|
|
234
|
+
* // gated tools need a PDLSS purpose (and ideally an action).
|
|
223
235
|
* toolGates: {
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
236
|
+
* browse_catalog: { minAccessLevel: 'read-only', purpose: 'shopping' },
|
|
237
|
+
* start_checkout: {
|
|
238
|
+
* minAccessLevel: 'standard',
|
|
239
|
+
* purpose: 'shopping',
|
|
240
|
+
* action: 'shopping.purchase',
|
|
241
|
+
* },
|
|
227
242
|
* },
|
|
228
243
|
* }),
|
|
229
244
|
* yourMcpServerHandler,
|
|
@@ -246,10 +261,11 @@ declare global {
|
|
|
246
261
|
* `X-Astra-Purpose` header is ignored. This lets the merchant declare what
|
|
247
262
|
* semantic purpose each tool fulfils rather than trusting agent self-declaration.
|
|
248
263
|
*
|
|
249
|
-
* When `action` is set (
|
|
264
|
+
* When `action` is set (symmetric with `purpose`), it is
|
|
250
265
|
* authoritative over `X-Astra-Action` / body declarations, letting the
|
|
251
266
|
* merchant pin a dotted-verb action (e.g. `shopping.search`) for a tool
|
|
252
|
-
* whose callers would otherwise
|
|
267
|
+
* whose callers would otherwise leave the action undeclared (purpose-only
|
|
268
|
+
* evaluation — raw tool names never travel as PDLSS actions).
|
|
253
269
|
*
|
|
254
270
|
* When `resource` is set, it overrides the default (`req.path`) for that
|
|
255
271
|
* tool's verify-access call — e.g. mapping `list_products` to `/api/catalog`.
|
|
@@ -265,26 +281,31 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
265
281
|
* Per-tool gating for `tools/call` invocations. Tools not listed inherit
|
|
266
282
|
* the default tier from `mcpRiskTier` (`tools/call` → `'standard'`).
|
|
267
283
|
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* bare string shorthand — which carries no purpose — only works if the caller
|
|
272
|
-
* supplies the purpose another way (an `X-Astra-Purpose` header, or
|
|
273
|
-
* `params._meta.astrasync.purpose`); otherwise the call fails fast with a
|
|
274
|
-
* `PDLSS_PURPOSE_REQUIRED` 400. Prefer the **object form with `purpose`**:
|
|
284
|
+
* Use the **object form** — it lets the merchant declare the PDLSS
|
|
285
|
+
* `purpose` (required for any gated tool: the backend rejects gated calls
|
|
286
|
+
* with no resolvable purpose) and pin a dotted-verb `action`:
|
|
275
287
|
* ```typescript
|
|
276
288
|
* toolGates: {
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* list_products: { purpose: 'shopping', // object form (recommended)
|
|
289
|
+
* list_products: { minAccessLevel: 'read-only',
|
|
290
|
+
* purpose: 'shopping',
|
|
280
291
|
* action: 'shopping.search',
|
|
281
292
|
* resource: '/api/catalog' },
|
|
282
|
-
* start_checkout: {
|
|
293
|
+
* start_checkout: { minAccessLevel: 'standard',
|
|
294
|
+
* purpose: 'shopping',
|
|
283
295
|
* action: 'shopping.purchase',
|
|
284
296
|
* resource: '/api/checkout/*' },
|
|
285
297
|
* }
|
|
286
298
|
* ```
|
|
287
299
|
*
|
|
300
|
+
* The bare access-level string shorthand (`browse_catalog: 'read-only'`)
|
|
301
|
+
* is a legacy form and a known footgun: it carries no purpose, so the call
|
|
302
|
+
* only succeeds when the AGENT declares one (an `X-Astra-Purpose` header
|
|
303
|
+
* or `params._meta.astrasync.purpose`) — otherwise it fails fast with a
|
|
304
|
+
* `PDLSS_PURPOSE_REQUIRED` 400. It also declares no action, so evaluation
|
|
305
|
+
* is purpose-only (the SDK never sends the raw tool name as the PDLSS
|
|
306
|
+
* action). `createMcpMiddleware` logs a warning at construction for every
|
|
307
|
+
* bare-string gate.
|
|
308
|
+
*
|
|
288
309
|
* When `tools/call` arrives for a tool not declared in `toolGates`, the SDK
|
|
289
310
|
* falls back to a risk-tier default based on the method classification
|
|
290
311
|
* (`mcpRiskTier`). For `tools/call` the fallback is `'standard'`. Best
|
|
@@ -324,7 +345,7 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
324
345
|
* If `true`, trust an inbound `X-Astra-Verified-Hop` header to skip
|
|
325
346
|
* verify-access when it carries a recent marker for the resolved agent.
|
|
326
347
|
*
|
|
327
|
-
* **DEFAULT FLIPPED TO `false` in SDK 2.4.13
|
|
348
|
+
* **DEFAULT FLIPPED TO `false` in SDK 2.4.13.** The marker
|
|
328
349
|
* is plaintext semicolon-delimited with no HMAC, so any client that sets
|
|
329
350
|
* the header (with the right format + fresh timestamp + matching ASTRA-id)
|
|
330
351
|
* skipped verify-access entirely. The per-process verify-access result
|
|
@@ -335,8 +356,8 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
335
356
|
* the header AND you trust the network path between hops (mTLS, internal
|
|
336
357
|
* VPC, etc.). For most installs, leave at the safe default.
|
|
337
358
|
*
|
|
338
|
-
*
|
|
339
|
-
* signing to the marker.
|
|
359
|
+
* A future SDK release will either remove this option entirely OR add
|
|
360
|
+
* HMAC signing to the marker.
|
|
340
361
|
*/
|
|
341
362
|
trustVerifiedHop?: boolean;
|
|
342
363
|
/** Window for accepting an upstream verified-hop marker. Default 60_000ms. */
|
|
@@ -352,9 +373,8 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
352
373
|
* Posture when the MCP middleware itself throws an internal error.
|
|
353
374
|
* Default `'open'` for backward compatibility in SDK 2.4.13. Shadow logs
|
|
354
375
|
* record what WOULD be denied with `failOnError: 'closed'` so merchants
|
|
355
|
-
* can grep correlationId for impact analysis during the
|
|
356
|
-
*
|
|
357
|
-
* Audit F-A1-06.
|
|
376
|
+
* can grep correlationId for impact analysis during the observation
|
|
377
|
+
* window. Default flips to `'closed'` in a follow-up release.
|
|
358
378
|
*/
|
|
359
379
|
failOnError?: 'open' | 'closed';
|
|
360
380
|
}
|
package/dist/adapters/mcp.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Request, Response, RequestHandler } from 'express';
|
|
2
|
-
import { a as AccessLevel, G as GatewayConfig,
|
|
2
|
+
import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from '../types-sMxBT-nM.js';
|
|
3
3
|
import '../metadata-capture.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -81,7 +81,7 @@ interface ParsedMcpRequest {
|
|
|
81
81
|
*/
|
|
82
82
|
agentIdFromBody?: string;
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
84
|
+
* Purpose extracted from the MCP body
|
|
85
85
|
* with the symmetric precedence chain. Sourced from `_meta.astrasync.purpose`
|
|
86
86
|
* (canonical SDK location) OR `params.arguments.purpose` (legacy /
|
|
87
87
|
* conventional callers). The discriminator is on `purposeSourceFromBody`.
|
|
@@ -92,7 +92,7 @@ interface ParsedMcpRequest {
|
|
|
92
92
|
/** Which body location resolved `purposeFromBody`. */
|
|
93
93
|
purposeSourceFromBody?: 'meta' | 'tool_argument';
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
95
|
+
* Action extracted from the MCP body with the same
|
|
96
96
|
* symmetric chain as purpose. Sourced from `_meta.astrasync.action`
|
|
97
97
|
* (canonical) OR `params.arguments.action` (legacy). Adapter combines
|
|
98
98
|
* with the `X-Astra-Action` header (header wins) before mapping; final
|
|
@@ -130,15 +130,24 @@ declare function parseMcpJsonRpc(body: unknown): ParsedMcpRequest | null;
|
|
|
130
130
|
* - `purpose` defaults to `undefined` (backend evaluator applies
|
|
131
131
|
* skip-when-undefined). Per-tool overrides via `toolGates` config let
|
|
132
132
|
* merchants declare the semantic purpose each tool fulfils.
|
|
133
|
-
* - `action`
|
|
134
|
-
*
|
|
133
|
+
* - `action` comes only from declarations (toolGate config, header, or
|
|
134
|
+
* body). For `tools/call` with none declared it is `undefined` —
|
|
135
|
+
* evaluation is purpose-only, because a raw tool name is a transport
|
|
136
|
+
* token, not a PDLSS action, and sending it as one guarantees an
|
|
137
|
+
* action-policy mismatch. For other JSON-RPC methods the method string
|
|
138
|
+
* is used.
|
|
135
139
|
*/
|
|
136
140
|
interface McpPdlssMapping {
|
|
137
141
|
purpose: string | undefined;
|
|
138
|
-
|
|
142
|
+
/**
|
|
143
|
+
* `undefined` when a `tools/call` request declared no action anywhere —
|
|
144
|
+
* the verify-access call then evaluates purpose-only. Tool names never
|
|
145
|
+
* travel as PDLSS actions.
|
|
146
|
+
*/
|
|
147
|
+
action: string | undefined;
|
|
139
148
|
resource: string;
|
|
140
149
|
purposeSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | undefined;
|
|
141
|
-
actionSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | 'transport_layer';
|
|
150
|
+
actionSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | 'transport_layer' | undefined;
|
|
142
151
|
}
|
|
143
152
|
/**
|
|
144
153
|
* v2.5.0 — PDLSS field derivation for MCP requests.
|
|
@@ -150,11 +159,13 @@ interface McpPdlssMapping {
|
|
|
150
159
|
* Resource precedence:
|
|
151
160
|
* - `toolGate.resource` if provided, else `requestPath`.
|
|
152
161
|
*
|
|
153
|
-
* Action precedence (3.1.0
|
|
154
|
-
* symmetry with purpose
|
|
162
|
+
* Action precedence (3.1.0 — toolGate override added for
|
|
163
|
+
* symmetry with purpose; 4.1.0 — the bare-tool-name fallback for
|
|
164
|
+
* `tools/call` was removed):
|
|
155
165
|
* - `toolGate.action` authoritative → header → body `_meta` → body
|
|
156
|
-
* `arguments` →
|
|
157
|
-
*
|
|
166
|
+
* `arguments` → then: `undefined` for `tools/call` (purpose-only
|
|
167
|
+
* evaluation — tool names are transport tokens, never PDLSS actions),
|
|
168
|
+
* or the JSON-RPC method string for other methods (transport_layer).
|
|
158
169
|
*
|
|
159
170
|
* @param requestPath The HTTP request path (e.g. '/mcp'). Required.
|
|
160
171
|
* @param toolGate Resolved per-tool config from `toolGates`, if present.
|
|
@@ -167,7 +178,7 @@ declare function mcpToPdlss(parsed: ParsedMcpRequest, requestPath: string, heade
|
|
|
167
178
|
/**
|
|
168
179
|
* Recommended minimum access level per method type. The MCP middleware uses
|
|
169
180
|
* this to split low-risk handshake / introspection traffic from high-risk
|
|
170
|
-
* tool execution
|
|
181
|
+
* tool execution.
|
|
171
182
|
*
|
|
172
183
|
* - `initialize` / `notifications/initialized` → `none` (handshake must work for unregistered probes)
|
|
173
184
|
* - `tools/list` / `prompts/list` / `resources/list` → `none` (introspection is public-surface)
|
|
@@ -218,12 +229,16 @@ declare function mcpRiskTier(parsed: ParsedMcpRequest): AccessLevel;
|
|
|
218
229
|
* createMcpMiddleware({
|
|
219
230
|
* apiBaseUrl: 'https://astrasync.ai/api',
|
|
220
231
|
* apiKey: process.env.ASTRASYNC_API_KEY,
|
|
221
|
-
* //
|
|
222
|
-
* //
|
|
232
|
+
* // Per-tool gates — tools not listed get the default tier from
|
|
233
|
+
* // `mcpRiskTier` (`tools/call` → 'standard'). Use the object form:
|
|
234
|
+
* // gated tools need a PDLSS purpose (and ideally an action).
|
|
223
235
|
* toolGates: {
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
236
|
+
* browse_catalog: { minAccessLevel: 'read-only', purpose: 'shopping' },
|
|
237
|
+
* start_checkout: {
|
|
238
|
+
* minAccessLevel: 'standard',
|
|
239
|
+
* purpose: 'shopping',
|
|
240
|
+
* action: 'shopping.purchase',
|
|
241
|
+
* },
|
|
227
242
|
* },
|
|
228
243
|
* }),
|
|
229
244
|
* yourMcpServerHandler,
|
|
@@ -246,10 +261,11 @@ declare global {
|
|
|
246
261
|
* `X-Astra-Purpose` header is ignored. This lets the merchant declare what
|
|
247
262
|
* semantic purpose each tool fulfils rather than trusting agent self-declaration.
|
|
248
263
|
*
|
|
249
|
-
* When `action` is set (
|
|
264
|
+
* When `action` is set (symmetric with `purpose`), it is
|
|
250
265
|
* authoritative over `X-Astra-Action` / body declarations, letting the
|
|
251
266
|
* merchant pin a dotted-verb action (e.g. `shopping.search`) for a tool
|
|
252
|
-
* whose callers would otherwise
|
|
267
|
+
* whose callers would otherwise leave the action undeclared (purpose-only
|
|
268
|
+
* evaluation — raw tool names never travel as PDLSS actions).
|
|
253
269
|
*
|
|
254
270
|
* When `resource` is set, it overrides the default (`req.path`) for that
|
|
255
271
|
* tool's verify-access call — e.g. mapping `list_products` to `/api/catalog`.
|
|
@@ -265,26 +281,31 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
265
281
|
* Per-tool gating for `tools/call` invocations. Tools not listed inherit
|
|
266
282
|
* the default tier from `mcpRiskTier` (`tools/call` → `'standard'`).
|
|
267
283
|
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* bare string shorthand — which carries no purpose — only works if the caller
|
|
272
|
-
* supplies the purpose another way (an `X-Astra-Purpose` header, or
|
|
273
|
-
* `params._meta.astrasync.purpose`); otherwise the call fails fast with a
|
|
274
|
-
* `PDLSS_PURPOSE_REQUIRED` 400. Prefer the **object form with `purpose`**:
|
|
284
|
+
* Use the **object form** — it lets the merchant declare the PDLSS
|
|
285
|
+
* `purpose` (required for any gated tool: the backend rejects gated calls
|
|
286
|
+
* with no resolvable purpose) and pin a dotted-verb `action`:
|
|
275
287
|
* ```typescript
|
|
276
288
|
* toolGates: {
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* list_products: { purpose: 'shopping', // object form (recommended)
|
|
289
|
+
* list_products: { minAccessLevel: 'read-only',
|
|
290
|
+
* purpose: 'shopping',
|
|
280
291
|
* action: 'shopping.search',
|
|
281
292
|
* resource: '/api/catalog' },
|
|
282
|
-
* start_checkout: {
|
|
293
|
+
* start_checkout: { minAccessLevel: 'standard',
|
|
294
|
+
* purpose: 'shopping',
|
|
283
295
|
* action: 'shopping.purchase',
|
|
284
296
|
* resource: '/api/checkout/*' },
|
|
285
297
|
* }
|
|
286
298
|
* ```
|
|
287
299
|
*
|
|
300
|
+
* The bare access-level string shorthand (`browse_catalog: 'read-only'`)
|
|
301
|
+
* is a legacy form and a known footgun: it carries no purpose, so the call
|
|
302
|
+
* only succeeds when the AGENT declares one (an `X-Astra-Purpose` header
|
|
303
|
+
* or `params._meta.astrasync.purpose`) — otherwise it fails fast with a
|
|
304
|
+
* `PDLSS_PURPOSE_REQUIRED` 400. It also declares no action, so evaluation
|
|
305
|
+
* is purpose-only (the SDK never sends the raw tool name as the PDLSS
|
|
306
|
+
* action). `createMcpMiddleware` logs a warning at construction for every
|
|
307
|
+
* bare-string gate.
|
|
308
|
+
*
|
|
288
309
|
* When `tools/call` arrives for a tool not declared in `toolGates`, the SDK
|
|
289
310
|
* falls back to a risk-tier default based on the method classification
|
|
290
311
|
* (`mcpRiskTier`). For `tools/call` the fallback is `'standard'`. Best
|
|
@@ -324,7 +345,7 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
324
345
|
* If `true`, trust an inbound `X-Astra-Verified-Hop` header to skip
|
|
325
346
|
* verify-access when it carries a recent marker for the resolved agent.
|
|
326
347
|
*
|
|
327
|
-
* **DEFAULT FLIPPED TO `false` in SDK 2.4.13
|
|
348
|
+
* **DEFAULT FLIPPED TO `false` in SDK 2.4.13.** The marker
|
|
328
349
|
* is plaintext semicolon-delimited with no HMAC, so any client that sets
|
|
329
350
|
* the header (with the right format + fresh timestamp + matching ASTRA-id)
|
|
330
351
|
* skipped verify-access entirely. The per-process verify-access result
|
|
@@ -335,8 +356,8 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
335
356
|
* the header AND you trust the network path between hops (mTLS, internal
|
|
336
357
|
* VPC, etc.). For most installs, leave at the safe default.
|
|
337
358
|
*
|
|
338
|
-
*
|
|
339
|
-
* signing to the marker.
|
|
359
|
+
* A future SDK release will either remove this option entirely OR add
|
|
360
|
+
* HMAC signing to the marker.
|
|
340
361
|
*/
|
|
341
362
|
trustVerifiedHop?: boolean;
|
|
342
363
|
/** Window for accepting an upstream verified-hop marker. Default 60_000ms. */
|
|
@@ -352,9 +373,8 @@ interface McpMiddlewareOptions extends GatewayConfig {
|
|
|
352
373
|
* Posture when the MCP middleware itself throws an internal error.
|
|
353
374
|
* Default `'open'` for backward compatibility in SDK 2.4.13. Shadow logs
|
|
354
375
|
* record what WOULD be denied with `failOnError: 'closed'` so merchants
|
|
355
|
-
* can grep correlationId for impact analysis during the
|
|
356
|
-
*
|
|
357
|
-
* Audit F-A1-06.
|
|
376
|
+
* can grep correlationId for impact analysis during the observation
|
|
377
|
+
* window. Default flips to `'closed'` in a follow-up release.
|
|
358
378
|
*/
|
|
359
379
|
failOnError?: 'open' | 'closed';
|
|
360
380
|
}
|