@nextera.one/axis-server-sdk 1.3.0 → 1.5.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/dist/index.mjs CHANGED
@@ -75,6 +75,22 @@ function IntentSensors(sensors) {
75
75
  };
76
76
  }
77
77
 
78
+ // src/decorators/handler-sensors.decorator.ts
79
+ import "reflect-metadata";
80
+ var HANDLER_SENSORS_KEY = "axis:handler:sensors";
81
+ function HandlerSensors(sensors) {
82
+ return (target) => {
83
+ Reflect.defineMetadata(HANDLER_SENSORS_KEY, sensors, target);
84
+ };
85
+ }
86
+
87
+ // src/decorators/sensor.decorator.ts
88
+ import { SetMetadata as SetMetadata2 } from "@nestjs/common";
89
+ var SENSOR_METADATA_KEY = "axis:sensor";
90
+ function Sensor(options) {
91
+ return SetMetadata2(SENSOR_METADATA_KEY, options ?? true);
92
+ }
93
+
78
94
  // src/decorators/tlv-field.decorator.ts
79
95
  import "reflect-metadata";
80
96
  var TLV_FIELDS_KEY = "axis:tlv:fields";
@@ -455,6 +471,7 @@ var IntentRouter = class {
455
471
  );
456
472
  const prefix = handlerMeta?.intent || instance.name;
457
473
  const routes = Reflect.getMetadata(INTENT_ROUTES_KEY, instance.constructor) || [];
474
+ const handlerSensors = Reflect.getMetadata(HANDLER_SENSORS_KEY, instance.constructor) || [];
458
475
  for (const route of routes) {
459
476
  const intentName = route.absolute ? route.action : `${prefix}.${route.action}`;
460
477
  const fn = instance[route.methodName].bind(instance);
@@ -463,7 +480,12 @@ var IntentRouter = class {
463
480
  } else {
464
481
  this.register(intentName, fn);
465
482
  }
466
- this.registerIntentMeta(intentName, Object.getPrototypeOf(instance), String(route.methodName));
483
+ this.registerIntentMeta(
484
+ intentName,
485
+ Object.getPrototypeOf(instance),
486
+ String(route.methodName),
487
+ handlerSensors
488
+ );
467
489
  }
468
490
  const proto = Object.getPrototypeOf(instance);
469
491
  for (const key of Object.getOwnPropertyNames(proto)) {
@@ -472,7 +494,7 @@ var IntentRouter = class {
472
494
  if (!this.handlers.has(meta.intent)) {
473
495
  this.register(meta.intent, instance[key].bind(instance));
474
496
  }
475
- this.registerIntentMeta(meta.intent, proto, key);
497
+ this.registerIntentMeta(meta.intent, proto, key, handlerSensors);
476
498
  }
477
499
  }
478
500
  /**
@@ -608,14 +630,22 @@ var IntentRouter = class {
608
630
  this.logger.warn(`${intent} failed in ${ms}ms - ${error}`);
609
631
  }
610
632
  }
611
- registerIntentMeta(intent, proto, methodName) {
633
+ registerIntentMeta(intent, proto, methodName, handlerSensors) {
612
634
  const decoder = Reflect.getMetadata(INTENT_BODY_KEY, proto, methodName);
613
635
  if (decoder) {
614
636
  this.intentDecoders.set(intent, decoder);
615
637
  }
616
- const sensors = Reflect.getMetadata(INTENT_SENSORS_KEY, proto, methodName);
617
- if (sensors && Array.isArray(sensors) && sensors.length > 0) {
618
- this.intentSensors.set(intent, sensors);
638
+ const intentSensors = Reflect.getMetadata(
639
+ INTENT_SENSORS_KEY,
640
+ proto,
641
+ methodName
642
+ );
643
+ const combined = [
644
+ ...handlerSensors || [],
645
+ ...Array.isArray(intentSensors) ? intentSensors : []
646
+ ];
647
+ if (combined.length > 0) {
648
+ this.intentSensors.set(intent, combined);
619
649
  }
620
650
  const meta = Reflect.getMetadata(INTENT_METADATA_KEY, proto, methodName);
621
651
  if (meta) {
@@ -718,6 +748,182 @@ IntentRouter = __decorateClass([
718
748
  __decorateParam(0, Optional())
719
749
  ], IntentRouter);
720
750
 
751
+ // src/engine/sensor-bands.ts
752
+ var BAND = {
753
+ /** Pre-decode: raw byte validation, geo, budget, magic */
754
+ WIRE: 0,
755
+ /** Post-decode: identity resolution, capsule, proof */
756
+ IDENTITY: 40,
757
+ /** Post-decode: authorization, signature, rate limiting */
758
+ POLICY: 90,
759
+ /** Post-decode: content validation, TLV, schema, files */
760
+ CONTENT: 140,
761
+ /** Post-decode: business logic sensors, streams, WS */
762
+ BUSINESS: 200,
763
+ /** Post-decode: audit, logging (always last) */
764
+ AUDIT: 900
765
+ };
766
+ var PRE_DECODE_BOUNDARY = 40;
767
+
768
+ // src/engine/observation/stable-json.ts
769
+ function normalize(value) {
770
+ if (Array.isArray(value)) {
771
+ return value.map((item) => normalize(item));
772
+ }
773
+ if (value && typeof value === "object") {
774
+ const entries = Object.entries(value).filter(([, nested]) => nested !== void 0).sort(([left], [right]) => left.localeCompare(right));
775
+ const normalized = {};
776
+ for (const [key, nested] of entries) {
777
+ normalized[key] = normalize(nested);
778
+ }
779
+ return normalized;
780
+ }
781
+ return value;
782
+ }
783
+ function stableJsonStringify(value) {
784
+ return JSON.stringify(normalize(value));
785
+ }
786
+
787
+ // src/engine/observation/observation-queue.codec.ts
788
+ function buildQueueMessage(observation, sourceNodeId, previous, lastError) {
789
+ const now = Date.now();
790
+ return {
791
+ v: 1,
792
+ observation,
793
+ attempts: previous ? previous.attempts + 1 : 0,
794
+ firstEnqueuedAt: previous?.firstEnqueuedAt ?? now,
795
+ lastEnqueuedAt: now,
796
+ sourceNodeId,
797
+ lastError
798
+ };
799
+ }
800
+ function encodeQueueMessage(message) {
801
+ return JSON.stringify(message);
802
+ }
803
+ function decodeQueueMessage(raw) {
804
+ try {
805
+ const parsed = JSON.parse(raw);
806
+ if (!parsed || parsed.v !== 1 || !parsed.observation?.id) {
807
+ return null;
808
+ }
809
+ return parsed;
810
+ } catch {
811
+ return null;
812
+ }
813
+ }
814
+ function parseStreamEntries(raw) {
815
+ if (!Array.isArray(raw)) {
816
+ return [];
817
+ }
818
+ const entries = [];
819
+ for (const streamRow of raw) {
820
+ if (!Array.isArray(streamRow) || streamRow.length < 2) {
821
+ continue;
822
+ }
823
+ const messageRows = streamRow[1];
824
+ if (!Array.isArray(messageRows)) {
825
+ continue;
826
+ }
827
+ for (const row of messageRows) {
828
+ if (!Array.isArray(row) || row.length < 2) {
829
+ continue;
830
+ }
831
+ const id = String(row[0]);
832
+ const fields = Array.isArray(row[1]) ? row[1] : [];
833
+ const fieldMap = fieldsToMap(fields);
834
+ const payload = fieldMap.get("payload");
835
+ if (!payload) {
836
+ continue;
837
+ }
838
+ const message = decodeQueueMessage(payload);
839
+ if (!message) {
840
+ continue;
841
+ }
842
+ entries.push({ id, message });
843
+ }
844
+ }
845
+ return entries;
846
+ }
847
+ function parseAutoClaimEntries(raw) {
848
+ if (!Array.isArray(raw) || raw.length < 2) {
849
+ return [];
850
+ }
851
+ const rows = Array.isArray(raw[1]) ? raw[1] : [];
852
+ return parseStreamEntries([["stream", rows]]);
853
+ }
854
+ function fieldsToMap(fields) {
855
+ const map3 = /* @__PURE__ */ new Map();
856
+ for (let i = 0; i < fields.length; i += 2) {
857
+ const key = fields[i];
858
+ const value = fields[i + 1];
859
+ if (key !== void 0 && value !== void 0) {
860
+ map3.set(String(key), String(value));
861
+ }
862
+ }
863
+ return map3;
864
+ }
865
+
866
+ // src/engine/observation/observation-hash.ts
867
+ import { createHash } from "crypto";
868
+ function canonicalizeObservation(obs) {
869
+ const obj = {
870
+ id: obs.id,
871
+ startMs: obs.startMs,
872
+ endMs: obs.endMs,
873
+ transport: obs.transport,
874
+ ip: obs.ip,
875
+ intent: obs.intent,
876
+ actorId: obs.actorId,
877
+ capsuleId: obs.capsuleId,
878
+ decision: obs.decision,
879
+ resultCode: obs.resultCode,
880
+ statusCode: obs.statusCode,
881
+ durationMs: obs.durationMs,
882
+ stages: obs.stages.map((s) => ({
883
+ name: s.name,
884
+ status: s.status,
885
+ startMs: s.startMs,
886
+ endMs: s.endMs,
887
+ durationMs: s.durationMs,
888
+ reason: s.reason,
889
+ code: s.code
890
+ })),
891
+ sensors: obs.sensors.map((s) => ({
892
+ name: s.name,
893
+ allowed: s.allowed,
894
+ riskScore: s.riskScore,
895
+ durationMs: s.durationMs,
896
+ reasons: s.reasons,
897
+ code: s.code
898
+ }))
899
+ };
900
+ return stableJsonStringify(obj);
901
+ }
902
+ function hashObservation(obs) {
903
+ const canonical = canonicalizeObservation(obs);
904
+ return createHash("sha256").update(canonical).digest("hex");
905
+ }
906
+ function buildUnsignedWitness(obs) {
907
+ if (!obs.decision || !obs.endMs) {
908
+ return null;
909
+ }
910
+ return {
911
+ v: 1,
912
+ observationId: obs.id,
913
+ payloadHash: hashObservation(obs),
914
+ sealedAt: Date.now(),
915
+ summary: {
916
+ intent: obs.intent,
917
+ actorId: obs.actorId,
918
+ decision: obs.decision,
919
+ statusCode: obs.statusCode,
920
+ durationMs: obs.durationMs,
921
+ sensorCount: obs.sensors.length,
922
+ stageCount: obs.stages.length
923
+ }
924
+ };
925
+ }
926
+
721
927
  // src/core/constants.ts
722
928
  import {
723
929
  AXIS_MAGIC,
@@ -784,6 +990,51 @@ import {
784
990
  ERR_CONTRACT_VIOLATION
785
991
  } from "@nextera.one/axis-protocol";
786
992
 
993
+ // src/engine/observation/response-observer.ts
994
+ var SENSITIVE_RESPONSE_TAGS = [4, 5, 6];
995
+ function verifyResponse(ctx, response) {
996
+ if (!response.effect || typeof response.effect !== "string") {
997
+ return {
998
+ passed: false,
999
+ code: "OBSERVER_INVALID_EFFECT",
1000
+ reason: "Response effect is missing or invalid"
1001
+ };
1002
+ }
1003
+ if (response.ok && (!response.body || response.body.length === 0)) {
1004
+ return {
1005
+ passed: false,
1006
+ code: "OBSERVER_EMPTY_BODY",
1007
+ reason: "Successful response must contain a body"
1008
+ };
1009
+ }
1010
+ if (response.body && response.body.length > MAX_BODY_LEN) {
1011
+ return {
1012
+ passed: false,
1013
+ code: "OBSERVER_BODY_OVERFLOW",
1014
+ reason: `Response body exceeds ${MAX_BODY_LEN} bytes`
1015
+ };
1016
+ }
1017
+ if (response.headers) {
1018
+ for (const tag of SENSITIVE_RESPONSE_TAGS) {
1019
+ if (response.headers.has(tag)) {
1020
+ return {
1021
+ passed: false,
1022
+ code: "OBSERVER_DATA_LEAK",
1023
+ reason: `Response must not contain sensitive TLV tag ${tag}`
1024
+ };
1025
+ }
1026
+ }
1027
+ }
1028
+ if (response.effect.includes("Error:") || response.effect.includes("stack") || response.effect.includes("at /")) {
1029
+ return {
1030
+ passed: false,
1031
+ code: "OBSERVER_INFO_LEAK",
1032
+ reason: "Response effect may contain internal error details"
1033
+ };
1034
+ }
1035
+ return { passed: true };
1036
+ }
1037
+
787
1038
  // src/core/varint.ts
788
1039
  import { encodeVarint, decodeVarint, varintLength } from "@nextera.one/axis-protocol";
789
1040
 
@@ -1059,7 +1310,7 @@ __export(ats1_exports, {
1059
1310
  tlvsToMap: () => tlvsToMap,
1060
1311
  validateTLVsAgainstSchema: () => validateTLVsAgainstSchema
1061
1312
  });
1062
- import { createHash as createHash2 } from "crypto";
1313
+ import { createHash as createHash3 } from "crypto";
1063
1314
  var DEFAULT_LIMITS = {
1064
1315
  maxVarintBytes: 10,
1065
1316
  maxTlvCount: 512,
@@ -1109,7 +1360,7 @@ function decodeU64BE(buf) {
1109
1360
  return buf.readBigUInt64BE(0);
1110
1361
  }
1111
1362
  function sha2562(data) {
1112
- return createHash2("sha256").update(data).digest();
1363
+ return createHash3("sha256").update(data).digest();
1113
1364
  }
1114
1365
  function encodeTLV(tag, value) {
1115
1366
  if (!Number.isInteger(tag) || tag <= 0)
@@ -2272,9 +2523,9 @@ function isAdminOpcode(op) {
2272
2523
  }
2273
2524
 
2274
2525
  // src/core/receipt.ts
2275
- import { createHash as createHash3 } from "crypto";
2526
+ import { createHash as createHash4 } from "crypto";
2276
2527
  function buildReceiptHash(prevHash, pid, actorId, intent, effect, ts) {
2277
- const h = createHash3("sha256");
2528
+ const h = createHash4("sha256");
2278
2529
  if (prevHash) h.update(prevHash);
2279
2530
  h.update(pid);
2280
2531
  h.update(Buffer.from(actorId, "utf8"));
@@ -2679,92 +2930,54 @@ var DiskUploadFileStore = class {
2679
2930
  }
2680
2931
  };
2681
2932
 
2682
- // src/core/index.ts
2683
- var core_exports = {};
2684
- __export(core_exports, {
2685
- AXIS_MAGIC: () => AXIS_MAGIC,
2686
- AXIS_VERSION: () => AXIS_VERSION,
2687
- AxisError: () => AxisError,
2688
- AxisFrameZ: () => AxisFrameZ,
2689
- BodyProfile: () => BodyProfile,
2690
- ERR_BAD_SIGNATURE: () => ERR_BAD_SIGNATURE,
2691
- ERR_CONTRACT_VIOLATION: () => ERR_CONTRACT_VIOLATION,
2692
- ERR_INVALID_PACKET: () => ERR_INVALID_PACKET,
2693
- ERR_REPLAY_DETECTED: () => ERR_REPLAY_DETECTED,
2694
- FLAG_BODY_TLV: () => FLAG_BODY_TLV,
2695
- FLAG_CHAIN_REQ: () => FLAG_CHAIN_REQ,
2696
- FLAG_HAS_WITNESS: () => FLAG_HAS_WITNESS,
2697
- MAX_BODY_LEN: () => MAX_BODY_LEN,
2698
- MAX_FRAME_LEN: () => MAX_FRAME_LEN,
2699
- MAX_HDR_LEN: () => MAX_HDR_LEN,
2700
- MAX_SIG_LEN: () => MAX_SIG_LEN,
2701
- NCERT_ALG: () => NCERT_ALG,
2702
- NCERT_EXP: () => NCERT_EXP,
2703
- NCERT_ISSUER_KID: () => NCERT_ISSUER_KID,
2704
- NCERT_KID: () => NCERT_KID,
2705
- NCERT_NBF: () => NCERT_NBF,
2706
- NCERT_NODE_ID: () => NCERT_NODE_ID,
2707
- NCERT_PAYLOAD: () => NCERT_PAYLOAD,
2708
- NCERT_PUB: () => NCERT_PUB,
2709
- NCERT_SCOPE: () => NCERT_SCOPE,
2710
- NCERT_SIG: () => NCERT_SIG,
2711
- PROOF_CAPSULE: () => PROOF_CAPSULE,
2712
- PROOF_JWT: () => PROOF_JWT,
2713
- PROOF_LOOM: () => PROOF_LOOM,
2714
- PROOF_MTLS: () => PROOF_MTLS,
2715
- PROOF_NONE: () => PROOF_NONE,
2716
- PROOF_WITNESS: () => PROOF_WITNESS,
2717
- ProofType: () => ProofType,
2718
- TLV: () => TLV,
2719
- TLV_ACTOR_ID: () => TLV_ACTOR_ID,
2720
- TLV_AUD: () => TLV_AUD,
2721
- TLV_BODY_ARR: () => TLV_BODY_ARR,
2722
- TLV_BODY_OBJ: () => TLV_BODY_OBJ,
2723
- TLV_CAPSULE: () => TLV_CAPSULE,
2724
- TLV_EFFECT: () => TLV_EFFECT,
2725
- TLV_ERROR_CODE: () => TLV_ERROR_CODE,
2726
- TLV_ERROR_MSG: () => TLV_ERROR_MSG,
2727
- TLV_INDEX: () => TLV_INDEX,
2728
- TLV_INTENT: () => TLV_INTENT,
2729
- TLV_KID: () => TLV_KID,
2730
- TLV_LOOM_PRESENCE_ID: () => TLV_LOOM_PRESENCE_ID,
2731
- TLV_LOOM_THREAD_HASH: () => TLV_LOOM_THREAD_HASH,
2732
- TLV_LOOM_WRIT: () => TLV_LOOM_WRIT,
2733
- TLV_NODE: () => TLV_NODE,
2734
- TLV_NODE_CERT_HASH: () => TLV_NODE_CERT_HASH,
2735
- TLV_NODE_KID: () => TLV_NODE_KID,
2736
- TLV_NONCE: () => TLV_NONCE,
2737
- TLV_OFFSET: () => TLV_OFFSET,
2738
- TLV_OK: () => TLV_OK,
2739
- TLV_PID: () => TLV_PID,
2740
- TLV_PREV_HASH: () => TLV_PREV_HASH,
2741
- TLV_PROOF_REF: () => TLV_PROOF_REF,
2742
- TLV_PROOF_TYPE: () => TLV_PROOF_TYPE,
2743
- TLV_REALM: () => TLV_REALM,
2744
- TLV_RECEIPT_HASH: () => TLV_RECEIPT_HASH,
2745
- TLV_RID: () => TLV_RID,
2746
- TLV_SHA256_CHUNK: () => TLV_SHA256_CHUNK,
2747
- TLV_TRACE_ID: () => TLV_TRACE_ID,
2748
- TLV_TS: () => TLV_TS,
2749
- TLV_UPLOAD_ID: () => TLV_UPLOAD_ID,
2750
- computeReceiptHash: () => computeReceiptHash,
2751
- computeSignaturePayload: () => computeSignaturePayload,
2752
- decodeArray: () => decodeArray,
2753
- decodeFrame: () => decodeFrame,
2754
- decodeObject: () => decodeObject,
2755
- decodeTLVs: () => decodeTLVs,
2756
- decodeTLVsList: () => decodeTLVsList,
2757
- decodeVarint: () => decodeVarint,
2758
- encodeFrame: () => encodeFrame,
2759
- encodeTLVs: () => encodeTLVs,
2760
- encodeVarint: () => encodeVarint,
2761
- generateEd25519KeyPair: () => generateEd25519KeyPair,
2762
- getSignTarget: () => getSignTarget,
2763
- sha256: () => sha256,
2764
- signFrame: () => signFrame,
2765
- varintLength: () => varintLength,
2766
- verifyFrameSignature: () => verifyFrameSignature
2767
- });
2933
+ // src/decorators/axis-request.decorator.ts
2934
+ import { createParamDecorator } from "@nestjs/common";
2935
+ function resolveIp(req) {
2936
+ return req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress || void 0;
2937
+ }
2938
+ var AxisRaw = createParamDecorator(
2939
+ (_data, ctx) => {
2940
+ const req = ctx.switchToHttp().getRequest();
2941
+ return req.body;
2942
+ }
2943
+ );
2944
+ var AxisIp = createParamDecorator(
2945
+ (_data, ctx) => {
2946
+ const req = ctx.switchToHttp().getRequest();
2947
+ return resolveIp(req);
2948
+ }
2949
+ );
2950
+ var AxisContext = createParamDecorator(
2951
+ (_data, ctx) => {
2952
+ const req = ctx.switchToHttp().getRequest();
2953
+ const axisData = req.axis || {};
2954
+ return {
2955
+ raw: req.body,
2956
+ ip: resolveIp(req),
2957
+ preDecodeInput: axisData.preDecodeInput,
2958
+ frameBytesCount: axisData.frameBytesCount || 0
2959
+ };
2960
+ }
2961
+ );
2962
+ var AxisDemoPubkey = createParamDecorator(
2963
+ (_data, ctx) => {
2964
+ if (process.env.NODE_ENV !== "development") return void 0;
2965
+ const req = ctx.switchToHttp().getRequest();
2966
+ return req.headers["x-demo-pubkey"];
2967
+ }
2968
+ );
2969
+ var AxisFrame3 = createParamDecorator(
2970
+ (_data, ctx) => {
2971
+ const req = ctx.switchToHttp().getRequest();
2972
+ const decoded = req.axisDecoded;
2973
+ if (!decoded) {
2974
+ throw new Error(
2975
+ "@AxisFrame() requires AxisDecodeInterceptor on the route. Add @UseInterceptors(AxisDecodeInterceptor) to use this decorator."
2976
+ );
2977
+ }
2978
+ return decoded;
2979
+ }
2980
+ );
2768
2981
 
2769
2982
  // src/core/axis-error.ts
2770
2983
  var AxisError = class extends Error {
@@ -2777,341 +2990,240 @@ var AxisError = class extends Error {
2777
2990
  }
2778
2991
  };
2779
2992
 
2780
- // src/crypto/index.ts
2781
- var crypto_exports = {};
2782
- __export(crypto_exports, {
2783
- ProofVerificationService: () => ProofVerificationService,
2784
- b64urlDecode: () => b64urlDecode,
2785
- b64urlDecodeString: () => b64urlDecodeString,
2786
- b64urlEncode: () => b64urlEncode,
2787
- b64urlEncodeString: () => b64urlEncodeString,
2788
- canonicalJson: () => canonicalJson,
2789
- canonicalJsonExcluding: () => canonicalJsonExcluding
2790
- });
2791
-
2792
- // src/crypto/proof-verification.service.ts
2993
+ // src/engine/handler-discovery.service.ts
2793
2994
  import { Injectable as Injectable4, Logger as Logger3 } from "@nestjs/common";
2794
- import * as crypto3 from "crypto";
2795
- import * as nacl from "tweetnacl";
2796
- var ProofVerificationService = class {
2797
- constructor() {
2798
- this.logger = new Logger3(ProofVerificationService.name);
2799
- // Cache of registered device public keys (deviceId -> pubKey)
2800
- this.deviceKeys = /* @__PURE__ */ new Map();
2801
- // Cache of trusted mTLS certificate fingerprints
2802
- this.trustedCerts = /* @__PURE__ */ new Map();
2995
+ var HandlerDiscoveryService = class {
2996
+ constructor(discovery, scanner, router) {
2997
+ this.discovery = discovery;
2998
+ this.scanner = scanner;
2999
+ this.router = router;
3000
+ this.logger = new Logger3(HandlerDiscoveryService.name);
2803
3001
  }
2804
- /**
2805
- * Verifies an authentication proof based on its type.
2806
- *
2807
- * **Supported Types:**
2808
- * - 1 (CAPSULE): Delegated to `verifyCapsuleProof`
2809
- * - 2 (JWT): Verified by `verifyJWTProof`
2810
- * - 3 (MTLS_ID): Verified by `verifyMTLSProof`
2811
- * - 4 (DEVICE_SE): Verified by `verifyDeviceSEProof`
2812
- *
2813
- * @param {ProofType} proofType - The numeric AXIS proof type
2814
- * @param {Uint8Array} proofRef - The binary reference or token for the proof
2815
- * @param {Object} context - Additional metadata required for specific proof types
2816
- * @param {Uint8Array} [context.signTarget] - The canonical bytes that were signed (for Ed25519)
2817
- * @param {Uint8Array} [context.signature] - The signature to verify (for Ed25519)
2818
- * @param {MTLSContext} [context.mtls] - mTLS certificate data
2819
- * @param {DeviceSEContext} [context.deviceSE] - Device Secure Element information
2820
- * @returns {Promise<ProofVerificationResult>} The outcome of the verification
2821
- */
2822
- async verifyProof(proofType, proofRef, context) {
2823
- switch (proofType) {
2824
- case 1:
2825
- return this.verifyCapsuleProof(proofRef);
2826
- case 2:
2827
- return this.verifyJWTProof(proofRef);
2828
- case 3:
2829
- return this.verifyMTLSProof(context.mtls);
2830
- case 4:
2831
- return this.verifyDeviceSEProof(
2832
- context.signTarget,
2833
- context.signature,
2834
- context.deviceSE
3002
+ onModuleInit() {
3003
+ const providers = this.discovery.getProviders();
3004
+ let totalIntents = 0;
3005
+ for (const wrapper of providers) {
3006
+ const { instance, metatype } = wrapper;
3007
+ if (!instance || !metatype) continue;
3008
+ const handlerMeta = Reflect.getMetadata(HANDLER_METADATA_KEY, metatype);
3009
+ if (!handlerMeta) continue;
3010
+ const handlerName = handlerMeta.intent || metatype.name;
3011
+ const proto = Object.getPrototypeOf(instance);
3012
+ const methods = this.scanner.getAllMethodNames(proto);
3013
+ let registered = 0;
3014
+ const handlerSensors = Reflect.getMetadata(HANDLER_SENSORS_KEY, metatype) || [];
3015
+ for (const methodName of methods) {
3016
+ const meta = Reflect.getMetadata(
3017
+ INTENT_METADATA_KEY,
3018
+ proto,
3019
+ methodName
2835
3020
  );
2836
- default:
2837
- return { valid: false, error: `Unknown proof type: ${proofType}` };
3021
+ if (!meta?.intent) continue;
3022
+ if (!this.router.has(meta.intent)) {
3023
+ this.router.register(
3024
+ meta.intent,
3025
+ instance[methodName].bind(instance)
3026
+ );
3027
+ registered++;
3028
+ totalIntents++;
3029
+ }
3030
+ this.router.registerIntentMeta(
3031
+ meta.intent,
3032
+ proto,
3033
+ methodName,
3034
+ handlerSensors
3035
+ );
3036
+ }
3037
+ if (registered > 0) {
3038
+ this.logger.log(
3039
+ `Auto-registered ${registered} intents from ${handlerName}`
3040
+ );
3041
+ }
2838
3042
  }
3043
+ this.logger.log(
3044
+ `Handler discovery complete: ${totalIntents} intents auto-registered`
3045
+ );
2839
3046
  }
2840
- /**
2841
- * Verify CAPSULE proof (delegated to CapsuleService)
2842
- */
2843
- async verifyCapsuleProof(proofRef) {
2844
- const capsuleId = new TextDecoder().decode(proofRef);
2845
- return {
2846
- valid: true,
2847
- metadata: { capsuleId, requiresCapsuleValidation: true }
2848
- };
3047
+ };
3048
+ HandlerDiscoveryService = __decorateClass([
3049
+ Injectable4()
3050
+ ], HandlerDiscoveryService);
3051
+
3052
+ // src/engine/sensor-discovery.service.ts
3053
+ import { Injectable as Injectable5, Logger as Logger4 } from "@nestjs/common";
3054
+ var SensorDiscoveryService = class {
3055
+ constructor(discovery, reflector, registry) {
3056
+ this.discovery = discovery;
3057
+ this.reflector = reflector;
3058
+ this.registry = registry;
3059
+ this.logger = new Logger4(SensorDiscoveryService.name);
2849
3060
  }
2850
- /**
2851
- * Verifies a JSON Web Token (JWT) proof.
2852
- *
2853
- * **Validation Logic:**
2854
- * 1. Decodes the token string.
2855
- * 2. Checks for valid 3-part JWT structure.
2856
- * 3. Validates `exp` (expiration) and `nbf` (not before) claims.
2857
- * 4. Extracts `actor_id` or `sub` as the identity.
2858
- *
2859
- * @param {Uint8Array} proofRef - Binary representation of the JWT string
2860
- * @returns {Promise<ProofVerificationResult>} Result including the actor identifier
2861
- */
2862
- async verifyJWTProof(proofRef) {
2863
- try {
2864
- const token = new TextDecoder().decode(proofRef);
2865
- const parts = token.split(".");
2866
- if (parts.length !== 3) {
2867
- return { valid: false, error: "Invalid JWT format" };
2868
- }
2869
- const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
2870
- const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
2871
- if (payload.exp && Date.now() / 1e3 > payload.exp) {
2872
- return { valid: false, error: "JWT expired" };
3061
+ onApplicationBootstrap() {
3062
+ const providers = this.discovery.getProviders();
3063
+ let count = 0;
3064
+ for (const wrapper of providers) {
3065
+ const { instance } = wrapper;
3066
+ if (!instance || !instance.constructor) continue;
3067
+ const meta = this.reflector.get(
3068
+ SENSOR_METADATA_KEY,
3069
+ instance.constructor
3070
+ );
3071
+ if (!meta) continue;
3072
+ const sensor = instance;
3073
+ if (!sensor.name || sensor.order === void 0) {
3074
+ this.logger.warn(
3075
+ `@Sensor() on ${instance.constructor.name} missing name or order \u2014 skipped`
3076
+ );
3077
+ continue;
2873
3078
  }
2874
- if (payload.nbf && Date.now() / 1e3 < payload.nbf) {
2875
- return { valid: false, error: "JWT not yet valid" };
3079
+ if (!sensor.phase) {
3080
+ const decoratorPhase = meta !== true ? meta.phase : void 0;
3081
+ sensor.phase = decoratorPhase ?? (sensor.order < PRE_DECODE_BOUNDARY ? "PRE_DECODE" : "POST_DECODE");
2876
3082
  }
2877
- return {
2878
- valid: true,
2879
- actorId: payload.sub || payload.actor_id,
2880
- metadata: { iss: payload.iss, scope: payload.scope }
2881
- };
2882
- } catch (e) {
2883
- const message = e instanceof Error ? e.message : "Unknown error";
2884
- return { valid: false, error: `JWT parse error: ${message}` };
3083
+ this.registry.register(sensor);
3084
+ count++;
2885
3085
  }
3086
+ this.logger.log(`Auto-registered ${count} sensors via @Sensor()`);
3087
+ }
3088
+ };
3089
+ SensorDiscoveryService = __decorateClass([
3090
+ Injectable5()
3091
+ ], SensorDiscoveryService);
3092
+
3093
+ // src/engine/registry/sensor.registry.ts
3094
+ import { Injectable as Injectable6, Logger as Logger5 } from "@nestjs/common";
3095
+ var SensorRegistry = class {
3096
+ constructor(configService) {
3097
+ this.configService = configService;
3098
+ this.sensors = [];
3099
+ this.logger = new Logger5(SensorRegistry.name);
2886
3100
  }
2887
3101
  /**
2888
- * Verify mTLS client certificate proof
3102
+ * Registers a new sensor in the registry.
3103
+ *
3104
+ * Validates that:
3105
+ * - AxisSensor has a unique name
3106
+ * - AxisSensor has an order field
3107
+ * - Pre-decode sensors have order < 40
3108
+ * - Post-decode sensors have order >= 40
3109
+ *
3110
+ * @param {AxisSensor} sensor - The sensor instance to register
3111
+ * @throws Error if validation fails
2889
3112
  */
2890
- async verifyMTLSProof(mtls) {
2891
- if (!mtls) {
2892
- return { valid: false, error: "No mTLS context provided" };
3113
+ register(sensor) {
3114
+ if (!sensor.name) {
3115
+ throw new Error("AxisSensor must have a name");
2893
3116
  }
2894
- if (!mtls.verified) {
2895
- return { valid: false, error: "mTLS not verified by TLS terminator" };
3117
+ const enabledSensorsStr = this.configService.get("ENABLED_SENSORS");
3118
+ const disabledSensorsStr = this.configService.get("DISABLED_SENSORS");
3119
+ const enabledSensors = enabledSensorsStr ? enabledSensorsStr.split(",").map((s) => s.trim()) : null;
3120
+ const disabledSensors = disabledSensorsStr ? disabledSensorsStr.split(",").map((s) => s.trim()) : [];
3121
+ if (enabledSensors && !enabledSensors.includes(sensor.name)) {
3122
+ this.logger.log(`Skipping disabled sensor (not in ENABLED_SENSORS): ${sensor.name}`);
3123
+ return;
2896
3124
  }
2897
- if (mtls.clientCertFingerprint) {
2898
- const trusted = this.trustedCerts.get(mtls.clientCertFingerprint);
2899
- if (trusted) {
2900
- return {
2901
- valid: true,
2902
- actorId: trusted.actorId,
2903
- metadata: {
2904
- fingerprint: mtls.clientCertFingerprint,
2905
- subject: mtls.clientCertSubject
2906
- }
2907
- };
2908
- }
3125
+ if (disabledSensors.includes(sensor.name)) {
3126
+ this.logger.log(`Skipping disabled sensor (in DISABLED_SENSORS): ${sensor.name}`);
3127
+ return;
2909
3128
  }
2910
- if (mtls.clientCertSubject) {
2911
- const cnMatch = mtls.clientCertSubject.match(/CN=([^,]+)/);
2912
- if (cnMatch) {
2913
- return {
2914
- valid: true,
2915
- actorId: cnMatch[1],
2916
- metadata: {
2917
- subject: mtls.clientCertSubject,
2918
- issuer: mtls.clientCertIssuer
2919
- }
2920
- };
2921
- }
3129
+ if (sensor.order === void 0) {
3130
+ throw new Error(`AxisSensor "${sensor.name}" must have an order field`);
2922
3131
  }
2923
- return { valid: false, error: "Could not extract actor from certificate" };
3132
+ const isPreDecodeSensor = this.isPreDecodeSensor(sensor);
3133
+ const isPostDecodeSensor = this.isPostDecodeSensor(sensor);
3134
+ if (isPreDecodeSensor && sensor.order >= 40) {
3135
+ this.logger.warn(
3136
+ `AxisSensor "${sensor.name}" is marked as PRE_DECODE but has order ${sensor.order} (should be < 40)`
3137
+ );
3138
+ }
3139
+ if (isPostDecodeSensor && sensor.order < 40) {
3140
+ this.logger.warn(
3141
+ `AxisSensor "${sensor.name}" is marked as POST_DECODE but has order ${sensor.order} (should be >= 40)`
3142
+ );
3143
+ }
3144
+ this.sensors.push(sensor);
3145
+ const phaseLabel = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase || "UNKNOWN";
3146
+ this.logger.debug(
3147
+ `Registered sensor: ${sensor.name} (order: ${sensor.order}, phase: ${phaseLabel})`
3148
+ );
2924
3149
  }
2925
3150
  /**
2926
- * Verify Device Secure Element signature
3151
+ * Returns all registered sensors, sorted by their execution order.
3152
+ *
3153
+ * @returns {AxisSensor[]} A sorted array of sensors
2927
3154
  */
2928
- async verifyDeviceSEProof(signTarget, signature, deviceSE) {
2929
- if (!deviceSE || !signTarget || !signature) {
2930
- return { valid: false, error: "Missing Device SE context" };
2931
- }
2932
- let publicKey = deviceSE.publicKey;
2933
- const registeredKey = this.deviceKeys.get(deviceSE.deviceId);
2934
- if (registeredKey) {
2935
- publicKey = registeredKey;
2936
- }
2937
- if (!publicKey || publicKey.length !== 32) {
2938
- return {
2939
- valid: false,
2940
- error: "Invalid or unregistered device public key"
2941
- };
2942
- }
2943
- try {
2944
- const valid = nacl.sign.detached.verify(signTarget, signature, publicKey);
2945
- if (!valid) {
2946
- return { valid: false, error: "Device signature verification failed" };
2947
- }
2948
- return {
2949
- valid: true,
2950
- actorId: deviceSE.deviceId,
2951
- metadata: { deviceId: deviceSE.deviceId, proofType: "DEVICE_SE" }
2952
- };
2953
- } catch (e) {
2954
- const message = e instanceof Error ? e.message : "Unknown error";
2955
- return {
2956
- valid: false,
2957
- error: `Signature verification error: ${message}`
2958
- };
2959
- }
3155
+ list() {
3156
+ return [...this.sensors].sort(
3157
+ (a, b) => (a.order ?? 999) - (b.order ?? 999)
3158
+ );
2960
3159
  }
2961
3160
  /**
2962
- * Registers a public key for a trusted device.
2963
- * This key will be used for future `DEVICE_SE` proof verifications.
3161
+ * Returns only pre-decode sensors (order < 40).
3162
+ * These sensors run in middleware on raw bytes before frame decoding.
2964
3163
  *
2965
- * @param {string} deviceId - Unique identifier for the device
2966
- * @param {Uint8Array} publicKey - 32-byte Ed25519 public key
2967
- * @throws {Error} If the public key is not 32 bytes
3164
+ * @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
2968
3165
  */
2969
- registerDeviceKey(deviceId, publicKey) {
2970
- if (publicKey.length !== 32) {
2971
- throw new Error("Device public key must be 32 bytes (Ed25519)");
2972
- }
2973
- this.deviceKeys.set(deviceId, publicKey);
2974
- this.logger.log(`Registered device key for ${deviceId}`);
3166
+ getPreDecodeSensors() {
3167
+ return this.list().filter((s) => (s.order ?? 999) < 40);
2975
3168
  }
2976
3169
  /**
2977
- * Unregister a device
3170
+ * Returns only post-decode sensors (order >= 40).
3171
+ * These sensors run in the controller on fully decoded frames.
3172
+ *
3173
+ * @returns {AxisPostSensor[]} Post-decode sensors sorted by order
2978
3174
  */
2979
- unregisterDevice(deviceId) {
2980
- return this.deviceKeys.delete(deviceId);
3175
+ getPostDecodeSensors() {
3176
+ return this.list().filter(
3177
+ (s) => (s.order ?? 999) >= 40
3178
+ );
2981
3179
  }
2982
3180
  /**
2983
- * Registers a trusted mTLS certificate fingerprint and associates it with an actor.
3181
+ * Helper: Check if a sensor is a pre-decode sensor.
2984
3182
  *
2985
- * @param {string} fingerprint - SHA-256 fingerprint of the client certificate
2986
- * @param {string} actorId - The actor to associate with this certificate
3183
+ * @private
3184
+ * @param {AxisSensor} sensor - The sensor to check
3185
+ * @returns {boolean} True if sensor is pre-decode
2987
3186
  */
2988
- registerMTLSCert(fingerprint, actorId) {
2989
- this.trustedCerts.set(fingerprint, { actorId, issuedAt: Date.now() });
2990
- this.logger.log(`Registered mTLS cert ${fingerprint} for actor ${actorId}`);
3187
+ isPreDecodeSensor(sensor) {
3188
+ const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3189
+ return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
2991
3190
  }
2992
3191
  /**
2993
- * Revoke an mTLS certificate
3192
+ * Helper: Check if a sensor is a post-decode sensor.
3193
+ *
3194
+ * @private
3195
+ * @param {AxisSensor} sensor - The sensor to check
3196
+ * @returns {boolean} True if sensor is post-decode
2994
3197
  */
2995
- revokeMTLSCert(fingerprint) {
2996
- return this.trustedCerts.delete(fingerprint);
3198
+ isPostDecodeSensor(sensor) {
3199
+ const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3200
+ return phase === "POST_DECODE" || (sensor.order ?? 999) >= 40;
2997
3201
  }
2998
3202
  /**
2999
- * Calculate certificate fingerprint (SHA-256)
3203
+ * Returns sensor count by phase.
3204
+ * Useful for diagnostics and monitoring.
3205
+ *
3206
+ * @returns {{preDecodeCount: number, postDecodeCount: number}}
3000
3207
  */
3001
- static calculateFingerprint(certPem) {
3002
- const der = Buffer.from(
3003
- certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
3004
- "base64"
3005
- );
3006
- return crypto3.createHash("sha256").update(der).digest("hex");
3007
- }
3008
- };
3009
- ProofVerificationService = __decorateClass([
3010
- Injectable4()
3011
- ], ProofVerificationService);
3012
-
3013
- // src/decorators/index.ts
3014
- var decorators_exports = {};
3015
- __export(decorators_exports, {
3016
- AxisContext: () => AxisContext,
3017
- AxisDemoPubkey: () => AxisDemoPubkey,
3018
- AxisFrame: () => AxisFrame3,
3019
- AxisIp: () => AxisIp,
3020
- AxisRaw: () => AxisRaw,
3021
- HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
3022
- Handler: () => Handler,
3023
- INTENT_BODY_KEY: () => INTENT_BODY_KEY,
3024
- INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
3025
- INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
3026
- INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
3027
- Intent: () => Intent,
3028
- IntentBody: () => IntentBody,
3029
- IntentSensors: () => IntentSensors,
3030
- SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
3031
- Sensor: () => Sensor,
3032
- TLV_FIELDS_KEY: () => TLV_FIELDS_KEY,
3033
- TLV_VALIDATORS_KEY: () => TLV_VALIDATORS_KEY,
3034
- TlvEnum: () => TlvEnum,
3035
- TlvField: () => TlvField,
3036
- TlvMinLen: () => TlvMinLen,
3037
- TlvRange: () => TlvRange,
3038
- TlvUtf8Pattern: () => TlvUtf8Pattern,
3039
- TlvValidate: () => TlvValidate,
3040
- buildDtoDecoder: () => buildDtoDecoder,
3041
- extractDtoSchema: () => extractDtoSchema
3042
- });
3043
-
3044
- // src/decorators/axis-request.decorator.ts
3045
- import { createParamDecorator } from "@nestjs/common";
3046
- function resolveIp(req) {
3047
- return req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress || void 0;
3048
- }
3049
- var AxisRaw = createParamDecorator(
3050
- (_data, ctx) => {
3051
- const req = ctx.switchToHttp().getRequest();
3052
- return req.body;
3053
- }
3054
- );
3055
- var AxisIp = createParamDecorator(
3056
- (_data, ctx) => {
3057
- const req = ctx.switchToHttp().getRequest();
3058
- return resolveIp(req);
3059
- }
3060
- );
3061
- var AxisContext = createParamDecorator(
3062
- (_data, ctx) => {
3063
- const req = ctx.switchToHttp().getRequest();
3064
- const axisData = req.axis || {};
3208
+ getSensorCountByPhase() {
3065
3209
  return {
3066
- raw: req.body,
3067
- ip: resolveIp(req),
3068
- preDecodeInput: axisData.preDecodeInput,
3069
- frameBytesCount: axisData.frameBytesCount || 0
3210
+ preDecodeCount: this.getPreDecodeSensors().length,
3211
+ postDecodeCount: this.getPostDecodeSensors().length
3070
3212
  };
3071
3213
  }
3072
- );
3073
- var AxisDemoPubkey = createParamDecorator(
3074
- (_data, ctx) => {
3075
- if (process.env.NODE_ENV !== "development") return void 0;
3076
- const req = ctx.switchToHttp().getRequest();
3077
- return req.headers["x-demo-pubkey"];
3078
- }
3079
- );
3080
- var AxisFrame3 = createParamDecorator(
3081
- (_data, ctx) => {
3082
- const req = ctx.switchToHttp().getRequest();
3083
- const decoded = req.axisDecoded;
3084
- if (!decoded) {
3085
- throw new Error(
3086
- "@AxisFrame() requires AxisDecodeInterceptor on the route. Add @UseInterceptors(AxisDecodeInterceptor) to use this decorator."
3087
- );
3088
- }
3089
- return decoded;
3214
+ /**
3215
+ * Clears all registered sensors.
3216
+ * Useful for testing.
3217
+ *
3218
+ * @internal
3219
+ */
3220
+ clear() {
3221
+ this.sensors = [];
3090
3222
  }
3091
- );
3092
-
3093
- // src/decorators/sensor.decorator.ts
3094
- import { SetMetadata as SetMetadata2 } from "@nestjs/common";
3095
- var SENSOR_METADATA_KEY = "axis:sensor";
3096
- function Sensor(options) {
3097
- return SetMetadata2(SENSOR_METADATA_KEY, options ?? true);
3098
- }
3099
-
3100
- // src/engine/index.ts
3101
- var engine_exports = {};
3102
- __export(engine_exports, {
3103
- BAND: () => BAND,
3104
- HandlerDiscoveryService: () => HandlerDiscoveryService,
3105
- IntentRouter: () => IntentRouter,
3106
- PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
3107
- SensorDiscoveryService: () => SensorDiscoveryService,
3108
- SensorRegistry: () => SensorRegistry,
3109
- createObservation: () => createObservation,
3110
- endStage: () => endStage,
3111
- finalizeObservation: () => finalizeObservation,
3112
- recordSensor: () => recordSensor,
3113
- startStage: () => startStage
3114
- });
3223
+ };
3224
+ SensorRegistry = __decorateClass([
3225
+ Injectable6()
3226
+ ], SensorRegistry);
3115
3227
 
3116
3228
  // src/engine/axis-observation.ts
3117
3229
  import { randomBytes as randomBytes3 } from "crypto";
@@ -3149,251 +3261,514 @@ function finalizeObservation(obs, decision, statusCode, resultCode) {
3149
3261
  if (resultCode) obs.resultCode = resultCode;
3150
3262
  }
3151
3263
 
3152
- // src/engine/handler-discovery.service.ts
3153
- import { Injectable as Injectable5, Logger as Logger4 } from "@nestjs/common";
3154
- var HandlerDiscoveryService = class {
3155
- constructor(discovery, scanner, router) {
3156
- this.discovery = discovery;
3157
- this.scanner = scanner;
3158
- this.router = router;
3159
- this.logger = new Logger4(HandlerDiscoveryService.name);
3264
+ // src/security/axis-sensor-chain.service.ts
3265
+ import { Injectable as Injectable7 } from "@nestjs/common";
3266
+ var AxisSensorChainService = class {
3267
+ constructor(registry) {
3268
+ this.registry = registry;
3160
3269
  }
3161
- onModuleInit() {
3162
- const providers = this.discovery.getProviders();
3163
- let totalIntents = 0;
3164
- for (const wrapper of providers) {
3165
- const { instance, metatype } = wrapper;
3166
- if (!instance || !metatype) continue;
3167
- const handlerMeta = Reflect.getMetadata(HANDLER_METADATA_KEY, metatype);
3168
- if (!handlerMeta) continue;
3169
- const handlerName = handlerMeta.intent || metatype.name;
3170
- const proto = Object.getPrototypeOf(instance);
3171
- const methods = this.scanner.getAllMethodNames(proto);
3172
- let registered = 0;
3173
- for (const methodName of methods) {
3174
- const meta = Reflect.getMetadata(
3175
- INTENT_METADATA_KEY,
3176
- proto,
3177
- methodName
3178
- );
3179
- if (!meta?.intent) continue;
3180
- if (!this.router.has(meta.intent)) {
3181
- this.router.register(
3182
- meta.intent,
3183
- instance[methodName].bind(instance)
3184
- );
3185
- registered++;
3186
- totalIntents++;
3187
- }
3188
- this.router.registerIntentMeta(meta.intent, proto, methodName);
3189
- }
3190
- if (registered > 0) {
3191
- this.logger.log(
3192
- `Auto-registered ${registered} intents from ${handlerName}`
3193
- );
3194
- }
3270
+ /**
3271
+ * Evaluate all applicable sensors based on phase.
3272
+ */
3273
+ async evaluate(input, phase = "POST_DECODE", baseDecision) {
3274
+ if (phase === "PRE_DECODE") {
3275
+ return this.evaluateSensors(this.registry.getPreDecodeSensors(), input);
3276
+ }
3277
+ if (phase === "BOTH") {
3278
+ const rawPreResult = await this.evaluateSensors(
3279
+ this.registry.getPreDecodeSensors(),
3280
+ input
3281
+ );
3282
+ const preResult = normalizeSensorDecision(rawPreResult);
3283
+ if (!preResult.allow) return rawPreResult;
3284
+ return this.evaluateSensors(
3285
+ this.registry.getPostDecodeSensors(),
3286
+ input,
3287
+ rawPreResult
3288
+ );
3195
3289
  }
3196
- this.logger.log(
3197
- `Handler discovery complete: ${totalIntents} intents auto-registered`
3290
+ return this.evaluateSensors(
3291
+ this.registry.getPostDecodeSensors(),
3292
+ input,
3293
+ baseDecision
3198
3294
  );
3199
3295
  }
3200
- };
3201
- HandlerDiscoveryService = __decorateClass([
3202
- Injectable5()
3203
- ], HandlerDiscoveryService);
3204
-
3205
- // src/engine/sensor-bands.ts
3206
- var BAND = {
3207
- /** Pre-decode: raw byte validation, geo, budget, magic */
3208
- WIRE: 0,
3209
- /** Post-decode: identity resolution, capsule, proof */
3210
- IDENTITY: 40,
3211
- /** Post-decode: authorization, signature, rate limiting */
3212
- POLICY: 90,
3213
- /** Post-decode: content validation, TLV, schema, files */
3214
- CONTENT: 140,
3215
- /** Post-decode: business logic sensors, streams, WS */
3216
- BUSINESS: 200,
3217
- /** Post-decode: audit, logging (always last) */
3218
- AUDIT: 900
3219
- };
3220
- var PRE_DECODE_BOUNDARY = 40;
3221
-
3222
- // src/engine/sensor-discovery.service.ts
3223
- import { Injectable as Injectable6, Logger as Logger5 } from "@nestjs/common";
3224
- var SensorDiscoveryService = class {
3225
- constructor(discovery, reflector, registry) {
3226
- this.discovery = discovery;
3227
- this.reflector = reflector;
3228
- this.registry = registry;
3229
- this.logger = new Logger5(SensorDiscoveryService.name);
3296
+ /** Run only pre-decode sensors. */
3297
+ async evaluatePre(input) {
3298
+ return this.evaluateSensors(this.registry.getPreDecodeSensors(), input);
3230
3299
  }
3231
- onApplicationBootstrap() {
3232
- const providers = this.discovery.getProviders();
3233
- let count = 0;
3234
- for (const wrapper of providers) {
3235
- const { instance } = wrapper;
3236
- if (!instance || !instance.constructor) continue;
3237
- const meta = this.reflector.get(
3238
- SENSOR_METADATA_KEY,
3239
- instance.constructor
3240
- );
3241
- if (!meta) continue;
3242
- const sensor = instance;
3243
- if (!sensor.name || sensor.order === void 0) {
3244
- this.logger.warn(
3245
- `@Sensor() on ${instance.constructor.name} missing name or order \u2014 skipped`
3246
- );
3247
- continue;
3248
- }
3249
- if (!sensor.phase) {
3250
- const decoratorPhase = meta !== true ? meta.phase : void 0;
3251
- sensor.phase = decoratorPhase ?? (sensor.order < PRE_DECODE_BOUNDARY ? "PRE_DECODE" : "POST_DECODE");
3300
+ /** Run only post-decode sensors. */
3301
+ async evaluatePost(input, baseDecision) {
3302
+ return this.evaluateSensors(
3303
+ this.registry.getPostDecodeSensors(),
3304
+ input,
3305
+ baseDecision
3306
+ );
3307
+ }
3308
+ async evaluateSensors(sensors, input, baseDecision) {
3309
+ const relevantSensors = sensors.filter(
3310
+ (s) => !s.supports || s.supports(input)
3311
+ );
3312
+ const normalizedBase = baseDecision ? normalizeSensorDecision(baseDecision) : void 0;
3313
+ let riskScore = normalizedBase?.riskScore ?? 0;
3314
+ const reasons = normalizedBase?.reasons ? [...normalizedBase.reasons] : [];
3315
+ const tags = normalizedBase?.tags ? { ...normalizedBase.tags } : {};
3316
+ let expSecondsMax = normalizedBase?.tighten?.expSecondsMax;
3317
+ let constraintsPatch = normalizedBase?.tighten?.constraintsPatch ? { ...normalizedBase.tighten.constraintsPatch } : {};
3318
+ for (const sensor of relevantSensors) {
3319
+ try {
3320
+ const t0 = Date.now();
3321
+ const rawDecision = await sensor.run(input);
3322
+ const elapsed = Date.now() - t0;
3323
+ const decision = normalizeSensorDecision(rawDecision);
3324
+ const obs = input.metadata?.observation;
3325
+ if (obs) {
3326
+ recordSensor(
3327
+ obs,
3328
+ sensor.name,
3329
+ decision.allow,
3330
+ decision.riskScore,
3331
+ elapsed,
3332
+ decision.reasons,
3333
+ decision.allow ? void 0 : decision.code
3334
+ );
3335
+ }
3336
+ if (!decision.allow) {
3337
+ return {
3338
+ allow: false,
3339
+ riskScore: Math.min(100, riskScore + decision.riskScore),
3340
+ reasons: [...reasons, ...decision.reasons],
3341
+ tags
3342
+ };
3343
+ }
3344
+ riskScore = Math.min(100, riskScore + decision.riskScore);
3345
+ reasons.push(...decision.reasons);
3346
+ if (decision.tags) {
3347
+ Object.assign(tags, decision.tags);
3348
+ }
3349
+ if (decision.tighten?.expSecondsMax !== void 0) {
3350
+ expSecondsMax = expSecondsMax === void 0 ? decision.tighten.expSecondsMax : Math.min(expSecondsMax, decision.tighten.expSecondsMax);
3351
+ }
3352
+ if (decision.tighten?.constraintsPatch) {
3353
+ constraintsPatch = {
3354
+ ...constraintsPatch,
3355
+ ...decision.tighten.constraintsPatch
3356
+ };
3357
+ }
3358
+ } catch (error) {
3359
+ console.error(`[AXIS][SENSOR] ${sensor.name} failed:`, error);
3360
+ const obs = input.metadata?.observation;
3361
+ if (obs) {
3362
+ recordSensor(obs, sensor.name, false, 100, 0, [
3363
+ `sensor_error:${sensor.name}`
3364
+ ]);
3365
+ }
3366
+ return {
3367
+ allow: false,
3368
+ riskScore: 100,
3369
+ reasons: [`sensor_error:${sensor.name}`]
3370
+ };
3252
3371
  }
3253
- this.registry.register(sensor);
3254
- count++;
3255
3372
  }
3256
- this.logger.log(`Auto-registered ${count} sensors via @Sensor()`);
3373
+ const tightenPatch = Object.keys(constraintsPatch).length > 0 ? constraintsPatch : void 0;
3374
+ return {
3375
+ allow: true,
3376
+ riskScore,
3377
+ reasons,
3378
+ tags,
3379
+ tighten: expSecondsMax !== void 0 || tightenPatch ? {
3380
+ expSecondsMax,
3381
+ constraintsPatch: tightenPatch
3382
+ } : void 0
3383
+ };
3257
3384
  }
3258
3385
  };
3259
- SensorDiscoveryService = __decorateClass([
3260
- Injectable6()
3261
- ], SensorDiscoveryService);
3386
+ AxisSensorChainService = __decorateClass([
3387
+ Injectable7()
3388
+ ], AxisSensorChainService);
3262
3389
 
3263
- // src/engine/registry/sensor.registry.ts
3264
- import { Injectable as Injectable7, Logger as Logger6 } from "@nestjs/common";
3265
- var SensorRegistry = class {
3266
- constructor(configService) {
3267
- this.configService = configService;
3268
- this.sensors = [];
3269
- this.logger = new Logger6(SensorRegistry.name);
3390
+ // src/core/index.ts
3391
+ var core_exports = {};
3392
+ __export(core_exports, {
3393
+ AXIS_MAGIC: () => AXIS_MAGIC,
3394
+ AXIS_VERSION: () => AXIS_VERSION,
3395
+ AxisError: () => AxisError,
3396
+ AxisFrameZ: () => AxisFrameZ,
3397
+ BodyProfile: () => BodyProfile,
3398
+ ERR_BAD_SIGNATURE: () => ERR_BAD_SIGNATURE,
3399
+ ERR_CONTRACT_VIOLATION: () => ERR_CONTRACT_VIOLATION,
3400
+ ERR_INVALID_PACKET: () => ERR_INVALID_PACKET,
3401
+ ERR_REPLAY_DETECTED: () => ERR_REPLAY_DETECTED,
3402
+ FLAG_BODY_TLV: () => FLAG_BODY_TLV,
3403
+ FLAG_CHAIN_REQ: () => FLAG_CHAIN_REQ,
3404
+ FLAG_HAS_WITNESS: () => FLAG_HAS_WITNESS,
3405
+ MAX_BODY_LEN: () => MAX_BODY_LEN,
3406
+ MAX_FRAME_LEN: () => MAX_FRAME_LEN,
3407
+ MAX_HDR_LEN: () => MAX_HDR_LEN,
3408
+ MAX_SIG_LEN: () => MAX_SIG_LEN,
3409
+ NCERT_ALG: () => NCERT_ALG,
3410
+ NCERT_EXP: () => NCERT_EXP,
3411
+ NCERT_ISSUER_KID: () => NCERT_ISSUER_KID,
3412
+ NCERT_KID: () => NCERT_KID,
3413
+ NCERT_NBF: () => NCERT_NBF,
3414
+ NCERT_NODE_ID: () => NCERT_NODE_ID,
3415
+ NCERT_PAYLOAD: () => NCERT_PAYLOAD,
3416
+ NCERT_PUB: () => NCERT_PUB,
3417
+ NCERT_SCOPE: () => NCERT_SCOPE,
3418
+ NCERT_SIG: () => NCERT_SIG,
3419
+ PROOF_CAPSULE: () => PROOF_CAPSULE,
3420
+ PROOF_JWT: () => PROOF_JWT,
3421
+ PROOF_LOOM: () => PROOF_LOOM,
3422
+ PROOF_MTLS: () => PROOF_MTLS,
3423
+ PROOF_NONE: () => PROOF_NONE,
3424
+ PROOF_WITNESS: () => PROOF_WITNESS,
3425
+ ProofType: () => ProofType,
3426
+ TLV: () => TLV,
3427
+ TLV_ACTOR_ID: () => TLV_ACTOR_ID,
3428
+ TLV_AUD: () => TLV_AUD,
3429
+ TLV_BODY_ARR: () => TLV_BODY_ARR,
3430
+ TLV_BODY_OBJ: () => TLV_BODY_OBJ,
3431
+ TLV_CAPSULE: () => TLV_CAPSULE,
3432
+ TLV_EFFECT: () => TLV_EFFECT,
3433
+ TLV_ERROR_CODE: () => TLV_ERROR_CODE,
3434
+ TLV_ERROR_MSG: () => TLV_ERROR_MSG,
3435
+ TLV_INDEX: () => TLV_INDEX,
3436
+ TLV_INTENT: () => TLV_INTENT,
3437
+ TLV_KID: () => TLV_KID,
3438
+ TLV_LOOM_PRESENCE_ID: () => TLV_LOOM_PRESENCE_ID,
3439
+ TLV_LOOM_THREAD_HASH: () => TLV_LOOM_THREAD_HASH,
3440
+ TLV_LOOM_WRIT: () => TLV_LOOM_WRIT,
3441
+ TLV_NODE: () => TLV_NODE,
3442
+ TLV_NODE_CERT_HASH: () => TLV_NODE_CERT_HASH,
3443
+ TLV_NODE_KID: () => TLV_NODE_KID,
3444
+ TLV_NONCE: () => TLV_NONCE,
3445
+ TLV_OFFSET: () => TLV_OFFSET,
3446
+ TLV_OK: () => TLV_OK,
3447
+ TLV_PID: () => TLV_PID,
3448
+ TLV_PREV_HASH: () => TLV_PREV_HASH,
3449
+ TLV_PROOF_REF: () => TLV_PROOF_REF,
3450
+ TLV_PROOF_TYPE: () => TLV_PROOF_TYPE,
3451
+ TLV_REALM: () => TLV_REALM,
3452
+ TLV_RECEIPT_HASH: () => TLV_RECEIPT_HASH,
3453
+ TLV_RID: () => TLV_RID,
3454
+ TLV_SHA256_CHUNK: () => TLV_SHA256_CHUNK,
3455
+ TLV_TRACE_ID: () => TLV_TRACE_ID,
3456
+ TLV_TS: () => TLV_TS,
3457
+ TLV_UPLOAD_ID: () => TLV_UPLOAD_ID,
3458
+ computeReceiptHash: () => computeReceiptHash,
3459
+ computeSignaturePayload: () => computeSignaturePayload,
3460
+ decodeArray: () => decodeArray,
3461
+ decodeFrame: () => decodeFrame,
3462
+ decodeObject: () => decodeObject,
3463
+ decodeTLVs: () => decodeTLVs,
3464
+ decodeTLVsList: () => decodeTLVsList,
3465
+ decodeVarint: () => decodeVarint,
3466
+ encodeFrame: () => encodeFrame,
3467
+ encodeTLVs: () => encodeTLVs,
3468
+ encodeVarint: () => encodeVarint,
3469
+ generateEd25519KeyPair: () => generateEd25519KeyPair,
3470
+ getSignTarget: () => getSignTarget,
3471
+ sha256: () => sha256,
3472
+ signFrame: () => signFrame,
3473
+ varintLength: () => varintLength,
3474
+ verifyFrameSignature: () => verifyFrameSignature
3475
+ });
3476
+
3477
+ // src/crypto/index.ts
3478
+ var crypto_exports = {};
3479
+ __export(crypto_exports, {
3480
+ ProofVerificationService: () => ProofVerificationService,
3481
+ b64urlDecode: () => b64urlDecode,
3482
+ b64urlDecodeString: () => b64urlDecodeString,
3483
+ b64urlEncode: () => b64urlEncode,
3484
+ b64urlEncodeString: () => b64urlEncodeString,
3485
+ canonicalJson: () => canonicalJson,
3486
+ canonicalJsonExcluding: () => canonicalJsonExcluding
3487
+ });
3488
+
3489
+ // src/crypto/proof-verification.service.ts
3490
+ import { Injectable as Injectable8, Logger as Logger7 } from "@nestjs/common";
3491
+ import * as crypto3 from "crypto";
3492
+ import * as nacl from "tweetnacl";
3493
+ var ProofVerificationService = class {
3494
+ constructor() {
3495
+ this.logger = new Logger7(ProofVerificationService.name);
3496
+ // Cache of registered device public keys (deviceId -> pubKey)
3497
+ this.deviceKeys = /* @__PURE__ */ new Map();
3498
+ // Cache of trusted mTLS certificate fingerprints
3499
+ this.trustedCerts = /* @__PURE__ */ new Map();
3270
3500
  }
3271
3501
  /**
3272
- * Registers a new sensor in the registry.
3502
+ * Verifies an authentication proof based on its type.
3273
3503
  *
3274
- * Validates that:
3275
- * - AxisSensor has a unique name
3276
- * - AxisSensor has an order field
3277
- * - Pre-decode sensors have order < 40
3278
- * - Post-decode sensors have order >= 40
3504
+ * **Supported Types:**
3505
+ * - 1 (CAPSULE): Delegated to `verifyCapsuleProof`
3506
+ * - 2 (JWT): Verified by `verifyJWTProof`
3507
+ * - 3 (MTLS_ID): Verified by `verifyMTLSProof`
3508
+ * - 4 (DEVICE_SE): Verified by `verifyDeviceSEProof`
3279
3509
  *
3280
- * @param {AxisSensor} sensor - The sensor instance to register
3281
- * @throws Error if validation fails
3510
+ * @param {ProofType} proofType - The numeric AXIS proof type
3511
+ * @param {Uint8Array} proofRef - The binary reference or token for the proof
3512
+ * @param {Object} context - Additional metadata required for specific proof types
3513
+ * @param {Uint8Array} [context.signTarget] - The canonical bytes that were signed (for Ed25519)
3514
+ * @param {Uint8Array} [context.signature] - The signature to verify (for Ed25519)
3515
+ * @param {MTLSContext} [context.mtls] - mTLS certificate data
3516
+ * @param {DeviceSEContext} [context.deviceSE] - Device Secure Element information
3517
+ * @returns {Promise<ProofVerificationResult>} The outcome of the verification
3282
3518
  */
3283
- register(sensor) {
3284
- if (!sensor.name) {
3285
- throw new Error("AxisSensor must have a name");
3286
- }
3287
- const enabledSensorsStr = this.configService.get("ENABLED_SENSORS");
3288
- const disabledSensorsStr = this.configService.get("DISABLED_SENSORS");
3289
- const enabledSensors = enabledSensorsStr ? enabledSensorsStr.split(",").map((s) => s.trim()) : null;
3290
- const disabledSensors = disabledSensorsStr ? disabledSensorsStr.split(",").map((s) => s.trim()) : [];
3291
- if (enabledSensors && !enabledSensors.includes(sensor.name)) {
3292
- this.logger.log(`Skipping disabled sensor (not in ENABLED_SENSORS): ${sensor.name}`);
3293
- return;
3294
- }
3295
- if (disabledSensors.includes(sensor.name)) {
3296
- this.logger.log(`Skipping disabled sensor (in DISABLED_SENSORS): ${sensor.name}`);
3297
- return;
3298
- }
3299
- if (sensor.order === void 0) {
3300
- throw new Error(`AxisSensor "${sensor.name}" must have an order field`);
3301
- }
3302
- const isPreDecodeSensor = this.isPreDecodeSensor(sensor);
3303
- const isPostDecodeSensor = this.isPostDecodeSensor(sensor);
3304
- if (isPreDecodeSensor && sensor.order >= 40) {
3305
- this.logger.warn(
3306
- `AxisSensor "${sensor.name}" is marked as PRE_DECODE but has order ${sensor.order} (should be < 40)`
3307
- );
3308
- }
3309
- if (isPostDecodeSensor && sensor.order < 40) {
3310
- this.logger.warn(
3311
- `AxisSensor "${sensor.name}" is marked as POST_DECODE but has order ${sensor.order} (should be >= 40)`
3312
- );
3519
+ async verifyProof(proofType, proofRef, context) {
3520
+ switch (proofType) {
3521
+ case 1:
3522
+ return this.verifyCapsuleProof(proofRef);
3523
+ case 2:
3524
+ return this.verifyJWTProof(proofRef);
3525
+ case 3:
3526
+ return this.verifyMTLSProof(context.mtls);
3527
+ case 4:
3528
+ return this.verifyDeviceSEProof(
3529
+ context.signTarget,
3530
+ context.signature,
3531
+ context.deviceSE
3532
+ );
3533
+ default:
3534
+ return { valid: false, error: `Unknown proof type: ${proofType}` };
3535
+ }
3536
+ }
3537
+ /**
3538
+ * Verify CAPSULE proof (delegated to CapsuleService)
3539
+ */
3540
+ async verifyCapsuleProof(proofRef) {
3541
+ const capsuleId = new TextDecoder().decode(proofRef);
3542
+ return {
3543
+ valid: true,
3544
+ metadata: { capsuleId, requiresCapsuleValidation: true }
3545
+ };
3546
+ }
3547
+ /**
3548
+ * Verifies a JSON Web Token (JWT) proof.
3549
+ *
3550
+ * **Validation Logic:**
3551
+ * 1. Decodes the token string.
3552
+ * 2. Checks for valid 3-part JWT structure.
3553
+ * 3. Validates `exp` (expiration) and `nbf` (not before) claims.
3554
+ * 4. Extracts `actor_id` or `sub` as the identity.
3555
+ *
3556
+ * @param {Uint8Array} proofRef - Binary representation of the JWT string
3557
+ * @returns {Promise<ProofVerificationResult>} Result including the actor identifier
3558
+ */
3559
+ async verifyJWTProof(proofRef) {
3560
+ try {
3561
+ const token = new TextDecoder().decode(proofRef);
3562
+ const parts = token.split(".");
3563
+ if (parts.length !== 3) {
3564
+ return { valid: false, error: "Invalid JWT format" };
3565
+ }
3566
+ const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
3567
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
3568
+ if (payload.exp && Date.now() / 1e3 > payload.exp) {
3569
+ return { valid: false, error: "JWT expired" };
3570
+ }
3571
+ if (payload.nbf && Date.now() / 1e3 < payload.nbf) {
3572
+ return { valid: false, error: "JWT not yet valid" };
3573
+ }
3574
+ return {
3575
+ valid: true,
3576
+ actorId: payload.sub || payload.actor_id,
3577
+ metadata: { iss: payload.iss, scope: payload.scope }
3578
+ };
3579
+ } catch (e) {
3580
+ const message = e instanceof Error ? e.message : "Unknown error";
3581
+ return { valid: false, error: `JWT parse error: ${message}` };
3313
3582
  }
3314
- this.sensors.push(sensor);
3315
- const phaseLabel = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase || "UNKNOWN";
3316
- this.logger.debug(
3317
- `Registered sensor: ${sensor.name} (order: ${sensor.order}, phase: ${phaseLabel})`
3318
- );
3319
3583
  }
3320
3584
  /**
3321
- * Returns all registered sensors, sorted by their execution order.
3322
- *
3323
- * @returns {AxisSensor[]} A sorted array of sensors
3585
+ * Verify mTLS client certificate proof
3324
3586
  */
3325
- list() {
3326
- return [...this.sensors].sort(
3327
- (a, b) => (a.order ?? 999) - (b.order ?? 999)
3328
- );
3587
+ async verifyMTLSProof(mtls) {
3588
+ if (!mtls) {
3589
+ return { valid: false, error: "No mTLS context provided" };
3590
+ }
3591
+ if (!mtls.verified) {
3592
+ return { valid: false, error: "mTLS not verified by TLS terminator" };
3593
+ }
3594
+ if (mtls.clientCertFingerprint) {
3595
+ const trusted = this.trustedCerts.get(mtls.clientCertFingerprint);
3596
+ if (trusted) {
3597
+ return {
3598
+ valid: true,
3599
+ actorId: trusted.actorId,
3600
+ metadata: {
3601
+ fingerprint: mtls.clientCertFingerprint,
3602
+ subject: mtls.clientCertSubject
3603
+ }
3604
+ };
3605
+ }
3606
+ }
3607
+ if (mtls.clientCertSubject) {
3608
+ const cnMatch = mtls.clientCertSubject.match(/CN=([^,]+)/);
3609
+ if (cnMatch) {
3610
+ return {
3611
+ valid: true,
3612
+ actorId: cnMatch[1],
3613
+ metadata: {
3614
+ subject: mtls.clientCertSubject,
3615
+ issuer: mtls.clientCertIssuer
3616
+ }
3617
+ };
3618
+ }
3619
+ }
3620
+ return { valid: false, error: "Could not extract actor from certificate" };
3329
3621
  }
3330
3622
  /**
3331
- * Returns only pre-decode sensors (order < 40).
3332
- * These sensors run in middleware on raw bytes before frame decoding.
3333
- *
3334
- * @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
3623
+ * Verify Device Secure Element signature
3335
3624
  */
3336
- getPreDecodeSensors() {
3337
- return this.list().filter((s) => (s.order ?? 999) < 40);
3625
+ async verifyDeviceSEProof(signTarget, signature, deviceSE) {
3626
+ if (!deviceSE || !signTarget || !signature) {
3627
+ return { valid: false, error: "Missing Device SE context" };
3628
+ }
3629
+ let publicKey = deviceSE.publicKey;
3630
+ const registeredKey = this.deviceKeys.get(deviceSE.deviceId);
3631
+ if (registeredKey) {
3632
+ publicKey = registeredKey;
3633
+ }
3634
+ if (!publicKey || publicKey.length !== 32) {
3635
+ return {
3636
+ valid: false,
3637
+ error: "Invalid or unregistered device public key"
3638
+ };
3639
+ }
3640
+ try {
3641
+ const valid = nacl.sign.detached.verify(signTarget, signature, publicKey);
3642
+ if (!valid) {
3643
+ return { valid: false, error: "Device signature verification failed" };
3644
+ }
3645
+ return {
3646
+ valid: true,
3647
+ actorId: deviceSE.deviceId,
3648
+ metadata: { deviceId: deviceSE.deviceId, proofType: "DEVICE_SE" }
3649
+ };
3650
+ } catch (e) {
3651
+ const message = e instanceof Error ? e.message : "Unknown error";
3652
+ return {
3653
+ valid: false,
3654
+ error: `Signature verification error: ${message}`
3655
+ };
3656
+ }
3338
3657
  }
3339
3658
  /**
3340
- * Returns only post-decode sensors (order >= 40).
3341
- * These sensors run in the controller on fully decoded frames.
3659
+ * Registers a public key for a trusted device.
3660
+ * This key will be used for future `DEVICE_SE` proof verifications.
3342
3661
  *
3343
- * @returns {AxisPostSensor[]} Post-decode sensors sorted by order
3662
+ * @param {string} deviceId - Unique identifier for the device
3663
+ * @param {Uint8Array} publicKey - 32-byte Ed25519 public key
3664
+ * @throws {Error} If the public key is not 32 bytes
3344
3665
  */
3345
- getPostDecodeSensors() {
3346
- return this.list().filter(
3347
- (s) => (s.order ?? 999) >= 40
3348
- );
3666
+ registerDeviceKey(deviceId, publicKey) {
3667
+ if (publicKey.length !== 32) {
3668
+ throw new Error("Device public key must be 32 bytes (Ed25519)");
3669
+ }
3670
+ this.deviceKeys.set(deviceId, publicKey);
3671
+ this.logger.log(`Registered device key for ${deviceId}`);
3349
3672
  }
3350
3673
  /**
3351
- * Helper: Check if a sensor is a pre-decode sensor.
3352
- *
3353
- * @private
3354
- * @param {AxisSensor} sensor - The sensor to check
3355
- * @returns {boolean} True if sensor is pre-decode
3674
+ * Unregister a device
3356
3675
  */
3357
- isPreDecodeSensor(sensor) {
3358
- const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3359
- return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
3676
+ unregisterDevice(deviceId) {
3677
+ return this.deviceKeys.delete(deviceId);
3360
3678
  }
3361
3679
  /**
3362
- * Helper: Check if a sensor is a post-decode sensor.
3680
+ * Registers a trusted mTLS certificate fingerprint and associates it with an actor.
3363
3681
  *
3364
- * @private
3365
- * @param {AxisSensor} sensor - The sensor to check
3366
- * @returns {boolean} True if sensor is post-decode
3682
+ * @param {string} fingerprint - SHA-256 fingerprint of the client certificate
3683
+ * @param {string} actorId - The actor to associate with this certificate
3367
3684
  */
3368
- isPostDecodeSensor(sensor) {
3369
- const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3370
- return phase === "POST_DECODE" || (sensor.order ?? 999) >= 40;
3685
+ registerMTLSCert(fingerprint, actorId) {
3686
+ this.trustedCerts.set(fingerprint, { actorId, issuedAt: Date.now() });
3687
+ this.logger.log(`Registered mTLS cert ${fingerprint} for actor ${actorId}`);
3371
3688
  }
3372
3689
  /**
3373
- * Returns sensor count by phase.
3374
- * Useful for diagnostics and monitoring.
3375
- *
3376
- * @returns {{preDecodeCount: number, postDecodeCount: number}}
3690
+ * Revoke an mTLS certificate
3377
3691
  */
3378
- getSensorCountByPhase() {
3379
- return {
3380
- preDecodeCount: this.getPreDecodeSensors().length,
3381
- postDecodeCount: this.getPostDecodeSensors().length
3382
- };
3692
+ revokeMTLSCert(fingerprint) {
3693
+ return this.trustedCerts.delete(fingerprint);
3383
3694
  }
3384
3695
  /**
3385
- * Clears all registered sensors.
3386
- * Useful for testing.
3387
- *
3388
- * @internal
3696
+ * Calculate certificate fingerprint (SHA-256)
3389
3697
  */
3390
- clear() {
3391
- this.sensors = [];
3698
+ static calculateFingerprint(certPem) {
3699
+ const der = Buffer.from(
3700
+ certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
3701
+ "base64"
3702
+ );
3703
+ return crypto3.createHash("sha256").update(der).digest("hex");
3392
3704
  }
3393
3705
  };
3394
- SensorRegistry = __decorateClass([
3395
- Injectable7()
3396
- ], SensorRegistry);
3706
+ ProofVerificationService = __decorateClass([
3707
+ Injectable8()
3708
+ ], ProofVerificationService);
3709
+
3710
+ // src/decorators/index.ts
3711
+ var decorators_exports = {};
3712
+ __export(decorators_exports, {
3713
+ AxisContext: () => AxisContext,
3714
+ AxisDemoPubkey: () => AxisDemoPubkey,
3715
+ AxisFrame: () => AxisFrame3,
3716
+ AxisIp: () => AxisIp,
3717
+ AxisRaw: () => AxisRaw,
3718
+ HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
3719
+ Handler: () => Handler,
3720
+ INTENT_BODY_KEY: () => INTENT_BODY_KEY,
3721
+ INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
3722
+ INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
3723
+ INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
3724
+ Intent: () => Intent,
3725
+ IntentBody: () => IntentBody,
3726
+ IntentSensors: () => IntentSensors,
3727
+ SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
3728
+ Sensor: () => Sensor,
3729
+ TLV_FIELDS_KEY: () => TLV_FIELDS_KEY,
3730
+ TLV_VALIDATORS_KEY: () => TLV_VALIDATORS_KEY,
3731
+ TlvEnum: () => TlvEnum,
3732
+ TlvField: () => TlvField,
3733
+ TlvMinLen: () => TlvMinLen,
3734
+ TlvRange: () => TlvRange,
3735
+ TlvUtf8Pattern: () => TlvUtf8Pattern,
3736
+ TlvValidate: () => TlvValidate,
3737
+ buildDtoDecoder: () => buildDtoDecoder,
3738
+ extractDtoSchema: () => extractDtoSchema
3739
+ });
3740
+
3741
+ // src/engine/index.ts
3742
+ var engine_exports = {};
3743
+ __export(engine_exports, {
3744
+ BAND: () => BAND,
3745
+ HandlerDiscoveryService: () => HandlerDiscoveryService,
3746
+ IntentRouter: () => IntentRouter,
3747
+ PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
3748
+ SensorDiscoveryService: () => SensorDiscoveryService,
3749
+ SensorRegistry: () => SensorRegistry,
3750
+ createObservation: () => createObservation,
3751
+ endStage: () => endStage,
3752
+ finalizeObservation: () => finalizeObservation,
3753
+ observation: () => observation_exports,
3754
+ recordSensor: () => recordSensor,
3755
+ startStage: () => startStage
3756
+ });
3757
+
3758
+ // src/engine/observation/index.ts
3759
+ var observation_exports = {};
3760
+ __export(observation_exports, {
3761
+ buildQueueMessage: () => buildQueueMessage,
3762
+ buildUnsignedWitness: () => buildUnsignedWitness,
3763
+ canonicalizeObservation: () => canonicalizeObservation,
3764
+ decodeQueueMessage: () => decodeQueueMessage,
3765
+ encodeQueueMessage: () => encodeQueueMessage,
3766
+ hashObservation: () => hashObservation,
3767
+ parseAutoClaimEntries: () => parseAutoClaimEntries,
3768
+ parseStreamEntries: () => parseStreamEntries,
3769
+ stableJsonStringify: () => stableJsonStringify,
3770
+ verifyResponse: () => verifyResponse
3771
+ });
3397
3772
 
3398
3773
  // src/loom/index.ts
3399
3774
  var loom_exports = {};
@@ -3763,7 +4138,7 @@ var AxisErrorZ = z2.object({
3763
4138
  });
3764
4139
 
3765
4140
  // src/schemas/body-profile.validator.ts
3766
- import { Injectable as Injectable8, Logger as Logger7 } from "@nestjs/common";
4141
+ import { Injectable as Injectable9, Logger as Logger8 } from "@nestjs/common";
3767
4142
  var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
3768
4143
  BodyProfile3[BodyProfile3["RAW"] = 0] = "RAW";
3769
4144
  BodyProfile3[BodyProfile3["TLV_MAP"] = 1] = "TLV_MAP";
@@ -3773,7 +4148,7 @@ var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
3773
4148
  })(BodyProfile2 || {});
3774
4149
  var BodyProfileValidator = class {
3775
4150
  constructor() {
3776
- this.logger = new Logger7(BodyProfileValidator.name);
4151
+ this.logger = new Logger8(BodyProfileValidator.name);
3777
4152
  }
3778
4153
  /**
3779
4154
  * Validate body matches declared profile
@@ -3889,12 +4264,13 @@ var BodyProfileValidator = class {
3889
4264
  }
3890
4265
  };
3891
4266
  BodyProfileValidator = __decorateClass([
3892
- Injectable8()
4267
+ Injectable9()
3893
4268
  ], BodyProfileValidator);
3894
4269
 
3895
4270
  // src/security/index.ts
3896
4271
  var security_exports = {};
3897
4272
  __export(security_exports, {
4273
+ AxisSensorChainService: () => AxisSensorChainService,
3898
4274
  CAPABILITIES: () => CAPABILITIES,
3899
4275
  INTENT_REQUIREMENTS: () => INTENT_REQUIREMENTS,
3900
4276
  PROOF_CAPABILITIES: () => PROOF_CAPABILITIES,
@@ -3927,7 +4303,7 @@ __export(sensors_exports, {
3927
4303
  });
3928
4304
 
3929
4305
  // src/sensors/access-profile-resolver.sensor.ts
3930
- import { Injectable as Injectable9 } from "@nestjs/common";
4306
+ import { Injectable as Injectable10 } from "@nestjs/common";
3931
4307
  var AccessProfileResolverSensor = class {
3932
4308
  constructor() {
3933
4309
  /** AxisSensor identifier */
@@ -3953,11 +4329,11 @@ var AccessProfileResolverSensor = class {
3953
4329
  };
3954
4330
  AccessProfileResolverSensor = __decorateClass([
3955
4331
  Sensor(),
3956
- Injectable9()
4332
+ Injectable10()
3957
4333
  ], AccessProfileResolverSensor);
3958
4334
 
3959
4335
  // src/sensors/body-budget.sensor.ts
3960
- import { Injectable as Injectable10 } from "@nestjs/common";
4336
+ import { Injectable as Injectable11 } from "@nestjs/common";
3961
4337
  var BodyBudgetSensor = class {
3962
4338
  constructor() {
3963
4339
  /** AxisSensor identifier */
@@ -4031,14 +4407,14 @@ var BodyBudgetSensor = class {
4031
4407
  };
4032
4408
  BodyBudgetSensor = __decorateClass([
4033
4409
  Sensor(),
4034
- Injectable10()
4410
+ Injectable11()
4035
4411
  ], BodyBudgetSensor);
4036
4412
 
4037
4413
  // src/sensors/capability-enforcement.sensor.ts
4038
- import { Injectable as Injectable11, Logger as Logger8 } from "@nestjs/common";
4414
+ import { Injectable as Injectable12, Logger as Logger9 } from "@nestjs/common";
4039
4415
  var CapabilityEnforcementSensor = class {
4040
4416
  constructor() {
4041
- this.logger = new Logger8(CapabilityEnforcementSensor.name);
4417
+ this.logger = new Logger9(CapabilityEnforcementSensor.name);
4042
4418
  /** AxisSensor identifier for logging and registry */
4043
4419
  this.name = "CapabilityEnforcementSensor";
4044
4420
  /**
@@ -4132,12 +4508,12 @@ var CapabilityEnforcementSensor = class {
4132
4508
  };
4133
4509
  CapabilityEnforcementSensor = __decorateClass([
4134
4510
  Sensor(),
4135
- Injectable11()
4511
+ Injectable12()
4136
4512
  ], CapabilityEnforcementSensor);
4137
4513
 
4138
4514
  // src/sensors/chunk-hash.sensor.ts
4139
- import { Injectable as Injectable12 } from "@nestjs/common";
4140
- import { createHash as createHash6 } from "crypto";
4515
+ import { Injectable as Injectable13 } from "@nestjs/common";
4516
+ import { createHash as createHash7 } from "crypto";
4141
4517
  var ChunkHashSensor = class {
4142
4518
  constructor() {
4143
4519
  /** Sensor identifier */
@@ -4196,7 +4572,7 @@ var ChunkHashSensor = class {
4196
4572
  reason: "Missing sha256Chunk TLV in header"
4197
4573
  };
4198
4574
  }
4199
- const actual = createHash6("sha256").update(bodyBytes).digest();
4575
+ const actual = createHash7("sha256").update(bodyBytes).digest();
4200
4576
  if (!Buffer.from(actual).equals(Buffer.from(expected))) {
4201
4577
  return {
4202
4578
  action: "DENY",
@@ -4209,15 +4585,15 @@ var ChunkHashSensor = class {
4209
4585
  };
4210
4586
  ChunkHashSensor = __decorateClass([
4211
4587
  Sensor(),
4212
- Injectable12()
4588
+ Injectable13()
4213
4589
  ], ChunkHashSensor);
4214
4590
 
4215
4591
  // src/sensors/entropy.sensor.ts
4216
- import { Injectable as Injectable13, Logger as Logger9 } from "@nestjs/common";
4592
+ import { Injectable as Injectable14, Logger as Logger10 } from "@nestjs/common";
4217
4593
  import * as crypto4 from "crypto";
4218
4594
  var EntropySensor = class {
4219
4595
  constructor() {
4220
- this.logger = new Logger9(EntropySensor.name);
4596
+ this.logger = new Logger10(EntropySensor.name);
4221
4597
  /**
4222
4598
  * Minimum acceptable entropy in bits per byte.
4223
4599
  *
@@ -4387,14 +4763,14 @@ var EntropySensor = class {
4387
4763
  };
4388
4764
  EntropySensor = __decorateClass([
4389
4765
  Sensor(),
4390
- Injectable13()
4766
+ Injectable14()
4391
4767
  ], EntropySensor);
4392
4768
 
4393
4769
  // src/sensors/execution-timeout.sensor.ts
4394
- import { Injectable as Injectable14, Logger as Logger10 } from "@nestjs/common";
4770
+ import { Injectable as Injectable15, Logger as Logger11 } from "@nestjs/common";
4395
4771
  var ExecutionTimeoutSensor = class {
4396
4772
  constructor() {
4397
- this.logger = new Logger10(ExecutionTimeoutSensor.name);
4773
+ this.logger = new Logger11(ExecutionTimeoutSensor.name);
4398
4774
  /** AxisSensor identifier */
4399
4775
  this.name = "ExecutionTimeoutSensor";
4400
4776
  /**
@@ -4472,11 +4848,11 @@ var ExecutionTimeoutSensor = class {
4472
4848
  };
4473
4849
  ExecutionTimeoutSensor = __decorateClass([
4474
4850
  Sensor(),
4475
- Injectable14()
4851
+ Injectable15()
4476
4852
  ], ExecutionTimeoutSensor);
4477
4853
 
4478
4854
  // src/sensors/frame-budget.sensor.ts
4479
- import { Injectable as Injectable15 } from "@nestjs/common";
4855
+ import { Injectable as Injectable16 } from "@nestjs/common";
4480
4856
  var FrameBudgetSensor = class {
4481
4857
  constructor(config) {
4482
4858
  this.config = config;
@@ -4535,11 +4911,11 @@ var FrameBudgetSensor = class {
4535
4911
  };
4536
4912
  FrameBudgetSensor = __decorateClass([
4537
4913
  Sensor({ phase: "PRE_DECODE" }),
4538
- Injectable15()
4914
+ Injectable16()
4539
4915
  ], FrameBudgetSensor);
4540
4916
 
4541
4917
  // src/sensors/frame-header-sanity.sensor.ts
4542
- import { Injectable as Injectable16 } from "@nestjs/common";
4918
+ import { Injectable as Injectable17 } from "@nestjs/common";
4543
4919
  var FrameHeaderSanitySensor = class {
4544
4920
  constructor() {
4545
4921
  this.name = "FrameHeaderSanitySensor";
@@ -4583,12 +4959,12 @@ var FrameHeaderSanitySensor = class {
4583
4959
  }
4584
4960
  };
4585
4961
  FrameHeaderSanitySensor = __decorateClass([
4586
- Injectable16(),
4962
+ Injectable17(),
4587
4963
  Sensor({ phase: "PRE_DECODE" })
4588
4964
  ], FrameHeaderSanitySensor);
4589
4965
 
4590
4966
  // src/sensors/header-tlv-limit.sensor.ts
4591
- import { Injectable as Injectable17 } from "@nestjs/common";
4967
+ import { Injectable as Injectable18 } from "@nestjs/common";
4592
4968
  var HeaderTLVLimitSensor = class {
4593
4969
  constructor() {
4594
4970
  this.name = "HeaderTLVLimitSensor";
@@ -4620,12 +4996,12 @@ var HeaderTLVLimitSensor = class {
4620
4996
  }
4621
4997
  };
4622
4998
  HeaderTLVLimitSensor = __decorateClass([
4623
- Injectable17(),
4999
+ Injectable18(),
4624
5000
  Sensor()
4625
5001
  ], HeaderTLVLimitSensor);
4626
5002
 
4627
5003
  // src/sensors/intent-allowlist.sensor.ts
4628
- import { Injectable as Injectable18 } from "@nestjs/common";
5004
+ import { Injectable as Injectable19 } from "@nestjs/common";
4629
5005
  var PUBLIC_INTENT_ALLOWLIST = [
4630
5006
  "public.",
4631
5007
  "schema.",
@@ -4660,12 +5036,12 @@ var IntentAllowlistSensor = class {
4660
5036
  }
4661
5037
  };
4662
5038
  IntentAllowlistSensor = __decorateClass([
4663
- Injectable18(),
5039
+ Injectable19(),
4664
5040
  Sensor()
4665
5041
  ], IntentAllowlistSensor);
4666
5042
 
4667
5043
  // src/sensors/intent-registry.sensor.ts
4668
- import { Injectable as Injectable19 } from "@nestjs/common";
5044
+ import { Injectable as Injectable20 } from "@nestjs/common";
4669
5045
  var IntentRegistrySensor = class {
4670
5046
  constructor(router) {
4671
5047
  this.router = router;
@@ -4688,12 +5064,12 @@ var IntentRegistrySensor = class {
4688
5064
  }
4689
5065
  };
4690
5066
  IntentRegistrySensor = __decorateClass([
4691
- Injectable19(),
5067
+ Injectable20(),
4692
5068
  Sensor({ phase: "POST_DECODE" })
4693
5069
  ], IntentRegistrySensor);
4694
5070
 
4695
5071
  // src/sensors/proof-presence.sensor.ts
4696
- import { Injectable as Injectable20 } from "@nestjs/common";
5072
+ import { Injectable as Injectable21 } from "@nestjs/common";
4697
5073
  var ProofPresenceSensor = class {
4698
5074
  constructor() {
4699
5075
  this.name = "ProofPresenceSensor";
@@ -4741,11 +5117,11 @@ var ProofPresenceSensor = class {
4741
5117
  };
4742
5118
  ProofPresenceSensor = __decorateClass([
4743
5119
  Sensor(),
4744
- Injectable20()
5120
+ Injectable21()
4745
5121
  ], ProofPresenceSensor);
4746
5122
 
4747
5123
  // src/sensors/protocol-strict.sensor.ts
4748
- import { Injectable as Injectable21, Logger as Logger11 } from "@nestjs/common";
5124
+ import { Injectable as Injectable22, Logger as Logger12 } from "@nestjs/common";
4749
5125
  var VALID_FLAGS = [
4750
5126
  0,
4751
5127
  // No flags
@@ -4763,7 +5139,7 @@ var VALID_FLAGS = [
4763
5139
  var ProtocolStrictSensor = class {
4764
5140
  constructor(config) {
4765
5141
  this.config = config;
4766
- this.logger = new Logger11(ProtocolStrictSensor.name);
5142
+ this.logger = new Logger12(ProtocolStrictSensor.name);
4767
5143
  /** Sensor identifier for logging and registry */
4768
5144
  this.name = "ProtocolStrictSensor";
4769
5145
  /**
@@ -5016,11 +5392,11 @@ var ProtocolStrictSensor = class {
5016
5392
  };
5017
5393
  ProtocolStrictSensor = __decorateClass([
5018
5394
  Sensor({ phase: "PRE_DECODE" }),
5019
- Injectable21()
5395
+ Injectable22()
5020
5396
  ], ProtocolStrictSensor);
5021
5397
 
5022
5398
  // src/sensors/receipt-policy.sensor.ts
5023
- import { Injectable as Injectable22 } from "@nestjs/common";
5399
+ import { Injectable as Injectable23 } from "@nestjs/common";
5024
5400
  var ReceiptPolicySensor = class {
5025
5401
  constructor() {
5026
5402
  this.name = "ReceiptPolicySensor";
@@ -5034,12 +5410,12 @@ var ReceiptPolicySensor = class {
5034
5410
  }
5035
5411
  };
5036
5412
  ReceiptPolicySensor = __decorateClass([
5037
- Injectable22(),
5413
+ Injectable23(),
5038
5414
  Sensor()
5039
5415
  ], ReceiptPolicySensor);
5040
5416
 
5041
5417
  // src/sensors/schema-validation.sensor.ts
5042
- import { Injectable as Injectable23 } from "@nestjs/common";
5418
+ import { Injectable as Injectable24 } from "@nestjs/common";
5043
5419
  function readU64be(b) {
5044
5420
  if (b.length !== 8)
5045
5421
  throw new AxisError("SCHEMA_TYPE_MISMATCH", "u64 must be 8 bytes", 400);
@@ -5214,11 +5590,11 @@ var SchemaValidationSensor = class {
5214
5590
  };
5215
5591
  SchemaValidationSensor = __decorateClass([
5216
5592
  Sensor(),
5217
- Injectable23()
5593
+ Injectable24()
5218
5594
  ], SchemaValidationSensor);
5219
5595
 
5220
5596
  // src/sensors/stream-scope.sensor.ts
5221
- import { Injectable as Injectable24 } from "@nestjs/common";
5597
+ import { Injectable as Injectable25 } from "@nestjs/common";
5222
5598
  var StreamScopeSensor = class {
5223
5599
  constructor() {
5224
5600
  /** Sensor identifier */
@@ -5264,11 +5640,11 @@ var StreamScopeSensor = class {
5264
5640
  };
5265
5641
  StreamScopeSensor = __decorateClass([
5266
5642
  Sensor(),
5267
- Injectable24()
5643
+ Injectable25()
5268
5644
  ], StreamScopeSensor);
5269
5645
 
5270
5646
  // src/sensors/tlv-parse.sensor.ts
5271
- import { Injectable as Injectable25 } from "@nestjs/common";
5647
+ import { Injectable as Injectable26 } from "@nestjs/common";
5272
5648
  var TLVParseSensor = class {
5273
5649
  constructor() {
5274
5650
  this.name = "TLVParseSensor";
@@ -5370,11 +5746,11 @@ var TLVParseSensor = class {
5370
5746
  };
5371
5747
  TLVParseSensor = __decorateClass([
5372
5748
  Sensor(),
5373
- Injectable25()
5749
+ Injectable26()
5374
5750
  ], TLVParseSensor);
5375
5751
 
5376
5752
  // src/sensors/varint-hardening.sensor.ts
5377
- import { Injectable as Injectable26 } from "@nestjs/common";
5753
+ import { Injectable as Injectable27 } from "@nestjs/common";
5378
5754
  var VarintHardeningSensor = class {
5379
5755
  constructor() {
5380
5756
  /** Sensor identifier */
@@ -5437,7 +5813,7 @@ var VarintHardeningSensor = class {
5437
5813
  };
5438
5814
  VarintHardeningSensor = __decorateClass([
5439
5815
  Sensor({ phase: "PRE_DECODE" }),
5440
- Injectable26()
5816
+ Injectable27()
5441
5817
  ], VarintHardeningSensor);
5442
5818
 
5443
5819
  // src/utils/index.ts
@@ -5508,14 +5884,21 @@ export {
5508
5884
  AXIS_UPLOAD_SESSION_STORE,
5509
5885
  AXIS_VERSION,
5510
5886
  ats1_exports as Ats1Codec,
5887
+ AxisContext,
5888
+ AxisDemoPubkey,
5889
+ AxisError,
5511
5890
  AxisFilesDownloadHandler,
5512
5891
  AxisFilesFinalizeHandler,
5513
5892
  AxisFrameZ,
5514
5893
  AxisIdDto,
5894
+ AxisIp,
5515
5895
  T as AxisPacketTags,
5516
5896
  AxisPartialType,
5897
+ AxisRaw,
5517
5898
  AxisResponseDto,
5899
+ AxisSensorChainService,
5518
5900
  AxisTlvDto,
5901
+ BAND,
5519
5902
  BodyProfile,
5520
5903
  CAPABILITIES,
5521
5904
  ContractViolationError,
@@ -5533,7 +5916,10 @@ export {
5533
5916
  FLAG_CHAIN_REQ,
5534
5917
  FLAG_HAS_WITNESS,
5535
5918
  HANDLER_METADATA_KEY,
5919
+ HANDLER_SENSORS_KEY,
5536
5920
  Handler,
5921
+ HandlerDiscoveryService,
5922
+ HandlerSensors,
5537
5923
  INTENT_BODY_KEY,
5538
5924
  INTENT_METADATA_KEY,
5539
5925
  INTENT_REQUIREMENTS,
@@ -5560,6 +5946,7 @@ export {
5560
5946
  NCERT_PUB,
5561
5947
  NCERT_SCOPE,
5562
5948
  NCERT_SIG,
5949
+ PRE_DECODE_BOUNDARY,
5563
5950
  PROOF_CAPABILITIES,
5564
5951
  PROOF_CAPSULE,
5565
5952
  PROOF_JWT,
@@ -5574,11 +5961,15 @@ export {
5574
5961
  RESPONSE_TAG_UPDATED_AT,
5575
5962
  RESPONSE_TAG_UPDATED_BY,
5576
5963
  RiskDecision,
5964
+ SENSOR_METADATA_KEY,
5577
5965
  Schema2002_PasskeyLoginOptionsRes,
5578
5966
  Schema2011_PasskeyLoginVerifyReq,
5579
5967
  Schema2012_PasskeyLoginVerifyRes,
5580
5968
  Schema2021_PasskeyRegisterOptionsReq,
5969
+ Sensor,
5581
5970
  SensorDecisions,
5971
+ SensorDiscoveryService,
5972
+ SensorRegistry,
5582
5973
  TLV,
5583
5974
  TLV_ACTOR_ID,
5584
5975
  TLV_AUD,
@@ -5627,21 +6018,26 @@ export {
5627
6018
  buildAts1Hdr,
5628
6019
  buildDtoDecoder,
5629
6020
  buildPacket,
6021
+ buildQueueMessage,
5630
6022
  buildReceiptHash,
5631
6023
  buildTLVs,
6024
+ buildUnsignedWitness,
5632
6025
  bytes,
5633
6026
  canAccessResource,
5634
6027
  canonicalJson,
5635
6028
  canonicalJsonExcluding,
6029
+ canonicalizeObservation,
5636
6030
  classifyIntent,
5637
6031
  computeReceiptHash,
5638
6032
  computeSignaturePayload,
5639
6033
  core_exports as core,
6034
+ createObservation,
5640
6035
  crypto_exports as crypto,
5641
6036
  decodeArray,
5642
6037
  decodeAxis1Frame,
5643
6038
  decodeFrame,
5644
6039
  decodeObject,
6040
+ decodeQueueMessage,
5645
6041
  decodeTLVs,
5646
6042
  decodeTLVsList,
5647
6043
  decodeVarint,
@@ -5649,13 +6045,17 @@ export {
5649
6045
  encVarint,
5650
6046
  encodeAxis1Frame,
5651
6047
  encodeFrame,
6048
+ encodeQueueMessage,
5652
6049
  encodeTLVs,
5653
6050
  encodeVarint,
6051
+ endStage,
5654
6052
  engine_exports as engine,
5655
6053
  extractDtoSchema,
6054
+ finalizeObservation,
5656
6055
  generateEd25519KeyPair,
5657
6056
  getSignTarget,
5658
6057
  hasScope,
6058
+ hashObservation,
5659
6059
  isAdminOpcode,
5660
6060
  isKnownOpcode,
5661
6061
  isTimestampValid,
@@ -5667,7 +6067,10 @@ export {
5667
6067
  packPasskeyLoginVerifyReq,
5668
6068
  packPasskeyLoginVerifyRes,
5669
6069
  packPasskeyRegisterOptionsReq,
6070
+ parseAutoClaimEntries,
5670
6071
  parseScope,
6072
+ parseStreamEntries,
6073
+ recordSensor,
5671
6074
  resolveTimeout,
5672
6075
  schemas_exports as schemas,
5673
6076
  security_exports as security,
@@ -5675,6 +6078,8 @@ export {
5675
6078
  sensors_exports as sensors,
5676
6079
  sha256,
5677
6080
  signFrame,
6081
+ stableJsonStringify,
6082
+ startStage,
5678
6083
  tlv,
5679
6084
  u64be,
5680
6085
  unpackPasskeyLoginOptionsReq,
@@ -5685,6 +6090,7 @@ export {
5685
6090
  validateFrameShape,
5686
6091
  varintLength,
5687
6092
  varintU,
5688
- verifyFrameSignature
6093
+ verifyFrameSignature,
6094
+ verifyResponse
5689
6095
  };
5690
6096
  //# sourceMappingURL=index.mjs.map