@nextera.one/axis-server-sdk 2.2.8 → 2.3.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.
@@ -569,6 +569,16 @@ function AxisPublic() {
569
569
  return target;
570
570
  };
571
571
  }
572
+ function AxisAuthorized() {
573
+ return (target, propertyKey, descriptor) => {
574
+ if (descriptor) {
575
+ Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target, propertyKey);
576
+ return descriptor;
577
+ }
578
+ Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target);
579
+ return target;
580
+ };
581
+ }
572
582
  function AxisAnonymous() {
573
583
  return (target, propertyKey, descriptor) => {
574
584
  if (descriptor) {
@@ -585,7 +595,7 @@ function AxisRateLimit(config) {
585
595
  return descriptor;
586
596
  };
587
597
  }
588
- var AXIS_META_KEY, SENSITIVITY_METADATA_KEY, CONTRACT_METADATA_KEY, REQUIRED_PROOF_METADATA_KEY, AXIS_PUBLIC_KEY, AXIS_ANONYMOUS_KEY, AXIS_RATE_LIMIT_KEY;
598
+ var AXIS_META_KEY, SENSITIVITY_METADATA_KEY, CONTRACT_METADATA_KEY, REQUIRED_PROOF_METADATA_KEY, AXIS_PUBLIC_KEY, AXIS_ANONYMOUS_KEY, AXIS_AUTHORIZED_KEY, AXIS_RATE_LIMIT_KEY;
589
599
  var init_intent_policy_decorator = __esm({
590
600
  "src/decorators/intent-policy.decorator.ts"() {
591
601
  AXIS_META_KEY = "axis:axis";
@@ -594,6 +604,7 @@ var init_intent_policy_decorator = __esm({
594
604
  REQUIRED_PROOF_METADATA_KEY = "axis:required_proof";
595
605
  AXIS_PUBLIC_KEY = "axis:public";
596
606
  AXIS_ANONYMOUS_KEY = "axis:anonymous";
607
+ AXIS_AUTHORIZED_KEY = "axis:authorized";
597
608
  AXIS_RATE_LIMIT_KEY = "axis:rateLimit";
598
609
  }
599
610
  });
@@ -1619,199 +1630,464 @@ var init_axis_chain_executor = __esm({
1619
1630
  }
1620
1631
  });
1621
1632
 
1622
- // src/cce/cce.types.ts
1623
- var CCE_PROTOCOL_VERSION, CCE_DERIVATION, CCE_AES_KEY_BYTES, CCE_IV_BYTES, CCE_NONCE_BYTES, CCE_ERROR, CceError;
1624
- var init_cce_types = __esm({
1625
- "src/cce/cce.types.ts"() {
1626
- CCE_PROTOCOL_VERSION = "cce-v1";
1627
- CCE_DERIVATION = {
1628
- /** Request execution context */
1629
- REQUEST: "axis:cce:req:v1",
1630
- /** Response execution context */
1631
- RESPONSE: "axis:cce:resp:v1",
1632
- /** Witness binding context */
1633
- WITNESS: "axis:cce:witness:v1"
1634
- };
1635
- CCE_AES_KEY_BYTES = 32;
1636
- CCE_IV_BYTES = 12;
1637
- CCE_NONCE_BYTES = 32;
1638
- CCE_ERROR = {
1639
- // Envelope errors
1640
- INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
1641
- UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
1642
- MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
1643
- MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
1644
- // Signature errors
1645
- CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
1646
- CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
1647
- // Capsule errors
1648
- CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
1649
- CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
1650
- CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
1651
- CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
1652
- CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
1653
- CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
1654
- // Binding errors
1655
- AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
1656
- INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
1657
- TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
1658
- TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
1659
- // Replay / nonce errors
1660
- REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
1661
- NONCE_REUSED: "CCE_NONCE_REUSED",
1662
- // Decryption errors
1663
- DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
1664
- KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
1665
- AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
1666
- PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
1667
- // Schema / validation errors
1668
- PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
1669
- INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
1670
- // Policy errors
1671
- POLICY_DENIED: "CCE_POLICY_DENIED",
1672
- CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
1673
- // Handler errors
1674
- HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
1675
- HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
1676
- HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
1677
- // Response errors
1678
- RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
1679
- };
1680
- CceError = class extends Error {
1681
- constructor(code, message, metadata) {
1682
- super(`[${code}] ${message}`);
1683
- this.code = code;
1684
- this.metadata = metadata;
1685
- this.name = "CceError";
1686
- }
1687
- /** Whether this error is safe to expose to the client */
1688
- get clientSafe() {
1689
- const internal = [
1690
- CCE_ERROR.DECRYPTION_FAILED,
1691
- CCE_ERROR.KEY_UNWRAP_FAILED,
1692
- CCE_ERROR.AEAD_TAG_MISMATCH,
1693
- CCE_ERROR.HANDLER_EXECUTION_FAILED,
1694
- CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
1695
- ];
1696
- return !internal.includes(this.code);
1697
- }
1698
- /** Get client-safe representation */
1699
- toClientError() {
1700
- if (this.clientSafe) {
1701
- return { code: this.code, message: this.message };
1702
- }
1703
- return {
1704
- code: CCE_ERROR.DECRYPTION_FAILED,
1705
- message: "Request processing failed"
1706
- };
1707
- }
1708
- };
1633
+ // src/security/scopes.ts
1634
+ function hasScope(scopes, required) {
1635
+ if (!Array.isArray(scopes) || scopes.length === 0) {
1636
+ return false;
1709
1637
  }
1710
- });
1711
-
1712
- // src/cce/cce-derivation.service.ts
1713
- import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
1714
- import { hkdf } from "@noble/hashes/hkdf.js";
1715
- import { sha256 } from "@noble/hashes/sha2.js";
1716
- function buildSalt(capsuleId, capsuleNonce, requestNonce) {
1717
- const encoder = new TextEncoder();
1718
- const data = encoder.encode(
1719
- capsuleId + "|" + capsuleNonce + "|" + requestNonce
1720
- );
1721
- return sha256(data);
1722
- }
1723
- function buildInfo(contextPrefix, capsule, extraNonce) {
1724
- const encoder = new TextEncoder();
1725
- const parts = [
1726
- contextPrefix,
1727
- capsule.sub,
1728
- capsule.kid,
1729
- capsule.intent,
1730
- capsule.aud,
1731
- String(capsule.tps_from),
1732
- String(capsule.tps_to),
1733
- capsule.policy_hash ?? "",
1734
- capsule.ver
1735
- ];
1736
- if (extraNonce) {
1737
- parts.push(extraNonce);
1638
+ if (scopes.includes(required)) {
1639
+ return true;
1738
1640
  }
1739
- return encoder.encode(parts.join("|"));
1641
+ const [resource, id] = required.split(":");
1642
+ if (resource && id) {
1643
+ const wildcard = `${resource}:*`;
1644
+ if (scopes.includes(wildcard)) {
1645
+ return true;
1646
+ }
1647
+ }
1648
+ return false;
1740
1649
  }
1741
- function deriveRequestExecutionKey(input) {
1742
- const ikm = hexToBytes(input.axisLocalSecret);
1743
- const salt = buildSalt(
1744
- input.capsule.capsule_id,
1745
- input.capsule.capsule_nonce,
1746
- input.requestNonce
1747
- );
1748
- const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
1749
- return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
1650
+ function parseScope(scope) {
1651
+ const parts = scope.split(":");
1652
+ if (parts.length !== 2) return null;
1653
+ return { resource: parts[0], id: parts[1] };
1750
1654
  }
1751
- function buildExecutionContext(input, requestId) {
1752
- const executionKey = deriveRequestExecutionKey(input);
1753
- const keyHash = bytesToHex(sha256(executionKey));
1754
- executionKey.fill(0);
1755
- return {
1756
- execution_key_hash: keyHash,
1757
- request_id: requestId,
1758
- capsule_id: input.capsule.capsule_id,
1759
- sub: input.capsule.sub,
1760
- kid: input.capsule.kid,
1761
- intent: input.capsule.intent,
1762
- aud: input.capsule.aud,
1763
- tps_from: input.capsule.tps_from,
1764
- tps_to: input.capsule.tps_to,
1765
- policy_hash: input.capsule.policy_hash,
1766
- derived_at: Math.floor(Date.now() / 1e3),
1767
- valid: true
1768
- };
1655
+ function canAccessResource(scopes, resourceType, resourceId) {
1656
+ const required = `${resourceType}:${resourceId}`;
1657
+ return hasScope(scopes, required);
1769
1658
  }
1770
- var init_cce_derivation_service = __esm({
1771
- "src/cce/cce-derivation.service.ts"() {
1772
- init_cce_types();
1659
+ var init_scopes = __esm({
1660
+ "src/security/scopes.ts"() {
1773
1661
  }
1774
1662
  });
1775
1663
 
1776
- // src/cce/cce-crypto.ts
1777
- import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
1778
- import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1779
- import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
1780
- function aesGcmEncrypt(key, plaintext, aad) {
1781
- if (key.length !== CCE_AES_KEY_BYTES) {
1782
- throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
1783
- }
1784
- const iv = randomBytes(CCE_IV_BYTES);
1785
- const cipher = createCipheriv("aes-256-gcm", key, iv);
1786
- if (aad) {
1787
- cipher.setAAD(aad);
1664
+ // src/security/inline-capsule.ts
1665
+ function normalizeInlineCapsule(input) {
1666
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
1667
+ return null;
1788
1668
  }
1789
- const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1790
- const tag = cipher.getAuthTag();
1669
+ const raw = input;
1670
+ const scopes = normalizeStringList(raw.scopes ?? raw.scope);
1791
1671
  return {
1792
- iv: new Uint8Array(iv),
1793
- ciphertext: new Uint8Array(encrypted),
1794
- tag: new Uint8Array(tag)
1672
+ id: normalizeScalar(raw.id),
1673
+ actorId: normalizeScalar(raw.actorId),
1674
+ intents: normalizeStringList(raw.intents),
1675
+ issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
1676
+ expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
1677
+ realm: normalizeScalar(raw.realm),
1678
+ node: normalizeScalar(raw.node),
1679
+ scopes,
1680
+ raw
1795
1681
  };
1796
1682
  }
1797
- function generateAesKey() {
1798
- return new Uint8Array(randomBytes(CCE_AES_KEY_BYTES));
1683
+ function inlineCapsuleAllowsIntent(capsule, intent) {
1684
+ if (!capsule.intents || capsule.intents.length === 0) {
1685
+ return false;
1686
+ }
1687
+ for (const pattern of capsule.intents) {
1688
+ if (pattern === "*" || pattern === intent) {
1689
+ return true;
1690
+ }
1691
+ if (pattern.endsWith(".*")) {
1692
+ const prefix = pattern.slice(0, -1);
1693
+ if (intent.startsWith(prefix)) {
1694
+ return true;
1695
+ }
1696
+ }
1697
+ }
1698
+ return false;
1799
1699
  }
1800
- function base64UrlEncode(bytes2) {
1801
- return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1700
+ function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
1701
+ if (capsule.expiresAt === void 0) {
1702
+ return false;
1703
+ }
1704
+ return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
1802
1705
  }
1803
- function hashPayload(payload) {
1804
- return bytesToHex2(sha2562(payload));
1706
+ function resolvePolicyScopes(scopes, context) {
1707
+ return scopes.map(
1708
+ (scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
1709
+ const resolved = resolveTemplateExpression(expression.trim(), context);
1710
+ if (resolved === void 0 || resolved === null || resolved === "") {
1711
+ throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
1712
+ }
1713
+ return String(resolved);
1714
+ })
1715
+ );
1805
1716
  }
1806
- var init_cce_crypto = __esm({
1807
- "src/cce/cce-crypto.ts"() {
1808
- init_cce_types();
1717
+ function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
1718
+ if (!capsule.scopes || capsule.scopes.length === 0) {
1719
+ return false;
1809
1720
  }
1810
- });
1811
-
1812
- // src/cce/cce-response.service.ts
1813
- import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
1814
- import { randomBytes as randomBytes2 } from "crypto";
1721
+ if (mode === "any") {
1722
+ return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
1723
+ }
1724
+ return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
1725
+ }
1726
+ function resolveTemplateExpression(expression, context) {
1727
+ if (expression === "intent") {
1728
+ return context.intent;
1729
+ }
1730
+ if (expression === "actorId") {
1731
+ return context.actorId;
1732
+ }
1733
+ if (expression === "chainId") {
1734
+ return context.chainId;
1735
+ }
1736
+ if (expression === "stepId") {
1737
+ return context.stepId;
1738
+ }
1739
+ if (expression.startsWith("body.")) {
1740
+ return getNestedValue(context.body, expression.slice(5));
1741
+ }
1742
+ return void 0;
1743
+ }
1744
+ function getNestedValue(value, path2) {
1745
+ if (!value || typeof value !== "object") {
1746
+ return void 0;
1747
+ }
1748
+ return path2.split(".").reduce((current, segment) => {
1749
+ if (!current || typeof current !== "object") {
1750
+ return void 0;
1751
+ }
1752
+ return current[segment];
1753
+ }, value);
1754
+ }
1755
+ function normalizeScalar(value) {
1756
+ if (typeof value === "string") {
1757
+ return value;
1758
+ }
1759
+ if (value instanceof Uint8Array) {
1760
+ return Buffer.from(value).toString("hex");
1761
+ }
1762
+ return void 0;
1763
+ }
1764
+ function normalizeStringList(value) {
1765
+ if (!value) {
1766
+ return void 0;
1767
+ }
1768
+ const list = Array.isArray(value) ? value : [value];
1769
+ const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
1770
+ return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
1771
+ }
1772
+ function normalizeTimestamp(value) {
1773
+ if (typeof value === "bigint") {
1774
+ return value;
1775
+ }
1776
+ if (typeof value === "number" && Number.isFinite(value)) {
1777
+ return BigInt(Math.trunc(value));
1778
+ }
1779
+ if (typeof value === "string" && value.trim().length > 0) {
1780
+ try {
1781
+ return BigInt(value);
1782
+ } catch {
1783
+ return void 0;
1784
+ }
1785
+ }
1786
+ return void 0;
1787
+ }
1788
+ var init_inline_capsule = __esm({
1789
+ "src/security/inline-capsule.ts"() {
1790
+ init_scopes();
1791
+ }
1792
+ });
1793
+
1794
+ // src/sensor/axis-sensor.ts
1795
+ function normalizeSensorDecision(sensorDecision) {
1796
+ if ("action" in sensorDecision) {
1797
+ switch (sensorDecision.action) {
1798
+ case "ALLOW":
1799
+ return {
1800
+ allow: true,
1801
+ riskScore: 0,
1802
+ reasons: [],
1803
+ meta: sensorDecision.meta
1804
+ };
1805
+ case "DENY":
1806
+ return {
1807
+ allow: false,
1808
+ riskScore: 100,
1809
+ reasons: [sensorDecision.code, sensorDecision.reason].filter(
1810
+ Boolean
1811
+ ),
1812
+ meta: sensorDecision.meta,
1813
+ retryAfterMs: sensorDecision.retryAfterMs
1814
+ };
1815
+ case "THROTTLE":
1816
+ return {
1817
+ allow: false,
1818
+ riskScore: 50,
1819
+ reasons: ["RATE_LIMIT"],
1820
+ retryAfterMs: sensorDecision.retryAfterMs,
1821
+ meta: sensorDecision.meta
1822
+ };
1823
+ case "FLAG":
1824
+ return {
1825
+ allow: true,
1826
+ riskScore: sensorDecision.scoreDelta,
1827
+ reasons: sensorDecision.reasons,
1828
+ meta: sensorDecision.meta
1829
+ };
1830
+ }
1831
+ }
1832
+ return {
1833
+ allow: sensorDecision.allow,
1834
+ riskScore: sensorDecision.riskScore,
1835
+ reasons: sensorDecision.reasons,
1836
+ tags: sensorDecision.tags,
1837
+ meta: sensorDecision.meta,
1838
+ tighten: sensorDecision.tighten,
1839
+ retryAfterMs: sensorDecision.retryAfterMs
1840
+ };
1841
+ }
1842
+ var Decision, SensorDecisions;
1843
+ var init_axis_sensor = __esm({
1844
+ "src/sensor/axis-sensor.ts"() {
1845
+ Decision = /* @__PURE__ */ ((Decision2) => {
1846
+ Decision2["ALLOW"] = "ALLOW";
1847
+ Decision2["DENY"] = "DENY";
1848
+ Decision2["THROTTLE"] = "THROTTLE";
1849
+ Decision2["FLAG"] = "FLAG";
1850
+ return Decision2;
1851
+ })(Decision || {});
1852
+ SensorDecisions = {
1853
+ allow(meta, tags) {
1854
+ return {
1855
+ decision: "ALLOW" /* ALLOW */,
1856
+ allow: true,
1857
+ riskScore: 0,
1858
+ reasons: [],
1859
+ tags,
1860
+ meta
1861
+ };
1862
+ },
1863
+ deny(code, reason, meta) {
1864
+ return {
1865
+ decision: "DENY" /* DENY */,
1866
+ allow: false,
1867
+ riskScore: 100,
1868
+ code,
1869
+ reasons: [code, reason].filter(Boolean),
1870
+ meta
1871
+ };
1872
+ },
1873
+ throttle(retryAfterMs, meta) {
1874
+ return {
1875
+ decision: "THROTTLE" /* THROTTLE */,
1876
+ allow: false,
1877
+ riskScore: 50,
1878
+ retryAfterMs,
1879
+ code: "RATE_LIMIT",
1880
+ reasons: ["RATE_LIMIT"],
1881
+ meta
1882
+ };
1883
+ },
1884
+ flag(scoreDelta, reasons, meta) {
1885
+ return {
1886
+ decision: "FLAG" /* FLAG */,
1887
+ allow: true,
1888
+ riskScore: scoreDelta,
1889
+ scoreDelta,
1890
+ reasons,
1891
+ meta
1892
+ };
1893
+ }
1894
+ };
1895
+ }
1896
+ });
1897
+
1898
+ // src/cce/cce.types.ts
1899
+ var CCE_PROTOCOL_VERSION, CCE_DERIVATION, CCE_AES_KEY_BYTES, CCE_IV_BYTES, CCE_NONCE_BYTES, CCE_ERROR, CceError;
1900
+ var init_cce_types = __esm({
1901
+ "src/cce/cce.types.ts"() {
1902
+ CCE_PROTOCOL_VERSION = "cce-v1";
1903
+ CCE_DERIVATION = {
1904
+ /** Request execution context */
1905
+ REQUEST: "axis:cce:req:v1",
1906
+ /** Response execution context */
1907
+ RESPONSE: "axis:cce:resp:v1",
1908
+ /** Witness binding context */
1909
+ WITNESS: "axis:cce:witness:v1"
1910
+ };
1911
+ CCE_AES_KEY_BYTES = 32;
1912
+ CCE_IV_BYTES = 12;
1913
+ CCE_NONCE_BYTES = 32;
1914
+ CCE_ERROR = {
1915
+ // Envelope errors
1916
+ INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
1917
+ UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
1918
+ MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
1919
+ MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
1920
+ // Signature errors
1921
+ CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
1922
+ CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
1923
+ // Capsule errors
1924
+ CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
1925
+ CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
1926
+ CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
1927
+ CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
1928
+ CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
1929
+ CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
1930
+ // Binding errors
1931
+ AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
1932
+ INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
1933
+ TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
1934
+ TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
1935
+ // Replay / nonce errors
1936
+ REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
1937
+ NONCE_REUSED: "CCE_NONCE_REUSED",
1938
+ // Decryption errors
1939
+ DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
1940
+ KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
1941
+ AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
1942
+ PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
1943
+ // Schema / validation errors
1944
+ PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
1945
+ INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
1946
+ // Policy errors
1947
+ POLICY_DENIED: "CCE_POLICY_DENIED",
1948
+ CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
1949
+ // Handler errors
1950
+ HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
1951
+ HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
1952
+ HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
1953
+ // Response errors
1954
+ RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
1955
+ };
1956
+ CceError = class extends Error {
1957
+ constructor(code, message, metadata) {
1958
+ super(`[${code}] ${message}`);
1959
+ this.code = code;
1960
+ this.metadata = metadata;
1961
+ this.name = "CceError";
1962
+ }
1963
+ /** Whether this error is safe to expose to the client */
1964
+ get clientSafe() {
1965
+ const internal = [
1966
+ CCE_ERROR.DECRYPTION_FAILED,
1967
+ CCE_ERROR.KEY_UNWRAP_FAILED,
1968
+ CCE_ERROR.AEAD_TAG_MISMATCH,
1969
+ CCE_ERROR.HANDLER_EXECUTION_FAILED,
1970
+ CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
1971
+ ];
1972
+ return !internal.includes(this.code);
1973
+ }
1974
+ /** Get client-safe representation */
1975
+ toClientError() {
1976
+ if (this.clientSafe) {
1977
+ return { code: this.code, message: this.message };
1978
+ }
1979
+ return {
1980
+ code: CCE_ERROR.DECRYPTION_FAILED,
1981
+ message: "Request processing failed"
1982
+ };
1983
+ }
1984
+ };
1985
+ }
1986
+ });
1987
+
1988
+ // src/cce/cce-derivation.service.ts
1989
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
1990
+ import { hkdf } from "@noble/hashes/hkdf.js";
1991
+ import { sha256 } from "@noble/hashes/sha2.js";
1992
+ function buildSalt(capsuleId, capsuleNonce, requestNonce) {
1993
+ const encoder = new TextEncoder();
1994
+ const data = encoder.encode(
1995
+ capsuleId + "|" + capsuleNonce + "|" + requestNonce
1996
+ );
1997
+ return sha256(data);
1998
+ }
1999
+ function buildInfo(contextPrefix, capsule, extraNonce) {
2000
+ const encoder = new TextEncoder();
2001
+ const parts = [
2002
+ contextPrefix,
2003
+ capsule.sub,
2004
+ capsule.kid,
2005
+ capsule.intent,
2006
+ capsule.aud,
2007
+ String(capsule.tps_from),
2008
+ String(capsule.tps_to),
2009
+ capsule.policy_hash ?? "",
2010
+ capsule.ver
2011
+ ];
2012
+ if (extraNonce) {
2013
+ parts.push(extraNonce);
2014
+ }
2015
+ return encoder.encode(parts.join("|"));
2016
+ }
2017
+ function deriveRequestExecutionKey(input) {
2018
+ const ikm = hexToBytes(input.axisLocalSecret);
2019
+ const salt = buildSalt(
2020
+ input.capsule.capsule_id,
2021
+ input.capsule.capsule_nonce,
2022
+ input.requestNonce
2023
+ );
2024
+ const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
2025
+ return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
2026
+ }
2027
+ function buildExecutionContext(input, requestId) {
2028
+ const executionKey = deriveRequestExecutionKey(input);
2029
+ const keyHash = bytesToHex(sha256(executionKey));
2030
+ executionKey.fill(0);
2031
+ return {
2032
+ execution_key_hash: keyHash,
2033
+ request_id: requestId,
2034
+ capsule_id: input.capsule.capsule_id,
2035
+ sub: input.capsule.sub,
2036
+ kid: input.capsule.kid,
2037
+ intent: input.capsule.intent,
2038
+ aud: input.capsule.aud,
2039
+ tps_from: input.capsule.tps_from,
2040
+ tps_to: input.capsule.tps_to,
2041
+ policy_hash: input.capsule.policy_hash,
2042
+ derived_at: Math.floor(Date.now() / 1e3),
2043
+ valid: true
2044
+ };
2045
+ }
2046
+ var init_cce_derivation_service = __esm({
2047
+ "src/cce/cce-derivation.service.ts"() {
2048
+ init_cce_types();
2049
+ }
2050
+ });
2051
+
2052
+ // src/cce/cce-crypto.ts
2053
+ import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
2054
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
2055
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
2056
+ function aesGcmEncrypt(key, plaintext, aad) {
2057
+ if (key.length !== CCE_AES_KEY_BYTES) {
2058
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
2059
+ }
2060
+ const iv = randomBytes(CCE_IV_BYTES);
2061
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
2062
+ if (aad) {
2063
+ cipher.setAAD(aad);
2064
+ }
2065
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
2066
+ const tag = cipher.getAuthTag();
2067
+ return {
2068
+ iv: new Uint8Array(iv),
2069
+ ciphertext: new Uint8Array(encrypted),
2070
+ tag: new Uint8Array(tag)
2071
+ };
2072
+ }
2073
+ function generateAesKey() {
2074
+ return new Uint8Array(randomBytes(CCE_AES_KEY_BYTES));
2075
+ }
2076
+ function base64UrlEncode(bytes2) {
2077
+ return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2078
+ }
2079
+ function hashPayload(payload) {
2080
+ return bytesToHex2(sha2562(payload));
2081
+ }
2082
+ var init_cce_crypto = __esm({
2083
+ "src/cce/cce-crypto.ts"() {
2084
+ init_cce_types();
2085
+ }
2086
+ });
2087
+
2088
+ // src/cce/cce-response.service.ts
2089
+ import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
2090
+ import { randomBytes as randomBytes2 } from "crypto";
1815
2091
  async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
1816
2092
  const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
1817
2093
  const responseNonce = bytesToHex3(
@@ -1984,124 +2260,20 @@ function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
1984
2260
  );
1985
2261
  const witnessKey = hkdf2(sha2563, ikm, salt, info, 32);
1986
2262
  const hash = bytesToHex4(sha2563(witnessKey));
1987
- witnessKey.fill(0);
1988
- return hash;
1989
- }
1990
- function hexToBytes2(hex) {
1991
- const bytes2 = new Uint8Array(hex.length / 2);
1992
- for (let i = 0; i < bytes2.length; i++) {
1993
- bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1994
- }
1995
- return bytes2;
1996
- }
1997
- var init_cce_witness_observer = __esm({
1998
- "src/cce/cce-witness.observer.ts"() {
1999
- init_cce_crypto();
2000
- init_cce_types();
2001
- }
2002
- });
2003
-
2004
- // src/sensor/axis-sensor.ts
2005
- function normalizeSensorDecision(sensorDecision) {
2006
- if ("action" in sensorDecision) {
2007
- switch (sensorDecision.action) {
2008
- case "ALLOW":
2009
- return {
2010
- allow: true,
2011
- riskScore: 0,
2012
- reasons: [],
2013
- meta: sensorDecision.meta
2014
- };
2015
- case "DENY":
2016
- return {
2017
- allow: false,
2018
- riskScore: 100,
2019
- reasons: [sensorDecision.code, sensorDecision.reason].filter(
2020
- Boolean
2021
- ),
2022
- meta: sensorDecision.meta,
2023
- retryAfterMs: sensorDecision.retryAfterMs
2024
- };
2025
- case "THROTTLE":
2026
- return {
2027
- allow: false,
2028
- riskScore: 50,
2029
- reasons: ["RATE_LIMIT"],
2030
- retryAfterMs: sensorDecision.retryAfterMs,
2031
- meta: sensorDecision.meta
2032
- };
2033
- case "FLAG":
2034
- return {
2035
- allow: true,
2036
- riskScore: sensorDecision.scoreDelta,
2037
- reasons: sensorDecision.reasons,
2038
- meta: sensorDecision.meta
2039
- };
2040
- }
2041
- }
2042
- return {
2043
- allow: sensorDecision.allow,
2044
- riskScore: sensorDecision.riskScore,
2045
- reasons: sensorDecision.reasons,
2046
- tags: sensorDecision.tags,
2047
- meta: sensorDecision.meta,
2048
- tighten: sensorDecision.tighten,
2049
- retryAfterMs: sensorDecision.retryAfterMs
2050
- };
2263
+ witnessKey.fill(0);
2264
+ return hash;
2051
2265
  }
2052
- var Decision, SensorDecisions;
2053
- var init_axis_sensor = __esm({
2054
- "src/sensor/axis-sensor.ts"() {
2055
- Decision = /* @__PURE__ */ ((Decision2) => {
2056
- Decision2["ALLOW"] = "ALLOW";
2057
- Decision2["DENY"] = "DENY";
2058
- Decision2["THROTTLE"] = "THROTTLE";
2059
- Decision2["FLAG"] = "FLAG";
2060
- return Decision2;
2061
- })(Decision || {});
2062
- SensorDecisions = {
2063
- allow(meta, tags) {
2064
- return {
2065
- decision: "ALLOW" /* ALLOW */,
2066
- allow: true,
2067
- riskScore: 0,
2068
- reasons: [],
2069
- tags,
2070
- meta
2071
- };
2072
- },
2073
- deny(code, reason, meta) {
2074
- return {
2075
- decision: "DENY" /* DENY */,
2076
- allow: false,
2077
- riskScore: 100,
2078
- code,
2079
- reasons: [code, reason].filter(Boolean),
2080
- meta
2081
- };
2082
- },
2083
- throttle(retryAfterMs, meta) {
2084
- return {
2085
- decision: "THROTTLE" /* THROTTLE */,
2086
- allow: false,
2087
- riskScore: 50,
2088
- retryAfterMs,
2089
- code: "RATE_LIMIT",
2090
- reasons: ["RATE_LIMIT"],
2091
- meta
2092
- };
2093
- },
2094
- flag(scoreDelta, reasons, meta) {
2095
- return {
2096
- decision: "FLAG" /* FLAG */,
2097
- allow: true,
2098
- riskScore: scoreDelta,
2099
- scoreDelta,
2100
- reasons,
2101
- meta
2102
- };
2103
- }
2104
- };
2266
+ function hexToBytes2(hex) {
2267
+ const bytes2 = new Uint8Array(hex.length / 2);
2268
+ for (let i = 0; i < bytes2.length; i++) {
2269
+ bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
2270
+ }
2271
+ return bytes2;
2272
+ }
2273
+ var init_cce_witness_observer = __esm({
2274
+ "src/cce/cce-witness.observer.ts"() {
2275
+ init_cce_crypto();
2276
+ init_cce_types();
2105
2277
  }
2106
2278
  });
2107
2279
 
@@ -2353,167 +2525,6 @@ var init_axis_error = __esm({
2353
2525
  }
2354
2526
  });
2355
2527
 
2356
- // src/security/scopes.ts
2357
- function hasScope(scopes, required) {
2358
- if (!Array.isArray(scopes) || scopes.length === 0) {
2359
- return false;
2360
- }
2361
- if (scopes.includes(required)) {
2362
- return true;
2363
- }
2364
- const [resource, id] = required.split(":");
2365
- if (resource && id) {
2366
- const wildcard = `${resource}:*`;
2367
- if (scopes.includes(wildcard)) {
2368
- return true;
2369
- }
2370
- }
2371
- return false;
2372
- }
2373
- function parseScope(scope) {
2374
- const parts = scope.split(":");
2375
- if (parts.length !== 2) return null;
2376
- return { resource: parts[0], id: parts[1] };
2377
- }
2378
- function canAccessResource(scopes, resourceType, resourceId) {
2379
- const required = `${resourceType}:${resourceId}`;
2380
- return hasScope(scopes, required);
2381
- }
2382
- var init_scopes = __esm({
2383
- "src/security/scopes.ts"() {
2384
- }
2385
- });
2386
-
2387
- // src/security/inline-capsule.ts
2388
- function normalizeInlineCapsule(input) {
2389
- if (!input || typeof input !== "object" || Array.isArray(input)) {
2390
- return null;
2391
- }
2392
- const raw = input;
2393
- const scopes = normalizeStringList(raw.scopes ?? raw.scope);
2394
- return {
2395
- id: normalizeScalar(raw.id),
2396
- actorId: normalizeScalar(raw.actorId),
2397
- intents: normalizeStringList(raw.intents),
2398
- issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
2399
- expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
2400
- realm: normalizeScalar(raw.realm),
2401
- node: normalizeScalar(raw.node),
2402
- scopes,
2403
- raw
2404
- };
2405
- }
2406
- function inlineCapsuleAllowsIntent(capsule, intent) {
2407
- if (!capsule.intents || capsule.intents.length === 0) {
2408
- return false;
2409
- }
2410
- for (const pattern of capsule.intents) {
2411
- if (pattern === "*" || pattern === intent) {
2412
- return true;
2413
- }
2414
- if (pattern.endsWith(".*")) {
2415
- const prefix = pattern.slice(0, -1);
2416
- if (intent.startsWith(prefix)) {
2417
- return true;
2418
- }
2419
- }
2420
- }
2421
- return false;
2422
- }
2423
- function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
2424
- if (capsule.expiresAt === void 0) {
2425
- return false;
2426
- }
2427
- return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
2428
- }
2429
- function resolvePolicyScopes(scopes, context) {
2430
- return scopes.map(
2431
- (scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
2432
- const resolved = resolveTemplateExpression(expression.trim(), context);
2433
- if (resolved === void 0 || resolved === null || resolved === "") {
2434
- throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
2435
- }
2436
- return String(resolved);
2437
- })
2438
- );
2439
- }
2440
- function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
2441
- if (!capsule.scopes || capsule.scopes.length === 0) {
2442
- return false;
2443
- }
2444
- if (mode === "any") {
2445
- return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
2446
- }
2447
- return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
2448
- }
2449
- function resolveTemplateExpression(expression, context) {
2450
- if (expression === "intent") {
2451
- return context.intent;
2452
- }
2453
- if (expression === "actorId") {
2454
- return context.actorId;
2455
- }
2456
- if (expression === "chainId") {
2457
- return context.chainId;
2458
- }
2459
- if (expression === "stepId") {
2460
- return context.stepId;
2461
- }
2462
- if (expression.startsWith("body.")) {
2463
- return getNestedValue(context.body, expression.slice(5));
2464
- }
2465
- return void 0;
2466
- }
2467
- function getNestedValue(value, path2) {
2468
- if (!value || typeof value !== "object") {
2469
- return void 0;
2470
- }
2471
- return path2.split(".").reduce((current, segment) => {
2472
- if (!current || typeof current !== "object") {
2473
- return void 0;
2474
- }
2475
- return current[segment];
2476
- }, value);
2477
- }
2478
- function normalizeScalar(value) {
2479
- if (typeof value === "string") {
2480
- return value;
2481
- }
2482
- if (value instanceof Uint8Array) {
2483
- return Buffer.from(value).toString("hex");
2484
- }
2485
- return void 0;
2486
- }
2487
- function normalizeStringList(value) {
2488
- if (!value) {
2489
- return void 0;
2490
- }
2491
- const list = Array.isArray(value) ? value : [value];
2492
- const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
2493
- return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
2494
- }
2495
- function normalizeTimestamp(value) {
2496
- if (typeof value === "bigint") {
2497
- return value;
2498
- }
2499
- if (typeof value === "number" && Number.isFinite(value)) {
2500
- return BigInt(Math.trunc(value));
2501
- }
2502
- if (typeof value === "string" && value.trim().length > 0) {
2503
- try {
2504
- return BigInt(value);
2505
- } catch {
2506
- return void 0;
2507
- }
2508
- }
2509
- return void 0;
2510
- }
2511
- var init_inline_capsule = __esm({
2512
- "src/security/inline-capsule.ts"() {
2513
- init_scopes();
2514
- }
2515
- });
2516
-
2517
2528
  // src/engine/intent.router.ts
2518
2529
  var intent_router_exports = {};
2519
2530
  __export(intent_router_exports, {
@@ -2590,23 +2601,23 @@ function normalizeChainConfig(decoratorConfig, intentConfig) {
2590
2601
  var import_dto_schema, _IntentRouter, IntentRouter;
2591
2602
  var init_intent_router = __esm({
2592
2603
  "src/engine/intent.router.ts"() {
2593
- init_cce_pipeline();
2594
- init_axis_error();
2595
- init_constants();
2596
- init_capsule_policy_decorator();
2597
- init_chain_decorator();
2598
- import_dto_schema = __toESM(require_dto_schema_util());
2599
2604
  init_handler_sensors_decorator();
2600
- init_handler_decorator();
2601
- init_intent_body_decorator();
2602
- init_intent_policy_decorator();
2605
+ init_capsule_policy_decorator();
2603
2606
  init_intent_sensors_decorator();
2604
- init_intent_decorator();
2607
+ init_intent_policy_decorator();
2608
+ init_intent_body_decorator();
2605
2609
  init_observer_decorator();
2610
+ init_handler_decorator();
2611
+ init_intent_decorator();
2612
+ init_chain_decorator();
2613
+ import_dto_schema = __toESM(require_dto_schema_util());
2606
2614
  init_inline_capsule();
2607
- init_axis_sensor();
2608
2615
  init_axis_execution_context();
2616
+ init_axis_sensor();
2609
2617
  init_axis_logger();
2618
+ init_cce_pipeline();
2619
+ init_axis_error();
2620
+ init_constants();
2610
2621
  _IntentRouter = class _IntentRouter {
2611
2622
  constructor(dependencyResolver, observerDispatcher, sensorRegistry) {
2612
2623
  this.logger = createAxisLogger(_IntentRouter.name);
@@ -2642,6 +2653,8 @@ var init_intent_router = __esm({
2642
2653
  this.publicIntents = /* @__PURE__ */ new Set();
2643
2654
  /** Intents flagged as anonymous-session accessible */
2644
2655
  this.anonymousIntents = /* @__PURE__ */ new Set();
2656
+ /** Intents flagged as authorized-session accessible */
2657
+ this.authorizedIntents = /* @__PURE__ */ new Set();
2645
2658
  /** Per-intent rate limit config */
2646
2659
  this.intentRateLimits = /* @__PURE__ */ new Map();
2647
2660
  /** CCE handler registry */
@@ -3068,6 +3081,18 @@ var init_intent_router = __esm({
3068
3081
  if (isAnonMethod || isAnonClass) {
3069
3082
  this.anonymousIntents.add(intent);
3070
3083
  }
3084
+ const isAuthorizedMethod = Reflect.getMetadata(
3085
+ AXIS_AUTHORIZED_KEY,
3086
+ proto,
3087
+ methodName
3088
+ );
3089
+ const isAuthorizedClass = Reflect.getMetadata(
3090
+ AXIS_AUTHORIZED_KEY,
3091
+ proto.constructor
3092
+ );
3093
+ if (isAuthorizedMethod || isAuthorizedClass) {
3094
+ this.authorizedIntents.add(intent);
3095
+ }
3071
3096
  const rateLimit = Reflect.getMetadata(
3072
3097
  AXIS_RATE_LIMIT_KEY,
3073
3098
  proto,
@@ -3093,6 +3118,9 @@ var init_intent_router = __esm({
3093
3118
  isAnonymous(intent) {
3094
3119
  return this.anonymousIntents.has(intent);
3095
3120
  }
3121
+ isAuthorized(intent) {
3122
+ return this.authorizedIntents.has(intent);
3123
+ }
3096
3124
  getRateLimit(intent) {
3097
3125
  return this.intentRateLimits.get(intent);
3098
3126
  }
@@ -10597,6 +10625,7 @@ __export(index_exports, {
10597
10625
  ATS1_HDR: () => ATS1_HDR,
10598
10626
  ATS1_SCHEMA: () => ATS1_SCHEMA,
10599
10627
  AXIS_ANONYMOUS_KEY: () => AXIS_ANONYMOUS_KEY,
10628
+ AXIS_AUTHORIZED_KEY: () => AXIS_AUTHORIZED_KEY,
10600
10629
  AXIS_EXECUTION_CONTEXT_KEY: () => AXIS_EXECUTION_CONTEXT_KEY,
10601
10630
  AXIS_MAGIC: () => AXIS_MAGIC,
10602
10631
  AXIS_META_KEY: () => AXIS_META_KEY,
@@ -10610,6 +10639,7 @@ __export(index_exports, {
10610
10639
  Ats1Codec: () => ats1_exports,
10611
10640
  Axis: () => Axis,
10612
10641
  AxisAnonymous: () => AxisAnonymous,
10642
+ AxisAuthorized: () => AxisAuthorized,
10613
10643
  AxisChainExecutor: () => AxisChainExecutor,
10614
10644
  AxisError: () => AxisError,
10615
10645
  AxisFrameZ: () => AxisFrameZ,