@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.
@@ -500,6 +500,16 @@ function AxisPublic() {
500
500
  return target;
501
501
  };
502
502
  }
503
+ function AxisAuthorized() {
504
+ return (target, propertyKey, descriptor) => {
505
+ if (descriptor) {
506
+ Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target, propertyKey);
507
+ return descriptor;
508
+ }
509
+ Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target);
510
+ return target;
511
+ };
512
+ }
503
513
  function AxisAnonymous() {
504
514
  return (target, propertyKey, descriptor) => {
505
515
  if (descriptor) {
@@ -516,7 +526,7 @@ function AxisRateLimit(config) {
516
526
  return descriptor;
517
527
  };
518
528
  }
519
- var import_reflect_metadata4, AXIS_META_KEY, SENSITIVITY_METADATA_KEY, CONTRACT_METADATA_KEY, REQUIRED_PROOF_METADATA_KEY, AXIS_PUBLIC_KEY, AXIS_ANONYMOUS_KEY, AXIS_RATE_LIMIT_KEY;
529
+ var import_reflect_metadata4, 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;
520
530
  var init_intent_policy_decorator = __esm({
521
531
  "src/decorators/intent-policy.decorator.ts"() {
522
532
  import_reflect_metadata4 = require("reflect-metadata");
@@ -526,6 +536,7 @@ var init_intent_policy_decorator = __esm({
526
536
  REQUIRED_PROOF_METADATA_KEY = "axis:required_proof";
527
537
  AXIS_PUBLIC_KEY = "axis:public";
528
538
  AXIS_ANONYMOUS_KEY = "axis:anonymous";
539
+ AXIS_AUTHORIZED_KEY = "axis:authorized";
529
540
  AXIS_RATE_LIMIT_KEY = "axis:rateLimit";
530
541
  }
531
542
  });
@@ -1545,199 +1556,464 @@ var init_axis_chain_executor = __esm({
1545
1556
  }
1546
1557
  });
1547
1558
 
1548
- // src/cce/cce.types.ts
1549
- var CCE_PROTOCOL_VERSION, CCE_DERIVATION, CCE_AES_KEY_BYTES, CCE_IV_BYTES, CCE_NONCE_BYTES, CCE_ERROR, CceError;
1550
- var init_cce_types = __esm({
1551
- "src/cce/cce.types.ts"() {
1552
- CCE_PROTOCOL_VERSION = "cce-v1";
1553
- CCE_DERIVATION = {
1554
- /** Request execution context */
1555
- REQUEST: "axis:cce:req:v1",
1556
- /** Response execution context */
1557
- RESPONSE: "axis:cce:resp:v1",
1558
- /** Witness binding context */
1559
- WITNESS: "axis:cce:witness:v1"
1560
- };
1561
- CCE_AES_KEY_BYTES = 32;
1562
- CCE_IV_BYTES = 12;
1563
- CCE_NONCE_BYTES = 32;
1564
- CCE_ERROR = {
1565
- // Envelope errors
1566
- INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
1567
- UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
1568
- MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
1569
- MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
1570
- // Signature errors
1571
- CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
1572
- CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
1573
- // Capsule errors
1574
- CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
1575
- CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
1576
- CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
1577
- CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
1578
- CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
1579
- CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
1580
- // Binding errors
1581
- AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
1582
- INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
1583
- TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
1584
- TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
1585
- // Replay / nonce errors
1586
- REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
1587
- NONCE_REUSED: "CCE_NONCE_REUSED",
1588
- // Decryption errors
1589
- DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
1590
- KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
1591
- AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
1592
- PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
1593
- // Schema / validation errors
1594
- PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
1595
- INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
1596
- // Policy errors
1597
- POLICY_DENIED: "CCE_POLICY_DENIED",
1598
- CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
1599
- // Handler errors
1600
- HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
1601
- HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
1602
- HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
1603
- // Response errors
1604
- RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
1605
- };
1606
- CceError = class extends Error {
1607
- constructor(code, message, metadata) {
1608
- super(`[${code}] ${message}`);
1609
- this.code = code;
1610
- this.metadata = metadata;
1611
- this.name = "CceError";
1612
- }
1613
- /** Whether this error is safe to expose to the client */
1614
- get clientSafe() {
1615
- const internal = [
1616
- CCE_ERROR.DECRYPTION_FAILED,
1617
- CCE_ERROR.KEY_UNWRAP_FAILED,
1618
- CCE_ERROR.AEAD_TAG_MISMATCH,
1619
- CCE_ERROR.HANDLER_EXECUTION_FAILED,
1620
- CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
1621
- ];
1622
- return !internal.includes(this.code);
1623
- }
1624
- /** Get client-safe representation */
1625
- toClientError() {
1626
- if (this.clientSafe) {
1627
- return { code: this.code, message: this.message };
1628
- }
1629
- return {
1630
- code: CCE_ERROR.DECRYPTION_FAILED,
1631
- message: "Request processing failed"
1632
- };
1633
- }
1634
- };
1559
+ // src/security/scopes.ts
1560
+ function hasScope(scopes, required) {
1561
+ if (!Array.isArray(scopes) || scopes.length === 0) {
1562
+ return false;
1635
1563
  }
1636
- });
1637
-
1638
- // src/cce/cce-derivation.service.ts
1639
- function buildSalt(capsuleId, capsuleNonce, requestNonce) {
1640
- const encoder = new TextEncoder();
1641
- const data = encoder.encode(
1642
- capsuleId + "|" + capsuleNonce + "|" + requestNonce
1643
- );
1644
- return (0, import_sha2.sha256)(data);
1645
- }
1646
- function buildInfo(contextPrefix, capsule, extraNonce) {
1647
- const encoder = new TextEncoder();
1648
- const parts = [
1649
- contextPrefix,
1650
- capsule.sub,
1651
- capsule.kid,
1652
- capsule.intent,
1653
- capsule.aud,
1654
- String(capsule.tps_from),
1655
- String(capsule.tps_to),
1656
- capsule.policy_hash ?? "",
1657
- capsule.ver
1658
- ];
1659
- if (extraNonce) {
1660
- parts.push(extraNonce);
1564
+ if (scopes.includes(required)) {
1565
+ return true;
1661
1566
  }
1662
- return encoder.encode(parts.join("|"));
1567
+ const [resource, id] = required.split(":");
1568
+ if (resource && id) {
1569
+ const wildcard = `${resource}:*`;
1570
+ if (scopes.includes(wildcard)) {
1571
+ return true;
1572
+ }
1573
+ }
1574
+ return false;
1663
1575
  }
1664
- function deriveRequestExecutionKey(input) {
1665
- const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
1666
- const salt = buildSalt(
1667
- input.capsule.capsule_id,
1668
- input.capsule.capsule_nonce,
1669
- input.requestNonce
1670
- );
1671
- const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
1672
- return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
1576
+ function parseScope(scope) {
1577
+ const parts = scope.split(":");
1578
+ if (parts.length !== 2) return null;
1579
+ return { resource: parts[0], id: parts[1] };
1673
1580
  }
1674
- function buildExecutionContext(input, requestId) {
1675
- const executionKey = deriveRequestExecutionKey(input);
1676
- const keyHash = (0, import_utils.bytesToHex)((0, import_sha2.sha256)(executionKey));
1677
- executionKey.fill(0);
1678
- return {
1679
- execution_key_hash: keyHash,
1680
- request_id: requestId,
1681
- capsule_id: input.capsule.capsule_id,
1682
- sub: input.capsule.sub,
1683
- kid: input.capsule.kid,
1684
- intent: input.capsule.intent,
1685
- aud: input.capsule.aud,
1686
- tps_from: input.capsule.tps_from,
1687
- tps_to: input.capsule.tps_to,
1688
- policy_hash: input.capsule.policy_hash,
1689
- derived_at: Math.floor(Date.now() / 1e3),
1690
- valid: true
1691
- };
1581
+ function canAccessResource(scopes, resourceType, resourceId) {
1582
+ const required = `${resourceType}:${resourceId}`;
1583
+ return hasScope(scopes, required);
1692
1584
  }
1693
- var import_utils, import_hkdf, import_sha2;
1694
- var init_cce_derivation_service = __esm({
1695
- "src/cce/cce-derivation.service.ts"() {
1696
- import_utils = require("@noble/hashes/utils.js");
1697
- import_hkdf = require("@noble/hashes/hkdf.js");
1698
- import_sha2 = require("@noble/hashes/sha2.js");
1699
- init_cce_types();
1585
+ var init_scopes = __esm({
1586
+ "src/security/scopes.ts"() {
1700
1587
  }
1701
1588
  });
1702
1589
 
1703
- // src/cce/cce-crypto.ts
1704
- function aesGcmEncrypt(key, plaintext, aad) {
1705
- if (key.length !== CCE_AES_KEY_BYTES) {
1706
- throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
1707
- }
1708
- const iv = (0, import_crypto2.randomBytes)(CCE_IV_BYTES);
1709
- const cipher = (0, import_crypto2.createCipheriv)("aes-256-gcm", key, iv);
1710
- if (aad) {
1711
- cipher.setAAD(aad);
1590
+ // src/security/inline-capsule.ts
1591
+ function normalizeInlineCapsule(input) {
1592
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
1593
+ return null;
1712
1594
  }
1713
- const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1714
- const tag = cipher.getAuthTag();
1595
+ const raw = input;
1596
+ const scopes = normalizeStringList(raw.scopes ?? raw.scope);
1715
1597
  return {
1716
- iv: new Uint8Array(iv),
1717
- ciphertext: new Uint8Array(encrypted),
1718
- tag: new Uint8Array(tag)
1598
+ id: normalizeScalar(raw.id),
1599
+ actorId: normalizeScalar(raw.actorId),
1600
+ intents: normalizeStringList(raw.intents),
1601
+ issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
1602
+ expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
1603
+ realm: normalizeScalar(raw.realm),
1604
+ node: normalizeScalar(raw.node),
1605
+ scopes,
1606
+ raw
1719
1607
  };
1720
1608
  }
1721
- function generateAesKey() {
1722
- return new Uint8Array((0, import_crypto2.randomBytes)(CCE_AES_KEY_BYTES));
1609
+ function inlineCapsuleAllowsIntent(capsule, intent) {
1610
+ if (!capsule.intents || capsule.intents.length === 0) {
1611
+ return false;
1612
+ }
1613
+ for (const pattern of capsule.intents) {
1614
+ if (pattern === "*" || pattern === intent) {
1615
+ return true;
1616
+ }
1617
+ if (pattern.endsWith(".*")) {
1618
+ const prefix = pattern.slice(0, -1);
1619
+ if (intent.startsWith(prefix)) {
1620
+ return true;
1621
+ }
1622
+ }
1623
+ }
1624
+ return false;
1723
1625
  }
1724
- function base64UrlEncode(bytes2) {
1725
- return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1626
+ function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
1627
+ if (capsule.expiresAt === void 0) {
1628
+ return false;
1629
+ }
1630
+ return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
1726
1631
  }
1727
- function hashPayload(payload) {
1728
- return (0, import_utils2.bytesToHex)((0, import_sha22.sha256)(payload));
1632
+ function resolvePolicyScopes(scopes, context) {
1633
+ return scopes.map(
1634
+ (scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
1635
+ const resolved = resolveTemplateExpression(expression.trim(), context);
1636
+ if (resolved === void 0 || resolved === null || resolved === "") {
1637
+ throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
1638
+ }
1639
+ return String(resolved);
1640
+ })
1641
+ );
1729
1642
  }
1730
- var import_utils2, import_sha22, import_crypto2;
1731
- var init_cce_crypto = __esm({
1732
- "src/cce/cce-crypto.ts"() {
1733
- import_utils2 = require("@noble/hashes/utils.js");
1734
- import_sha22 = require("@noble/hashes/sha2.js");
1735
- import_crypto2 = require("crypto");
1736
- init_cce_types();
1643
+ function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
1644
+ if (!capsule.scopes || capsule.scopes.length === 0) {
1645
+ return false;
1737
1646
  }
1738
- });
1739
-
1740
- // src/cce/cce-response.service.ts
1647
+ if (mode === "any") {
1648
+ return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
1649
+ }
1650
+ return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
1651
+ }
1652
+ function resolveTemplateExpression(expression, context) {
1653
+ if (expression === "intent") {
1654
+ return context.intent;
1655
+ }
1656
+ if (expression === "actorId") {
1657
+ return context.actorId;
1658
+ }
1659
+ if (expression === "chainId") {
1660
+ return context.chainId;
1661
+ }
1662
+ if (expression === "stepId") {
1663
+ return context.stepId;
1664
+ }
1665
+ if (expression.startsWith("body.")) {
1666
+ return getNestedValue(context.body, expression.slice(5));
1667
+ }
1668
+ return void 0;
1669
+ }
1670
+ function getNestedValue(value, path2) {
1671
+ if (!value || typeof value !== "object") {
1672
+ return void 0;
1673
+ }
1674
+ return path2.split(".").reduce((current, segment) => {
1675
+ if (!current || typeof current !== "object") {
1676
+ return void 0;
1677
+ }
1678
+ return current[segment];
1679
+ }, value);
1680
+ }
1681
+ function normalizeScalar(value) {
1682
+ if (typeof value === "string") {
1683
+ return value;
1684
+ }
1685
+ if (value instanceof Uint8Array) {
1686
+ return Buffer.from(value).toString("hex");
1687
+ }
1688
+ return void 0;
1689
+ }
1690
+ function normalizeStringList(value) {
1691
+ if (!value) {
1692
+ return void 0;
1693
+ }
1694
+ const list = Array.isArray(value) ? value : [value];
1695
+ const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
1696
+ return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
1697
+ }
1698
+ function normalizeTimestamp(value) {
1699
+ if (typeof value === "bigint") {
1700
+ return value;
1701
+ }
1702
+ if (typeof value === "number" && Number.isFinite(value)) {
1703
+ return BigInt(Math.trunc(value));
1704
+ }
1705
+ if (typeof value === "string" && value.trim().length > 0) {
1706
+ try {
1707
+ return BigInt(value);
1708
+ } catch {
1709
+ return void 0;
1710
+ }
1711
+ }
1712
+ return void 0;
1713
+ }
1714
+ var init_inline_capsule = __esm({
1715
+ "src/security/inline-capsule.ts"() {
1716
+ init_scopes();
1717
+ }
1718
+ });
1719
+
1720
+ // src/sensor/axis-sensor.ts
1721
+ function normalizeSensorDecision(sensorDecision) {
1722
+ if ("action" in sensorDecision) {
1723
+ switch (sensorDecision.action) {
1724
+ case "ALLOW":
1725
+ return {
1726
+ allow: true,
1727
+ riskScore: 0,
1728
+ reasons: [],
1729
+ meta: sensorDecision.meta
1730
+ };
1731
+ case "DENY":
1732
+ return {
1733
+ allow: false,
1734
+ riskScore: 100,
1735
+ reasons: [sensorDecision.code, sensorDecision.reason].filter(
1736
+ Boolean
1737
+ ),
1738
+ meta: sensorDecision.meta,
1739
+ retryAfterMs: sensorDecision.retryAfterMs
1740
+ };
1741
+ case "THROTTLE":
1742
+ return {
1743
+ allow: false,
1744
+ riskScore: 50,
1745
+ reasons: ["RATE_LIMIT"],
1746
+ retryAfterMs: sensorDecision.retryAfterMs,
1747
+ meta: sensorDecision.meta
1748
+ };
1749
+ case "FLAG":
1750
+ return {
1751
+ allow: true,
1752
+ riskScore: sensorDecision.scoreDelta,
1753
+ reasons: sensorDecision.reasons,
1754
+ meta: sensorDecision.meta
1755
+ };
1756
+ }
1757
+ }
1758
+ return {
1759
+ allow: sensorDecision.allow,
1760
+ riskScore: sensorDecision.riskScore,
1761
+ reasons: sensorDecision.reasons,
1762
+ tags: sensorDecision.tags,
1763
+ meta: sensorDecision.meta,
1764
+ tighten: sensorDecision.tighten,
1765
+ retryAfterMs: sensorDecision.retryAfterMs
1766
+ };
1767
+ }
1768
+ var Decision, SensorDecisions;
1769
+ var init_axis_sensor = __esm({
1770
+ "src/sensor/axis-sensor.ts"() {
1771
+ Decision = /* @__PURE__ */ ((Decision2) => {
1772
+ Decision2["ALLOW"] = "ALLOW";
1773
+ Decision2["DENY"] = "DENY";
1774
+ Decision2["THROTTLE"] = "THROTTLE";
1775
+ Decision2["FLAG"] = "FLAG";
1776
+ return Decision2;
1777
+ })(Decision || {});
1778
+ SensorDecisions = {
1779
+ allow(meta, tags) {
1780
+ return {
1781
+ decision: "ALLOW" /* ALLOW */,
1782
+ allow: true,
1783
+ riskScore: 0,
1784
+ reasons: [],
1785
+ tags,
1786
+ meta
1787
+ };
1788
+ },
1789
+ deny(code, reason, meta) {
1790
+ return {
1791
+ decision: "DENY" /* DENY */,
1792
+ allow: false,
1793
+ riskScore: 100,
1794
+ code,
1795
+ reasons: [code, reason].filter(Boolean),
1796
+ meta
1797
+ };
1798
+ },
1799
+ throttle(retryAfterMs, meta) {
1800
+ return {
1801
+ decision: "THROTTLE" /* THROTTLE */,
1802
+ allow: false,
1803
+ riskScore: 50,
1804
+ retryAfterMs,
1805
+ code: "RATE_LIMIT",
1806
+ reasons: ["RATE_LIMIT"],
1807
+ meta
1808
+ };
1809
+ },
1810
+ flag(scoreDelta, reasons, meta) {
1811
+ return {
1812
+ decision: "FLAG" /* FLAG */,
1813
+ allow: true,
1814
+ riskScore: scoreDelta,
1815
+ scoreDelta,
1816
+ reasons,
1817
+ meta
1818
+ };
1819
+ }
1820
+ };
1821
+ }
1822
+ });
1823
+
1824
+ // src/cce/cce.types.ts
1825
+ var CCE_PROTOCOL_VERSION, CCE_DERIVATION, CCE_AES_KEY_BYTES, CCE_IV_BYTES, CCE_NONCE_BYTES, CCE_ERROR, CceError;
1826
+ var init_cce_types = __esm({
1827
+ "src/cce/cce.types.ts"() {
1828
+ CCE_PROTOCOL_VERSION = "cce-v1";
1829
+ CCE_DERIVATION = {
1830
+ /** Request execution context */
1831
+ REQUEST: "axis:cce:req:v1",
1832
+ /** Response execution context */
1833
+ RESPONSE: "axis:cce:resp:v1",
1834
+ /** Witness binding context */
1835
+ WITNESS: "axis:cce:witness:v1"
1836
+ };
1837
+ CCE_AES_KEY_BYTES = 32;
1838
+ CCE_IV_BYTES = 12;
1839
+ CCE_NONCE_BYTES = 32;
1840
+ CCE_ERROR = {
1841
+ // Envelope errors
1842
+ INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
1843
+ UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
1844
+ MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
1845
+ MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
1846
+ // Signature errors
1847
+ CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
1848
+ CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
1849
+ // Capsule errors
1850
+ CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
1851
+ CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
1852
+ CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
1853
+ CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
1854
+ CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
1855
+ CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
1856
+ // Binding errors
1857
+ AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
1858
+ INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
1859
+ TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
1860
+ TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
1861
+ // Replay / nonce errors
1862
+ REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
1863
+ NONCE_REUSED: "CCE_NONCE_REUSED",
1864
+ // Decryption errors
1865
+ DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
1866
+ KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
1867
+ AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
1868
+ PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
1869
+ // Schema / validation errors
1870
+ PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
1871
+ INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
1872
+ // Policy errors
1873
+ POLICY_DENIED: "CCE_POLICY_DENIED",
1874
+ CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
1875
+ // Handler errors
1876
+ HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
1877
+ HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
1878
+ HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
1879
+ // Response errors
1880
+ RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
1881
+ };
1882
+ CceError = class extends Error {
1883
+ constructor(code, message, metadata) {
1884
+ super(`[${code}] ${message}`);
1885
+ this.code = code;
1886
+ this.metadata = metadata;
1887
+ this.name = "CceError";
1888
+ }
1889
+ /** Whether this error is safe to expose to the client */
1890
+ get clientSafe() {
1891
+ const internal = [
1892
+ CCE_ERROR.DECRYPTION_FAILED,
1893
+ CCE_ERROR.KEY_UNWRAP_FAILED,
1894
+ CCE_ERROR.AEAD_TAG_MISMATCH,
1895
+ CCE_ERROR.HANDLER_EXECUTION_FAILED,
1896
+ CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
1897
+ ];
1898
+ return !internal.includes(this.code);
1899
+ }
1900
+ /** Get client-safe representation */
1901
+ toClientError() {
1902
+ if (this.clientSafe) {
1903
+ return { code: this.code, message: this.message };
1904
+ }
1905
+ return {
1906
+ code: CCE_ERROR.DECRYPTION_FAILED,
1907
+ message: "Request processing failed"
1908
+ };
1909
+ }
1910
+ };
1911
+ }
1912
+ });
1913
+
1914
+ // src/cce/cce-derivation.service.ts
1915
+ function buildSalt(capsuleId, capsuleNonce, requestNonce) {
1916
+ const encoder = new TextEncoder();
1917
+ const data = encoder.encode(
1918
+ capsuleId + "|" + capsuleNonce + "|" + requestNonce
1919
+ );
1920
+ return (0, import_sha2.sha256)(data);
1921
+ }
1922
+ function buildInfo(contextPrefix, capsule, extraNonce) {
1923
+ const encoder = new TextEncoder();
1924
+ const parts = [
1925
+ contextPrefix,
1926
+ capsule.sub,
1927
+ capsule.kid,
1928
+ capsule.intent,
1929
+ capsule.aud,
1930
+ String(capsule.tps_from),
1931
+ String(capsule.tps_to),
1932
+ capsule.policy_hash ?? "",
1933
+ capsule.ver
1934
+ ];
1935
+ if (extraNonce) {
1936
+ parts.push(extraNonce);
1937
+ }
1938
+ return encoder.encode(parts.join("|"));
1939
+ }
1940
+ function deriveRequestExecutionKey(input) {
1941
+ const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
1942
+ const salt = buildSalt(
1943
+ input.capsule.capsule_id,
1944
+ input.capsule.capsule_nonce,
1945
+ input.requestNonce
1946
+ );
1947
+ const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
1948
+ return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
1949
+ }
1950
+ function buildExecutionContext(input, requestId) {
1951
+ const executionKey = deriveRequestExecutionKey(input);
1952
+ const keyHash = (0, import_utils.bytesToHex)((0, import_sha2.sha256)(executionKey));
1953
+ executionKey.fill(0);
1954
+ return {
1955
+ execution_key_hash: keyHash,
1956
+ request_id: requestId,
1957
+ capsule_id: input.capsule.capsule_id,
1958
+ sub: input.capsule.sub,
1959
+ kid: input.capsule.kid,
1960
+ intent: input.capsule.intent,
1961
+ aud: input.capsule.aud,
1962
+ tps_from: input.capsule.tps_from,
1963
+ tps_to: input.capsule.tps_to,
1964
+ policy_hash: input.capsule.policy_hash,
1965
+ derived_at: Math.floor(Date.now() / 1e3),
1966
+ valid: true
1967
+ };
1968
+ }
1969
+ var import_utils, import_hkdf, import_sha2;
1970
+ var init_cce_derivation_service = __esm({
1971
+ "src/cce/cce-derivation.service.ts"() {
1972
+ import_utils = require("@noble/hashes/utils.js");
1973
+ import_hkdf = require("@noble/hashes/hkdf.js");
1974
+ import_sha2 = require("@noble/hashes/sha2.js");
1975
+ init_cce_types();
1976
+ }
1977
+ });
1978
+
1979
+ // src/cce/cce-crypto.ts
1980
+ function aesGcmEncrypt(key, plaintext, aad) {
1981
+ if (key.length !== CCE_AES_KEY_BYTES) {
1982
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
1983
+ }
1984
+ const iv = (0, import_crypto2.randomBytes)(CCE_IV_BYTES);
1985
+ const cipher = (0, import_crypto2.createCipheriv)("aes-256-gcm", key, iv);
1986
+ if (aad) {
1987
+ cipher.setAAD(aad);
1988
+ }
1989
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1990
+ const tag = cipher.getAuthTag();
1991
+ return {
1992
+ iv: new Uint8Array(iv),
1993
+ ciphertext: new Uint8Array(encrypted),
1994
+ tag: new Uint8Array(tag)
1995
+ };
1996
+ }
1997
+ function generateAesKey() {
1998
+ return new Uint8Array((0, import_crypto2.randomBytes)(CCE_AES_KEY_BYTES));
1999
+ }
2000
+ function base64UrlEncode(bytes2) {
2001
+ return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2002
+ }
2003
+ function hashPayload(payload) {
2004
+ return (0, import_utils2.bytesToHex)((0, import_sha22.sha256)(payload));
2005
+ }
2006
+ var import_utils2, import_sha22, import_crypto2;
2007
+ var init_cce_crypto = __esm({
2008
+ "src/cce/cce-crypto.ts"() {
2009
+ import_utils2 = require("@noble/hashes/utils.js");
2010
+ import_sha22 = require("@noble/hashes/sha2.js");
2011
+ import_crypto2 = require("crypto");
2012
+ init_cce_types();
2013
+ }
2014
+ });
2015
+
2016
+ // src/cce/cce-response.service.ts
1741
2017
  async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
1742
2018
  const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
1743
2019
  const responseNonce = (0, import_utils3.bytesToHex)(
@@ -1914,124 +2190,20 @@ function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
1914
2190
  return hash;
1915
2191
  }
1916
2192
  function hexToBytes2(hex) {
1917
- const bytes2 = new Uint8Array(hex.length / 2);
1918
- for (let i = 0; i < bytes2.length; i++) {
1919
- bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1920
- }
1921
- return bytes2;
1922
- }
1923
- var import_utils4, import_hkdf2, import_sha23;
1924
- var init_cce_witness_observer = __esm({
1925
- "src/cce/cce-witness.observer.ts"() {
1926
- import_utils4 = require("@noble/hashes/utils.js");
1927
- import_hkdf2 = require("@noble/hashes/hkdf.js");
1928
- import_sha23 = require("@noble/hashes/sha2.js");
1929
- init_cce_crypto();
1930
- init_cce_types();
1931
- }
1932
- });
1933
-
1934
- // src/sensor/axis-sensor.ts
1935
- function normalizeSensorDecision(sensorDecision) {
1936
- if ("action" in sensorDecision) {
1937
- switch (sensorDecision.action) {
1938
- case "ALLOW":
1939
- return {
1940
- allow: true,
1941
- riskScore: 0,
1942
- reasons: [],
1943
- meta: sensorDecision.meta
1944
- };
1945
- case "DENY":
1946
- return {
1947
- allow: false,
1948
- riskScore: 100,
1949
- reasons: [sensorDecision.code, sensorDecision.reason].filter(
1950
- Boolean
1951
- ),
1952
- meta: sensorDecision.meta,
1953
- retryAfterMs: sensorDecision.retryAfterMs
1954
- };
1955
- case "THROTTLE":
1956
- return {
1957
- allow: false,
1958
- riskScore: 50,
1959
- reasons: ["RATE_LIMIT"],
1960
- retryAfterMs: sensorDecision.retryAfterMs,
1961
- meta: sensorDecision.meta
1962
- };
1963
- case "FLAG":
1964
- return {
1965
- allow: true,
1966
- riskScore: sensorDecision.scoreDelta,
1967
- reasons: sensorDecision.reasons,
1968
- meta: sensorDecision.meta
1969
- };
1970
- }
1971
- }
1972
- return {
1973
- allow: sensorDecision.allow,
1974
- riskScore: sensorDecision.riskScore,
1975
- reasons: sensorDecision.reasons,
1976
- tags: sensorDecision.tags,
1977
- meta: sensorDecision.meta,
1978
- tighten: sensorDecision.tighten,
1979
- retryAfterMs: sensorDecision.retryAfterMs
1980
- };
2193
+ const bytes2 = new Uint8Array(hex.length / 2);
2194
+ for (let i = 0; i < bytes2.length; i++) {
2195
+ bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
2196
+ }
2197
+ return bytes2;
1981
2198
  }
1982
- var Decision, SensorDecisions;
1983
- var init_axis_sensor = __esm({
1984
- "src/sensor/axis-sensor.ts"() {
1985
- Decision = /* @__PURE__ */ ((Decision2) => {
1986
- Decision2["ALLOW"] = "ALLOW";
1987
- Decision2["DENY"] = "DENY";
1988
- Decision2["THROTTLE"] = "THROTTLE";
1989
- Decision2["FLAG"] = "FLAG";
1990
- return Decision2;
1991
- })(Decision || {});
1992
- SensorDecisions = {
1993
- allow(meta, tags) {
1994
- return {
1995
- decision: "ALLOW" /* ALLOW */,
1996
- allow: true,
1997
- riskScore: 0,
1998
- reasons: [],
1999
- tags,
2000
- meta
2001
- };
2002
- },
2003
- deny(code, reason, meta) {
2004
- return {
2005
- decision: "DENY" /* DENY */,
2006
- allow: false,
2007
- riskScore: 100,
2008
- code,
2009
- reasons: [code, reason].filter(Boolean),
2010
- meta
2011
- };
2012
- },
2013
- throttle(retryAfterMs, meta) {
2014
- return {
2015
- decision: "THROTTLE" /* THROTTLE */,
2016
- allow: false,
2017
- riskScore: 50,
2018
- retryAfterMs,
2019
- code: "RATE_LIMIT",
2020
- reasons: ["RATE_LIMIT"],
2021
- meta
2022
- };
2023
- },
2024
- flag(scoreDelta, reasons, meta) {
2025
- return {
2026
- decision: "FLAG" /* FLAG */,
2027
- allow: true,
2028
- riskScore: scoreDelta,
2029
- scoreDelta,
2030
- reasons,
2031
- meta
2032
- };
2033
- }
2034
- };
2199
+ var import_utils4, import_hkdf2, import_sha23;
2200
+ var init_cce_witness_observer = __esm({
2201
+ "src/cce/cce-witness.observer.ts"() {
2202
+ import_utils4 = require("@noble/hashes/utils.js");
2203
+ import_hkdf2 = require("@noble/hashes/hkdf.js");
2204
+ import_sha23 = require("@noble/hashes/sha2.js");
2205
+ init_cce_crypto();
2206
+ init_cce_types();
2035
2207
  }
2036
2208
  });
2037
2209
 
@@ -2283,167 +2455,6 @@ var init_axis_error = __esm({
2283
2455
  }
2284
2456
  });
2285
2457
 
2286
- // src/security/scopes.ts
2287
- function hasScope(scopes, required) {
2288
- if (!Array.isArray(scopes) || scopes.length === 0) {
2289
- return false;
2290
- }
2291
- if (scopes.includes(required)) {
2292
- return true;
2293
- }
2294
- const [resource, id] = required.split(":");
2295
- if (resource && id) {
2296
- const wildcard = `${resource}:*`;
2297
- if (scopes.includes(wildcard)) {
2298
- return true;
2299
- }
2300
- }
2301
- return false;
2302
- }
2303
- function parseScope(scope) {
2304
- const parts = scope.split(":");
2305
- if (parts.length !== 2) return null;
2306
- return { resource: parts[0], id: parts[1] };
2307
- }
2308
- function canAccessResource(scopes, resourceType, resourceId) {
2309
- const required = `${resourceType}:${resourceId}`;
2310
- return hasScope(scopes, required);
2311
- }
2312
- var init_scopes = __esm({
2313
- "src/security/scopes.ts"() {
2314
- }
2315
- });
2316
-
2317
- // src/security/inline-capsule.ts
2318
- function normalizeInlineCapsule(input) {
2319
- if (!input || typeof input !== "object" || Array.isArray(input)) {
2320
- return null;
2321
- }
2322
- const raw = input;
2323
- const scopes = normalizeStringList(raw.scopes ?? raw.scope);
2324
- return {
2325
- id: normalizeScalar(raw.id),
2326
- actorId: normalizeScalar(raw.actorId),
2327
- intents: normalizeStringList(raw.intents),
2328
- issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
2329
- expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
2330
- realm: normalizeScalar(raw.realm),
2331
- node: normalizeScalar(raw.node),
2332
- scopes,
2333
- raw
2334
- };
2335
- }
2336
- function inlineCapsuleAllowsIntent(capsule, intent) {
2337
- if (!capsule.intents || capsule.intents.length === 0) {
2338
- return false;
2339
- }
2340
- for (const pattern of capsule.intents) {
2341
- if (pattern === "*" || pattern === intent) {
2342
- return true;
2343
- }
2344
- if (pattern.endsWith(".*")) {
2345
- const prefix = pattern.slice(0, -1);
2346
- if (intent.startsWith(prefix)) {
2347
- return true;
2348
- }
2349
- }
2350
- }
2351
- return false;
2352
- }
2353
- function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
2354
- if (capsule.expiresAt === void 0) {
2355
- return false;
2356
- }
2357
- return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
2358
- }
2359
- function resolvePolicyScopes(scopes, context) {
2360
- return scopes.map(
2361
- (scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
2362
- const resolved = resolveTemplateExpression(expression.trim(), context);
2363
- if (resolved === void 0 || resolved === null || resolved === "") {
2364
- throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
2365
- }
2366
- return String(resolved);
2367
- })
2368
- );
2369
- }
2370
- function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
2371
- if (!capsule.scopes || capsule.scopes.length === 0) {
2372
- return false;
2373
- }
2374
- if (mode === "any") {
2375
- return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
2376
- }
2377
- return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
2378
- }
2379
- function resolveTemplateExpression(expression, context) {
2380
- if (expression === "intent") {
2381
- return context.intent;
2382
- }
2383
- if (expression === "actorId") {
2384
- return context.actorId;
2385
- }
2386
- if (expression === "chainId") {
2387
- return context.chainId;
2388
- }
2389
- if (expression === "stepId") {
2390
- return context.stepId;
2391
- }
2392
- if (expression.startsWith("body.")) {
2393
- return getNestedValue(context.body, expression.slice(5));
2394
- }
2395
- return void 0;
2396
- }
2397
- function getNestedValue(value, path2) {
2398
- if (!value || typeof value !== "object") {
2399
- return void 0;
2400
- }
2401
- return path2.split(".").reduce((current, segment) => {
2402
- if (!current || typeof current !== "object") {
2403
- return void 0;
2404
- }
2405
- return current[segment];
2406
- }, value);
2407
- }
2408
- function normalizeScalar(value) {
2409
- if (typeof value === "string") {
2410
- return value;
2411
- }
2412
- if (value instanceof Uint8Array) {
2413
- return Buffer.from(value).toString("hex");
2414
- }
2415
- return void 0;
2416
- }
2417
- function normalizeStringList(value) {
2418
- if (!value) {
2419
- return void 0;
2420
- }
2421
- const list = Array.isArray(value) ? value : [value];
2422
- const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
2423
- return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
2424
- }
2425
- function normalizeTimestamp(value) {
2426
- if (typeof value === "bigint") {
2427
- return value;
2428
- }
2429
- if (typeof value === "number" && Number.isFinite(value)) {
2430
- return BigInt(Math.trunc(value));
2431
- }
2432
- if (typeof value === "string" && value.trim().length > 0) {
2433
- try {
2434
- return BigInt(value);
2435
- } catch {
2436
- return void 0;
2437
- }
2438
- }
2439
- return void 0;
2440
- }
2441
- var init_inline_capsule = __esm({
2442
- "src/security/inline-capsule.ts"() {
2443
- init_scopes();
2444
- }
2445
- });
2446
-
2447
2458
  // src/engine/intent.router.ts
2448
2459
  var intent_router_exports = {};
2449
2460
  __export(intent_router_exports, {
@@ -2517,23 +2528,23 @@ var import_axis_protocol4, import_dto_schema, _IntentRouter, IntentRouter;
2517
2528
  var init_intent_router = __esm({
2518
2529
  "src/engine/intent.router.ts"() {
2519
2530
  import_axis_protocol4 = require("@nextera.one/axis-protocol");
2520
- init_cce_pipeline();
2521
- init_axis_error();
2522
- init_constants();
2523
- init_capsule_policy_decorator();
2524
- init_chain_decorator();
2525
- import_dto_schema = __toESM(require_dto_schema_util());
2526
2531
  init_handler_sensors_decorator();
2527
- init_handler_decorator();
2528
- init_intent_body_decorator();
2529
- init_intent_policy_decorator();
2532
+ init_capsule_policy_decorator();
2530
2533
  init_intent_sensors_decorator();
2531
- init_intent_decorator();
2534
+ init_intent_policy_decorator();
2535
+ init_intent_body_decorator();
2532
2536
  init_observer_decorator();
2537
+ init_handler_decorator();
2538
+ init_intent_decorator();
2539
+ init_chain_decorator();
2540
+ import_dto_schema = __toESM(require_dto_schema_util());
2533
2541
  init_inline_capsule();
2534
- init_axis_sensor();
2535
2542
  init_axis_execution_context();
2543
+ init_axis_sensor();
2536
2544
  init_axis_logger();
2545
+ init_cce_pipeline();
2546
+ init_axis_error();
2547
+ init_constants();
2537
2548
  _IntentRouter = class _IntentRouter {
2538
2549
  constructor(dependencyResolver, observerDispatcher, sensorRegistry) {
2539
2550
  this.logger = createAxisLogger(_IntentRouter.name);
@@ -2569,6 +2580,8 @@ var init_intent_router = __esm({
2569
2580
  this.publicIntents = /* @__PURE__ */ new Set();
2570
2581
  /** Intents flagged as anonymous-session accessible */
2571
2582
  this.anonymousIntents = /* @__PURE__ */ new Set();
2583
+ /** Intents flagged as authorized-session accessible */
2584
+ this.authorizedIntents = /* @__PURE__ */ new Set();
2572
2585
  /** Per-intent rate limit config */
2573
2586
  this.intentRateLimits = /* @__PURE__ */ new Map();
2574
2587
  /** CCE handler registry */
@@ -2995,6 +3008,18 @@ var init_intent_router = __esm({
2995
3008
  if (isAnonMethod || isAnonClass) {
2996
3009
  this.anonymousIntents.add(intent);
2997
3010
  }
3011
+ const isAuthorizedMethod = Reflect.getMetadata(
3012
+ AXIS_AUTHORIZED_KEY,
3013
+ proto,
3014
+ methodName
3015
+ );
3016
+ const isAuthorizedClass = Reflect.getMetadata(
3017
+ AXIS_AUTHORIZED_KEY,
3018
+ proto.constructor
3019
+ );
3020
+ if (isAuthorizedMethod || isAuthorizedClass) {
3021
+ this.authorizedIntents.add(intent);
3022
+ }
2998
3023
  const rateLimit = Reflect.getMetadata(
2999
3024
  AXIS_RATE_LIMIT_KEY,
3000
3025
  proto,
@@ -3020,6 +3045,9 @@ var init_intent_router = __esm({
3020
3045
  isAnonymous(intent) {
3021
3046
  return this.anonymousIntents.has(intent);
3022
3047
  }
3048
+ isAuthorized(intent) {
3049
+ return this.authorizedIntents.has(intent);
3050
+ }
3023
3051
  getRateLimit(intent) {
3024
3052
  return this.intentRateLimits.get(intent);
3025
3053
  }
@@ -10528,6 +10556,7 @@ __export(index_exports, {
10528
10556
  ATS1_HDR: () => ATS1_HDR,
10529
10557
  ATS1_SCHEMA: () => ATS1_SCHEMA,
10530
10558
  AXIS_ANONYMOUS_KEY: () => AXIS_ANONYMOUS_KEY,
10559
+ AXIS_AUTHORIZED_KEY: () => AXIS_AUTHORIZED_KEY,
10531
10560
  AXIS_EXECUTION_CONTEXT_KEY: () => AXIS_EXECUTION_CONTEXT_KEY,
10532
10561
  AXIS_MAGIC: () => import_axis_protocol.AXIS_MAGIC,
10533
10562
  AXIS_META_KEY: () => AXIS_META_KEY,
@@ -10541,6 +10570,7 @@ __export(index_exports, {
10541
10570
  Ats1Codec: () => ats1_exports,
10542
10571
  Axis: () => Axis,
10543
10572
  AxisAnonymous: () => AxisAnonymous,
10573
+ AxisAuthorized: () => AxisAuthorized,
10544
10574
  AxisChainExecutor: () => AxisChainExecutor,
10545
10575
  AxisError: () => AxisError,
10546
10576
  AxisFrameZ: () => AxisFrameZ,