@nextera.one/axis-server-sdk 1.4.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,23 @@ 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
+
721
768
  // src/engine/observation/stable-json.ts
722
769
  function normalize(value) {
723
770
  if (Array.isArray(value)) {
@@ -2883,92 +2930,54 @@ var DiskUploadFileStore = class {
2883
2930
  }
2884
2931
  };
2885
2932
 
2886
- // src/core/index.ts
2887
- var core_exports = {};
2888
- __export(core_exports, {
2889
- AXIS_MAGIC: () => AXIS_MAGIC,
2890
- AXIS_VERSION: () => AXIS_VERSION,
2891
- AxisError: () => AxisError,
2892
- AxisFrameZ: () => AxisFrameZ,
2893
- BodyProfile: () => BodyProfile,
2894
- ERR_BAD_SIGNATURE: () => ERR_BAD_SIGNATURE,
2895
- ERR_CONTRACT_VIOLATION: () => ERR_CONTRACT_VIOLATION,
2896
- ERR_INVALID_PACKET: () => ERR_INVALID_PACKET,
2897
- ERR_REPLAY_DETECTED: () => ERR_REPLAY_DETECTED,
2898
- FLAG_BODY_TLV: () => FLAG_BODY_TLV,
2899
- FLAG_CHAIN_REQ: () => FLAG_CHAIN_REQ,
2900
- FLAG_HAS_WITNESS: () => FLAG_HAS_WITNESS,
2901
- MAX_BODY_LEN: () => MAX_BODY_LEN,
2902
- MAX_FRAME_LEN: () => MAX_FRAME_LEN,
2903
- MAX_HDR_LEN: () => MAX_HDR_LEN,
2904
- MAX_SIG_LEN: () => MAX_SIG_LEN,
2905
- NCERT_ALG: () => NCERT_ALG,
2906
- NCERT_EXP: () => NCERT_EXP,
2907
- NCERT_ISSUER_KID: () => NCERT_ISSUER_KID,
2908
- NCERT_KID: () => NCERT_KID,
2909
- NCERT_NBF: () => NCERT_NBF,
2910
- NCERT_NODE_ID: () => NCERT_NODE_ID,
2911
- NCERT_PAYLOAD: () => NCERT_PAYLOAD,
2912
- NCERT_PUB: () => NCERT_PUB,
2913
- NCERT_SCOPE: () => NCERT_SCOPE,
2914
- NCERT_SIG: () => NCERT_SIG,
2915
- PROOF_CAPSULE: () => PROOF_CAPSULE,
2916
- PROOF_JWT: () => PROOF_JWT,
2917
- PROOF_LOOM: () => PROOF_LOOM,
2918
- PROOF_MTLS: () => PROOF_MTLS,
2919
- PROOF_NONE: () => PROOF_NONE,
2920
- PROOF_WITNESS: () => PROOF_WITNESS,
2921
- ProofType: () => ProofType,
2922
- TLV: () => TLV,
2923
- TLV_ACTOR_ID: () => TLV_ACTOR_ID,
2924
- TLV_AUD: () => TLV_AUD,
2925
- TLV_BODY_ARR: () => TLV_BODY_ARR,
2926
- TLV_BODY_OBJ: () => TLV_BODY_OBJ,
2927
- TLV_CAPSULE: () => TLV_CAPSULE,
2928
- TLV_EFFECT: () => TLV_EFFECT,
2929
- TLV_ERROR_CODE: () => TLV_ERROR_CODE,
2930
- TLV_ERROR_MSG: () => TLV_ERROR_MSG,
2931
- TLV_INDEX: () => TLV_INDEX,
2932
- TLV_INTENT: () => TLV_INTENT,
2933
- TLV_KID: () => TLV_KID,
2934
- TLV_LOOM_PRESENCE_ID: () => TLV_LOOM_PRESENCE_ID,
2935
- TLV_LOOM_THREAD_HASH: () => TLV_LOOM_THREAD_HASH,
2936
- TLV_LOOM_WRIT: () => TLV_LOOM_WRIT,
2937
- TLV_NODE: () => TLV_NODE,
2938
- TLV_NODE_CERT_HASH: () => TLV_NODE_CERT_HASH,
2939
- TLV_NODE_KID: () => TLV_NODE_KID,
2940
- TLV_NONCE: () => TLV_NONCE,
2941
- TLV_OFFSET: () => TLV_OFFSET,
2942
- TLV_OK: () => TLV_OK,
2943
- TLV_PID: () => TLV_PID,
2944
- TLV_PREV_HASH: () => TLV_PREV_HASH,
2945
- TLV_PROOF_REF: () => TLV_PROOF_REF,
2946
- TLV_PROOF_TYPE: () => TLV_PROOF_TYPE,
2947
- TLV_REALM: () => TLV_REALM,
2948
- TLV_RECEIPT_HASH: () => TLV_RECEIPT_HASH,
2949
- TLV_RID: () => TLV_RID,
2950
- TLV_SHA256_CHUNK: () => TLV_SHA256_CHUNK,
2951
- TLV_TRACE_ID: () => TLV_TRACE_ID,
2952
- TLV_TS: () => TLV_TS,
2953
- TLV_UPLOAD_ID: () => TLV_UPLOAD_ID,
2954
- computeReceiptHash: () => computeReceiptHash,
2955
- computeSignaturePayload: () => computeSignaturePayload,
2956
- decodeArray: () => decodeArray,
2957
- decodeFrame: () => decodeFrame,
2958
- decodeObject: () => decodeObject,
2959
- decodeTLVs: () => decodeTLVs,
2960
- decodeTLVsList: () => decodeTLVsList,
2961
- decodeVarint: () => decodeVarint,
2962
- encodeFrame: () => encodeFrame,
2963
- encodeTLVs: () => encodeTLVs,
2964
- encodeVarint: () => encodeVarint,
2965
- generateEd25519KeyPair: () => generateEd25519KeyPair,
2966
- getSignTarget: () => getSignTarget,
2967
- sha256: () => sha256,
2968
- signFrame: () => signFrame,
2969
- varintLength: () => varintLength,
2970
- verifyFrameSignature: () => verifyFrameSignature
2971
- });
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
+ );
2972
2981
 
2973
2982
  // src/core/axis-error.ts
2974
2983
  var AxisError = class extends Error {
@@ -2981,342 +2990,240 @@ var AxisError = class extends Error {
2981
2990
  }
2982
2991
  };
2983
2992
 
2984
- // src/crypto/index.ts
2985
- var crypto_exports = {};
2986
- __export(crypto_exports, {
2987
- ProofVerificationService: () => ProofVerificationService,
2988
- b64urlDecode: () => b64urlDecode,
2989
- b64urlDecodeString: () => b64urlDecodeString,
2990
- b64urlEncode: () => b64urlEncode,
2991
- b64urlEncodeString: () => b64urlEncodeString,
2992
- canonicalJson: () => canonicalJson,
2993
- canonicalJsonExcluding: () => canonicalJsonExcluding
2994
- });
2995
-
2996
- // src/crypto/proof-verification.service.ts
2993
+ // src/engine/handler-discovery.service.ts
2997
2994
  import { Injectable as Injectable4, Logger as Logger3 } from "@nestjs/common";
2998
- import * as crypto3 from "crypto";
2999
- import * as nacl from "tweetnacl";
3000
- var ProofVerificationService = class {
3001
- constructor() {
3002
- this.logger = new Logger3(ProofVerificationService.name);
3003
- // Cache of registered device public keys (deviceId -> pubKey)
3004
- this.deviceKeys = /* @__PURE__ */ new Map();
3005
- // Cache of trusted mTLS certificate fingerprints
3006
- 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);
3007
3001
  }
3008
- /**
3009
- * Verifies an authentication proof based on its type.
3010
- *
3011
- * **Supported Types:**
3012
- * - 1 (CAPSULE): Delegated to `verifyCapsuleProof`
3013
- * - 2 (JWT): Verified by `verifyJWTProof`
3014
- * - 3 (MTLS_ID): Verified by `verifyMTLSProof`
3015
- * - 4 (DEVICE_SE): Verified by `verifyDeviceSEProof`
3016
- *
3017
- * @param {ProofType} proofType - The numeric AXIS proof type
3018
- * @param {Uint8Array} proofRef - The binary reference or token for the proof
3019
- * @param {Object} context - Additional metadata required for specific proof types
3020
- * @param {Uint8Array} [context.signTarget] - The canonical bytes that were signed (for Ed25519)
3021
- * @param {Uint8Array} [context.signature] - The signature to verify (for Ed25519)
3022
- * @param {MTLSContext} [context.mtls] - mTLS certificate data
3023
- * @param {DeviceSEContext} [context.deviceSE] - Device Secure Element information
3024
- * @returns {Promise<ProofVerificationResult>} The outcome of the verification
3025
- */
3026
- async verifyProof(proofType, proofRef, context) {
3027
- switch (proofType) {
3028
- case 1:
3029
- return this.verifyCapsuleProof(proofRef);
3030
- case 2:
3031
- return this.verifyJWTProof(proofRef);
3032
- case 3:
3033
- return this.verifyMTLSProof(context.mtls);
3034
- case 4:
3035
- return this.verifyDeviceSEProof(
3036
- context.signTarget,
3037
- context.signature,
3038
- 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
3020
+ );
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
3039
3035
  );
3040
- default:
3041
- return { valid: false, error: `Unknown proof type: ${proofType}` };
3042
- }
3043
- }
3044
- /**
3045
- * Verify CAPSULE proof (delegated to CapsuleService)
3046
- */
3047
- async verifyCapsuleProof(proofRef) {
3048
- const capsuleId = new TextDecoder().decode(proofRef);
3049
- return {
3050
- valid: true,
3051
- metadata: { capsuleId, requiresCapsuleValidation: true }
3052
- };
3053
- }
3054
- /**
3055
- * Verifies a JSON Web Token (JWT) proof.
3056
- *
3057
- * **Validation Logic:**
3058
- * 1. Decodes the token string.
3059
- * 2. Checks for valid 3-part JWT structure.
3060
- * 3. Validates `exp` (expiration) and `nbf` (not before) claims.
3061
- * 4. Extracts `actor_id` or `sub` as the identity.
3062
- *
3063
- * @param {Uint8Array} proofRef - Binary representation of the JWT string
3064
- * @returns {Promise<ProofVerificationResult>} Result including the actor identifier
3065
- */
3066
- async verifyJWTProof(proofRef) {
3067
- try {
3068
- const token = new TextDecoder().decode(proofRef);
3069
- const parts = token.split(".");
3070
- if (parts.length !== 3) {
3071
- return { valid: false, error: "Invalid JWT format" };
3072
- }
3073
- const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
3074
- const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
3075
- if (payload.exp && Date.now() / 1e3 > payload.exp) {
3076
- return { valid: false, error: "JWT expired" };
3077
3036
  }
3078
- if (payload.nbf && Date.now() / 1e3 < payload.nbf) {
3079
- return { valid: false, error: "JWT not yet valid" };
3037
+ if (registered > 0) {
3038
+ this.logger.log(
3039
+ `Auto-registered ${registered} intents from ${handlerName}`
3040
+ );
3080
3041
  }
3081
- return {
3082
- valid: true,
3083
- actorId: payload.sub || payload.actor_id,
3084
- metadata: { iss: payload.iss, scope: payload.scope }
3085
- };
3086
- } catch (e) {
3087
- const message = e instanceof Error ? e.message : "Unknown error";
3088
- return { valid: false, error: `JWT parse error: ${message}` };
3089
3042
  }
3043
+ this.logger.log(
3044
+ `Handler discovery complete: ${totalIntents} intents auto-registered`
3045
+ );
3090
3046
  }
3091
- /**
3092
- * Verify mTLS client certificate proof
3093
- */
3094
- async verifyMTLSProof(mtls) {
3095
- if (!mtls) {
3096
- return { valid: false, error: "No mTLS context provided" };
3097
- }
3098
- if (!mtls.verified) {
3099
- return { valid: false, error: "mTLS not verified by TLS terminator" };
3100
- }
3101
- if (mtls.clientCertFingerprint) {
3102
- const trusted = this.trustedCerts.get(mtls.clientCertFingerprint);
3103
- if (trusted) {
3104
- return {
3105
- valid: true,
3106
- actorId: trusted.actorId,
3107
- metadata: {
3108
- fingerprint: mtls.clientCertFingerprint,
3109
- subject: mtls.clientCertSubject
3110
- }
3111
- };
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);
3060
+ }
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;
3112
3078
  }
3113
- }
3114
- if (mtls.clientCertSubject) {
3115
- const cnMatch = mtls.clientCertSubject.match(/CN=([^,]+)/);
3116
- if (cnMatch) {
3117
- return {
3118
- valid: true,
3119
- actorId: cnMatch[1],
3120
- metadata: {
3121
- subject: mtls.clientCertSubject,
3122
- issuer: mtls.clientCertIssuer
3123
- }
3124
- };
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");
3125
3082
  }
3083
+ this.registry.register(sensor);
3084
+ count++;
3126
3085
  }
3127
- return { valid: false, error: "Could not extract actor from certificate" };
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);
3128
3100
  }
3129
3101
  /**
3130
- * Verify Device Secure Element signature
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
3131
3112
  */
3132
- async verifyDeviceSEProof(signTarget, signature, deviceSE) {
3133
- if (!deviceSE || !signTarget || !signature) {
3134
- return { valid: false, error: "Missing Device SE context" };
3113
+ register(sensor) {
3114
+ if (!sensor.name) {
3115
+ throw new Error("AxisSensor must have a name");
3135
3116
  }
3136
- let publicKey = deviceSE.publicKey;
3137
- const registeredKey = this.deviceKeys.get(deviceSE.deviceId);
3138
- if (registeredKey) {
3139
- publicKey = registeredKey;
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;
3140
3124
  }
3141
- if (!publicKey || publicKey.length !== 32) {
3142
- return {
3143
- valid: false,
3144
- error: "Invalid or unregistered device public key"
3145
- };
3125
+ if (disabledSensors.includes(sensor.name)) {
3126
+ this.logger.log(`Skipping disabled sensor (in DISABLED_SENSORS): ${sensor.name}`);
3127
+ return;
3146
3128
  }
3147
- try {
3148
- const valid = nacl.sign.detached.verify(signTarget, signature, publicKey);
3149
- if (!valid) {
3150
- return { valid: false, error: "Device signature verification failed" };
3151
- }
3152
- return {
3153
- valid: true,
3154
- actorId: deviceSE.deviceId,
3155
- metadata: { deviceId: deviceSE.deviceId, proofType: "DEVICE_SE" }
3156
- };
3157
- } catch (e) {
3158
- const message = e instanceof Error ? e.message : "Unknown error";
3159
- return {
3160
- valid: false,
3161
- error: `Signature verification error: ${message}`
3162
- };
3129
+ if (sensor.order === void 0) {
3130
+ throw new Error(`AxisSensor "${sensor.name}" must have an order field`);
3131
+ }
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
+ );
3163
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
+ );
3164
3149
  }
3165
3150
  /**
3166
- * Registers a public key for a trusted device.
3167
- * This key will be used for future `DEVICE_SE` proof verifications.
3151
+ * Returns all registered sensors, sorted by their execution order.
3168
3152
  *
3169
- * @param {string} deviceId - Unique identifier for the device
3170
- * @param {Uint8Array} publicKey - 32-byte Ed25519 public key
3171
- * @throws {Error} If the public key is not 32 bytes
3153
+ * @returns {AxisSensor[]} A sorted array of sensors
3172
3154
  */
3173
- registerDeviceKey(deviceId, publicKey) {
3174
- if (publicKey.length !== 32) {
3175
- throw new Error("Device public key must be 32 bytes (Ed25519)");
3176
- }
3177
- this.deviceKeys.set(deviceId, publicKey);
3178
- this.logger.log(`Registered device key for ${deviceId}`);
3155
+ list() {
3156
+ return [...this.sensors].sort(
3157
+ (a, b) => (a.order ?? 999) - (b.order ?? 999)
3158
+ );
3179
3159
  }
3180
3160
  /**
3181
- * Unregister a device
3161
+ * Returns only pre-decode sensors (order < 40).
3162
+ * These sensors run in middleware on raw bytes before frame decoding.
3163
+ *
3164
+ * @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
3182
3165
  */
3183
- unregisterDevice(deviceId) {
3184
- return this.deviceKeys.delete(deviceId);
3166
+ getPreDecodeSensors() {
3167
+ return this.list().filter((s) => (s.order ?? 999) < 40);
3185
3168
  }
3186
3169
  /**
3187
- * Registers a trusted mTLS certificate fingerprint and associates it with an actor.
3170
+ * Returns only post-decode sensors (order >= 40).
3171
+ * These sensors run in the controller on fully decoded frames.
3188
3172
  *
3189
- * @param {string} fingerprint - SHA-256 fingerprint of the client certificate
3190
- * @param {string} actorId - The actor to associate with this certificate
3173
+ * @returns {AxisPostSensor[]} Post-decode sensors sorted by order
3191
3174
  */
3192
- registerMTLSCert(fingerprint, actorId) {
3193
- this.trustedCerts.set(fingerprint, { actorId, issuedAt: Date.now() });
3194
- this.logger.log(`Registered mTLS cert ${fingerprint} for actor ${actorId}`);
3175
+ getPostDecodeSensors() {
3176
+ return this.list().filter(
3177
+ (s) => (s.order ?? 999) >= 40
3178
+ );
3195
3179
  }
3196
3180
  /**
3197
- * Revoke an mTLS certificate
3181
+ * Helper: Check if a sensor is a pre-decode sensor.
3182
+ *
3183
+ * @private
3184
+ * @param {AxisSensor} sensor - The sensor to check
3185
+ * @returns {boolean} True if sensor is pre-decode
3198
3186
  */
3199
- revokeMTLSCert(fingerprint) {
3200
- return this.trustedCerts.delete(fingerprint);
3187
+ isPreDecodeSensor(sensor) {
3188
+ const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3189
+ return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
3201
3190
  }
3202
3191
  /**
3203
- * Calculate certificate fingerprint (SHA-256)
3204
- */
3205
- static calculateFingerprint(certPem) {
3206
- const der = Buffer.from(
3207
- certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
3208
- "base64"
3209
- );
3210
- return crypto3.createHash("sha256").update(der).digest("hex");
3211
- }
3212
- };
3213
- ProofVerificationService = __decorateClass([
3214
- Injectable4()
3215
- ], ProofVerificationService);
3216
-
3217
- // src/decorators/index.ts
3218
- var decorators_exports = {};
3219
- __export(decorators_exports, {
3220
- AxisContext: () => AxisContext,
3221
- AxisDemoPubkey: () => AxisDemoPubkey,
3222
- AxisFrame: () => AxisFrame3,
3223
- AxisIp: () => AxisIp,
3224
- AxisRaw: () => AxisRaw,
3225
- HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
3226
- Handler: () => Handler,
3227
- INTENT_BODY_KEY: () => INTENT_BODY_KEY,
3228
- INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
3229
- INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
3230
- INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
3231
- Intent: () => Intent,
3232
- IntentBody: () => IntentBody,
3233
- IntentSensors: () => IntentSensors,
3234
- SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
3235
- Sensor: () => Sensor,
3236
- TLV_FIELDS_KEY: () => TLV_FIELDS_KEY,
3237
- TLV_VALIDATORS_KEY: () => TLV_VALIDATORS_KEY,
3238
- TlvEnum: () => TlvEnum,
3239
- TlvField: () => TlvField,
3240
- TlvMinLen: () => TlvMinLen,
3241
- TlvRange: () => TlvRange,
3242
- TlvUtf8Pattern: () => TlvUtf8Pattern,
3243
- TlvValidate: () => TlvValidate,
3244
- buildDtoDecoder: () => buildDtoDecoder,
3245
- extractDtoSchema: () => extractDtoSchema
3246
- });
3247
-
3248
- // src/decorators/axis-request.decorator.ts
3249
- import { createParamDecorator } from "@nestjs/common";
3250
- function resolveIp(req) {
3251
- return req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress || void 0;
3252
- }
3253
- var AxisRaw = createParamDecorator(
3254
- (_data, ctx) => {
3255
- const req = ctx.switchToHttp().getRequest();
3256
- return req.body;
3257
- }
3258
- );
3259
- var AxisIp = createParamDecorator(
3260
- (_data, ctx) => {
3261
- const req = ctx.switchToHttp().getRequest();
3262
- return resolveIp(req);
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
3197
+ */
3198
+ isPostDecodeSensor(sensor) {
3199
+ const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3200
+ return phase === "POST_DECODE" || (sensor.order ?? 999) >= 40;
3263
3201
  }
3264
- );
3265
- var AxisContext = createParamDecorator(
3266
- (_data, ctx) => {
3267
- const req = ctx.switchToHttp().getRequest();
3268
- const axisData = req.axis || {};
3202
+ /**
3203
+ * Returns sensor count by phase.
3204
+ * Useful for diagnostics and monitoring.
3205
+ *
3206
+ * @returns {{preDecodeCount: number, postDecodeCount: number}}
3207
+ */
3208
+ getSensorCountByPhase() {
3269
3209
  return {
3270
- raw: req.body,
3271
- ip: resolveIp(req),
3272
- preDecodeInput: axisData.preDecodeInput,
3273
- frameBytesCount: axisData.frameBytesCount || 0
3210
+ preDecodeCount: this.getPreDecodeSensors().length,
3211
+ postDecodeCount: this.getPostDecodeSensors().length
3274
3212
  };
3275
3213
  }
3276
- );
3277
- var AxisDemoPubkey = createParamDecorator(
3278
- (_data, ctx) => {
3279
- if (process.env.NODE_ENV !== "development") return void 0;
3280
- const req = ctx.switchToHttp().getRequest();
3281
- return req.headers["x-demo-pubkey"];
3282
- }
3283
- );
3284
- var AxisFrame3 = createParamDecorator(
3285
- (_data, ctx) => {
3286
- const req = ctx.switchToHttp().getRequest();
3287
- const decoded = req.axisDecoded;
3288
- if (!decoded) {
3289
- throw new Error(
3290
- "@AxisFrame() requires AxisDecodeInterceptor on the route. Add @UseInterceptors(AxisDecodeInterceptor) to use this decorator."
3291
- );
3292
- }
3293
- return decoded;
3214
+ /**
3215
+ * Clears all registered sensors.
3216
+ * Useful for testing.
3217
+ *
3218
+ * @internal
3219
+ */
3220
+ clear() {
3221
+ this.sensors = [];
3294
3222
  }
3295
- );
3296
-
3297
- // src/decorators/sensor.decorator.ts
3298
- import { SetMetadata as SetMetadata2 } from "@nestjs/common";
3299
- var SENSOR_METADATA_KEY = "axis:sensor";
3300
- function Sensor(options) {
3301
- return SetMetadata2(SENSOR_METADATA_KEY, options ?? true);
3302
- }
3303
-
3304
- // src/engine/index.ts
3305
- var engine_exports = {};
3306
- __export(engine_exports, {
3307
- BAND: () => BAND,
3308
- HandlerDiscoveryService: () => HandlerDiscoveryService,
3309
- IntentRouter: () => IntentRouter,
3310
- PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
3311
- SensorDiscoveryService: () => SensorDiscoveryService,
3312
- SensorRegistry: () => SensorRegistry,
3313
- createObservation: () => createObservation,
3314
- endStage: () => endStage,
3315
- finalizeObservation: () => finalizeObservation,
3316
- observation: () => observation_exports,
3317
- recordSensor: () => recordSensor,
3318
- startStage: () => startStage
3319
- });
3223
+ };
3224
+ SensorRegistry = __decorateClass([
3225
+ Injectable6()
3226
+ ], SensorRegistry);
3320
3227
 
3321
3228
  // src/engine/axis-observation.ts
3322
3229
  import { randomBytes as randomBytes3 } from "crypto";
@@ -3354,251 +3261,499 @@ function finalizeObservation(obs, decision, statusCode, resultCode) {
3354
3261
  if (resultCode) obs.resultCode = resultCode;
3355
3262
  }
3356
3263
 
3357
- // src/engine/handler-discovery.service.ts
3358
- import { Injectable as Injectable5, Logger as Logger4 } from "@nestjs/common";
3359
- var HandlerDiscoveryService = class {
3360
- constructor(discovery, scanner, router) {
3361
- this.discovery = discovery;
3362
- this.scanner = scanner;
3363
- this.router = router;
3364
- 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;
3365
3269
  }
3366
- onModuleInit() {
3367
- const providers = this.discovery.getProviders();
3368
- let totalIntents = 0;
3369
- for (const wrapper of providers) {
3370
- const { instance, metatype } = wrapper;
3371
- if (!instance || !metatype) continue;
3372
- const handlerMeta = Reflect.getMetadata(HANDLER_METADATA_KEY, metatype);
3373
- if (!handlerMeta) continue;
3374
- const handlerName = handlerMeta.intent || metatype.name;
3375
- const proto = Object.getPrototypeOf(instance);
3376
- const methods = this.scanner.getAllMethodNames(proto);
3377
- let registered = 0;
3378
- for (const methodName of methods) {
3379
- const meta = Reflect.getMetadata(
3380
- INTENT_METADATA_KEY,
3381
- proto,
3382
- methodName
3383
- );
3384
- if (!meta?.intent) continue;
3385
- if (!this.router.has(meta.intent)) {
3386
- this.router.register(
3387
- meta.intent,
3388
- instance[methodName].bind(instance)
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
+ );
3289
+ }
3290
+ return this.evaluateSensors(
3291
+ this.registry.getPostDecodeSensors(),
3292
+ input,
3293
+ baseDecision
3294
+ );
3295
+ }
3296
+ /** Run only pre-decode sensors. */
3297
+ async evaluatePre(input) {
3298
+ return this.evaluateSensors(this.registry.getPreDecodeSensors(), input);
3299
+ }
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
3389
3334
  );
3390
- registered++;
3391
- totalIntents++;
3392
3335
  }
3393
- this.router.registerIntentMeta(meta.intent, proto, methodName);
3394
- }
3395
- if (registered > 0) {
3396
- this.logger.log(
3397
- `Auto-registered ${registered} intents from ${handlerName}`
3398
- );
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
+ };
3399
3371
  }
3400
3372
  }
3401
- this.logger.log(
3402
- `Handler discovery complete: ${totalIntents} intents auto-registered`
3403
- );
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
+ };
3404
3384
  }
3405
3385
  };
3406
- HandlerDiscoveryService = __decorateClass([
3407
- Injectable5()
3408
- ], HandlerDiscoveryService);
3386
+ AxisSensorChainService = __decorateClass([
3387
+ Injectable7()
3388
+ ], AxisSensorChainService);
3409
3389
 
3410
- // src/engine/sensor-bands.ts
3411
- var BAND = {
3412
- /** Pre-decode: raw byte validation, geo, budget, magic */
3413
- WIRE: 0,
3414
- /** Post-decode: identity resolution, capsule, proof */
3415
- IDENTITY: 40,
3416
- /** Post-decode: authorization, signature, rate limiting */
3417
- POLICY: 90,
3418
- /** Post-decode: content validation, TLV, schema, files */
3419
- CONTENT: 140,
3420
- /** Post-decode: business logic sensors, streams, WS */
3421
- BUSINESS: 200,
3422
- /** Post-decode: audit, logging (always last) */
3423
- AUDIT: 900
3424
- };
3425
- var PRE_DECODE_BOUNDARY = 40;
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
+ });
3426
3476
 
3427
- // src/engine/sensor-discovery.service.ts
3428
- import { Injectable as Injectable6, Logger as Logger5 } from "@nestjs/common";
3429
- var SensorDiscoveryService = class {
3430
- constructor(discovery, reflector, registry) {
3431
- this.discovery = discovery;
3432
- this.reflector = reflector;
3433
- this.registry = registry;
3434
- this.logger = new Logger5(SensorDiscoveryService.name);
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();
3435
3500
  }
3436
- onApplicationBootstrap() {
3437
- const providers = this.discovery.getProviders();
3438
- let count = 0;
3439
- for (const wrapper of providers) {
3440
- const { instance } = wrapper;
3441
- if (!instance || !instance.constructor) continue;
3442
- const meta = this.reflector.get(
3443
- SENSOR_METADATA_KEY,
3444
- instance.constructor
3445
- );
3446
- if (!meta) continue;
3447
- const sensor = instance;
3448
- if (!sensor.name || sensor.order === void 0) {
3449
- this.logger.warn(
3450
- `@Sensor() on ${instance.constructor.name} missing name or order \u2014 skipped`
3501
+ /**
3502
+ * Verifies an authentication proof based on its type.
3503
+ *
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`
3509
+ *
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
3518
+ */
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
3451
3532
  );
3452
- continue;
3453
- }
3454
- if (!sensor.phase) {
3455
- const decoratorPhase = meta !== true ? meta.phase : void 0;
3456
- sensor.phase = decoratorPhase ?? (sensor.order < PRE_DECODE_BOUNDARY ? "PRE_DECODE" : "POST_DECODE");
3457
- }
3458
- this.registry.register(sensor);
3459
- count++;
3533
+ default:
3534
+ return { valid: false, error: `Unknown proof type: ${proofType}` };
3460
3535
  }
3461
- this.logger.log(`Auto-registered ${count} sensors via @Sensor()`);
3462
3536
  }
3463
- };
3464
- SensorDiscoveryService = __decorateClass([
3465
- Injectable6()
3466
- ], SensorDiscoveryService);
3467
-
3468
- // src/engine/registry/sensor.registry.ts
3469
- import { Injectable as Injectable7, Logger as Logger6 } from "@nestjs/common";
3470
- var SensorRegistry = class {
3471
- constructor(configService) {
3472
- this.configService = configService;
3473
- this.sensors = [];
3474
- this.logger = new Logger6(SensorRegistry.name);
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
+ };
3475
3546
  }
3476
3547
  /**
3477
- * Registers a new sensor in the registry.
3548
+ * Verifies a JSON Web Token (JWT) proof.
3478
3549
  *
3479
- * Validates that:
3480
- * - AxisSensor has a unique name
3481
- * - AxisSensor has an order field
3482
- * - Pre-decode sensors have order < 40
3483
- * - Post-decode sensors have order >= 40
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.
3484
3555
  *
3485
- * @param {AxisSensor} sensor - The sensor instance to register
3486
- * @throws Error if validation fails
3556
+ * @param {Uint8Array} proofRef - Binary representation of the JWT string
3557
+ * @returns {Promise<ProofVerificationResult>} Result including the actor identifier
3487
3558
  */
3488
- register(sensor) {
3489
- if (!sensor.name) {
3490
- throw new Error("AxisSensor must have a name");
3491
- }
3492
- const enabledSensorsStr = this.configService.get("ENABLED_SENSORS");
3493
- const disabledSensorsStr = this.configService.get("DISABLED_SENSORS");
3494
- const enabledSensors = enabledSensorsStr ? enabledSensorsStr.split(",").map((s) => s.trim()) : null;
3495
- const disabledSensors = disabledSensorsStr ? disabledSensorsStr.split(",").map((s) => s.trim()) : [];
3496
- if (enabledSensors && !enabledSensors.includes(sensor.name)) {
3497
- this.logger.log(`Skipping disabled sensor (not in ENABLED_SENSORS): ${sensor.name}`);
3498
- return;
3499
- }
3500
- if (disabledSensors.includes(sensor.name)) {
3501
- this.logger.log(`Skipping disabled sensor (in DISABLED_SENSORS): ${sensor.name}`);
3502
- return;
3503
- }
3504
- if (sensor.order === void 0) {
3505
- throw new Error(`AxisSensor "${sensor.name}" must have an order field`);
3506
- }
3507
- const isPreDecodeSensor = this.isPreDecodeSensor(sensor);
3508
- const isPostDecodeSensor = this.isPostDecodeSensor(sensor);
3509
- if (isPreDecodeSensor && sensor.order >= 40) {
3510
- this.logger.warn(
3511
- `AxisSensor "${sensor.name}" is marked as PRE_DECODE but has order ${sensor.order} (should be < 40)`
3512
- );
3513
- }
3514
- if (isPostDecodeSensor && sensor.order < 40) {
3515
- this.logger.warn(
3516
- `AxisSensor "${sensor.name}" is marked as POST_DECODE but has order ${sensor.order} (should be >= 40)`
3517
- );
3518
- }
3519
- this.sensors.push(sensor);
3520
- const phaseLabel = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase || "UNKNOWN";
3521
- this.logger.debug(
3522
- `Registered sensor: ${sensor.name} (order: ${sensor.order}, phase: ${phaseLabel})`
3523
- );
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}` };
3582
+ }
3524
3583
  }
3525
3584
  /**
3526
- * Returns all registered sensors, sorted by their execution order.
3527
- *
3528
- * @returns {AxisSensor[]} A sorted array of sensors
3585
+ * Verify mTLS client certificate proof
3529
3586
  */
3530
- list() {
3531
- return [...this.sensors].sort(
3532
- (a, b) => (a.order ?? 999) - (b.order ?? 999)
3533
- );
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" };
3534
3621
  }
3535
3622
  /**
3536
- * Returns only pre-decode sensors (order < 40).
3537
- * These sensors run in middleware on raw bytes before frame decoding.
3538
- *
3539
- * @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
3623
+ * Verify Device Secure Element signature
3540
3624
  */
3541
- getPreDecodeSensors() {
3542
- 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
+ }
3543
3657
  }
3544
3658
  /**
3545
- * Returns only post-decode sensors (order >= 40).
3546
- * 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.
3547
3661
  *
3548
- * @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
3549
3665
  */
3550
- getPostDecodeSensors() {
3551
- return this.list().filter(
3552
- (s) => (s.order ?? 999) >= 40
3553
- );
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}`);
3554
3672
  }
3555
3673
  /**
3556
- * Helper: Check if a sensor is a pre-decode sensor.
3557
- *
3558
- * @private
3559
- * @param {AxisSensor} sensor - The sensor to check
3560
- * @returns {boolean} True if sensor is pre-decode
3674
+ * Unregister a device
3561
3675
  */
3562
- isPreDecodeSensor(sensor) {
3563
- const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3564
- return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
3676
+ unregisterDevice(deviceId) {
3677
+ return this.deviceKeys.delete(deviceId);
3565
3678
  }
3566
3679
  /**
3567
- * Helper: Check if a sensor is a post-decode sensor.
3680
+ * Registers a trusted mTLS certificate fingerprint and associates it with an actor.
3568
3681
  *
3569
- * @private
3570
- * @param {AxisSensor} sensor - The sensor to check
3571
- * @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
3572
3684
  */
3573
- isPostDecodeSensor(sensor) {
3574
- const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
3575
- 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}`);
3576
3688
  }
3577
3689
  /**
3578
- * Returns sensor count by phase.
3579
- * Useful for diagnostics and monitoring.
3580
- *
3581
- * @returns {{preDecodeCount: number, postDecodeCount: number}}
3690
+ * Revoke an mTLS certificate
3582
3691
  */
3583
- getSensorCountByPhase() {
3584
- return {
3585
- preDecodeCount: this.getPreDecodeSensors().length,
3586
- postDecodeCount: this.getPostDecodeSensors().length
3587
- };
3692
+ revokeMTLSCert(fingerprint) {
3693
+ return this.trustedCerts.delete(fingerprint);
3588
3694
  }
3589
3695
  /**
3590
- * Clears all registered sensors.
3591
- * Useful for testing.
3592
- *
3593
- * @internal
3696
+ * Calculate certificate fingerprint (SHA-256)
3594
3697
  */
3595
- clear() {
3596
- 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");
3597
3704
  }
3598
3705
  };
3599
- SensorRegistry = __decorateClass([
3600
- Injectable7()
3601
- ], 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
+ });
3602
3757
 
3603
3758
  // src/engine/observation/index.ts
3604
3759
  var observation_exports = {};
@@ -3983,7 +4138,7 @@ var AxisErrorZ = z2.object({
3983
4138
  });
3984
4139
 
3985
4140
  // src/schemas/body-profile.validator.ts
3986
- import { Injectable as Injectable8, Logger as Logger7 } from "@nestjs/common";
4141
+ import { Injectable as Injectable9, Logger as Logger8 } from "@nestjs/common";
3987
4142
  var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
3988
4143
  BodyProfile3[BodyProfile3["RAW"] = 0] = "RAW";
3989
4144
  BodyProfile3[BodyProfile3["TLV_MAP"] = 1] = "TLV_MAP";
@@ -3993,7 +4148,7 @@ var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
3993
4148
  })(BodyProfile2 || {});
3994
4149
  var BodyProfileValidator = class {
3995
4150
  constructor() {
3996
- this.logger = new Logger7(BodyProfileValidator.name);
4151
+ this.logger = new Logger8(BodyProfileValidator.name);
3997
4152
  }
3998
4153
  /**
3999
4154
  * Validate body matches declared profile
@@ -4109,12 +4264,13 @@ var BodyProfileValidator = class {
4109
4264
  }
4110
4265
  };
4111
4266
  BodyProfileValidator = __decorateClass([
4112
- Injectable8()
4267
+ Injectable9()
4113
4268
  ], BodyProfileValidator);
4114
4269
 
4115
4270
  // src/security/index.ts
4116
4271
  var security_exports = {};
4117
4272
  __export(security_exports, {
4273
+ AxisSensorChainService: () => AxisSensorChainService,
4118
4274
  CAPABILITIES: () => CAPABILITIES,
4119
4275
  INTENT_REQUIREMENTS: () => INTENT_REQUIREMENTS,
4120
4276
  PROOF_CAPABILITIES: () => PROOF_CAPABILITIES,
@@ -4147,7 +4303,7 @@ __export(sensors_exports, {
4147
4303
  });
4148
4304
 
4149
4305
  // src/sensors/access-profile-resolver.sensor.ts
4150
- import { Injectable as Injectable9 } from "@nestjs/common";
4306
+ import { Injectable as Injectable10 } from "@nestjs/common";
4151
4307
  var AccessProfileResolverSensor = class {
4152
4308
  constructor() {
4153
4309
  /** AxisSensor identifier */
@@ -4173,11 +4329,11 @@ var AccessProfileResolverSensor = class {
4173
4329
  };
4174
4330
  AccessProfileResolverSensor = __decorateClass([
4175
4331
  Sensor(),
4176
- Injectable9()
4332
+ Injectable10()
4177
4333
  ], AccessProfileResolverSensor);
4178
4334
 
4179
4335
  // src/sensors/body-budget.sensor.ts
4180
- import { Injectable as Injectable10 } from "@nestjs/common";
4336
+ import { Injectable as Injectable11 } from "@nestjs/common";
4181
4337
  var BodyBudgetSensor = class {
4182
4338
  constructor() {
4183
4339
  /** AxisSensor identifier */
@@ -4251,14 +4407,14 @@ var BodyBudgetSensor = class {
4251
4407
  };
4252
4408
  BodyBudgetSensor = __decorateClass([
4253
4409
  Sensor(),
4254
- Injectable10()
4410
+ Injectable11()
4255
4411
  ], BodyBudgetSensor);
4256
4412
 
4257
4413
  // src/sensors/capability-enforcement.sensor.ts
4258
- import { Injectable as Injectable11, Logger as Logger8 } from "@nestjs/common";
4414
+ import { Injectable as Injectable12, Logger as Logger9 } from "@nestjs/common";
4259
4415
  var CapabilityEnforcementSensor = class {
4260
4416
  constructor() {
4261
- this.logger = new Logger8(CapabilityEnforcementSensor.name);
4417
+ this.logger = new Logger9(CapabilityEnforcementSensor.name);
4262
4418
  /** AxisSensor identifier for logging and registry */
4263
4419
  this.name = "CapabilityEnforcementSensor";
4264
4420
  /**
@@ -4352,11 +4508,11 @@ var CapabilityEnforcementSensor = class {
4352
4508
  };
4353
4509
  CapabilityEnforcementSensor = __decorateClass([
4354
4510
  Sensor(),
4355
- Injectable11()
4511
+ Injectable12()
4356
4512
  ], CapabilityEnforcementSensor);
4357
4513
 
4358
4514
  // src/sensors/chunk-hash.sensor.ts
4359
- import { Injectable as Injectable12 } from "@nestjs/common";
4515
+ import { Injectable as Injectable13 } from "@nestjs/common";
4360
4516
  import { createHash as createHash7 } from "crypto";
4361
4517
  var ChunkHashSensor = class {
4362
4518
  constructor() {
@@ -4429,15 +4585,15 @@ var ChunkHashSensor = class {
4429
4585
  };
4430
4586
  ChunkHashSensor = __decorateClass([
4431
4587
  Sensor(),
4432
- Injectable12()
4588
+ Injectable13()
4433
4589
  ], ChunkHashSensor);
4434
4590
 
4435
4591
  // src/sensors/entropy.sensor.ts
4436
- import { Injectable as Injectable13, Logger as Logger9 } from "@nestjs/common";
4592
+ import { Injectable as Injectable14, Logger as Logger10 } from "@nestjs/common";
4437
4593
  import * as crypto4 from "crypto";
4438
4594
  var EntropySensor = class {
4439
4595
  constructor() {
4440
- this.logger = new Logger9(EntropySensor.name);
4596
+ this.logger = new Logger10(EntropySensor.name);
4441
4597
  /**
4442
4598
  * Minimum acceptable entropy in bits per byte.
4443
4599
  *
@@ -4607,14 +4763,14 @@ var EntropySensor = class {
4607
4763
  };
4608
4764
  EntropySensor = __decorateClass([
4609
4765
  Sensor(),
4610
- Injectable13()
4766
+ Injectable14()
4611
4767
  ], EntropySensor);
4612
4768
 
4613
4769
  // src/sensors/execution-timeout.sensor.ts
4614
- import { Injectable as Injectable14, Logger as Logger10 } from "@nestjs/common";
4770
+ import { Injectable as Injectable15, Logger as Logger11 } from "@nestjs/common";
4615
4771
  var ExecutionTimeoutSensor = class {
4616
4772
  constructor() {
4617
- this.logger = new Logger10(ExecutionTimeoutSensor.name);
4773
+ this.logger = new Logger11(ExecutionTimeoutSensor.name);
4618
4774
  /** AxisSensor identifier */
4619
4775
  this.name = "ExecutionTimeoutSensor";
4620
4776
  /**
@@ -4692,11 +4848,11 @@ var ExecutionTimeoutSensor = class {
4692
4848
  };
4693
4849
  ExecutionTimeoutSensor = __decorateClass([
4694
4850
  Sensor(),
4695
- Injectable14()
4851
+ Injectable15()
4696
4852
  ], ExecutionTimeoutSensor);
4697
4853
 
4698
4854
  // src/sensors/frame-budget.sensor.ts
4699
- import { Injectable as Injectable15 } from "@nestjs/common";
4855
+ import { Injectable as Injectable16 } from "@nestjs/common";
4700
4856
  var FrameBudgetSensor = class {
4701
4857
  constructor(config) {
4702
4858
  this.config = config;
@@ -4755,11 +4911,11 @@ var FrameBudgetSensor = class {
4755
4911
  };
4756
4912
  FrameBudgetSensor = __decorateClass([
4757
4913
  Sensor({ phase: "PRE_DECODE" }),
4758
- Injectable15()
4914
+ Injectable16()
4759
4915
  ], FrameBudgetSensor);
4760
4916
 
4761
4917
  // src/sensors/frame-header-sanity.sensor.ts
4762
- import { Injectable as Injectable16 } from "@nestjs/common";
4918
+ import { Injectable as Injectable17 } from "@nestjs/common";
4763
4919
  var FrameHeaderSanitySensor = class {
4764
4920
  constructor() {
4765
4921
  this.name = "FrameHeaderSanitySensor";
@@ -4803,12 +4959,12 @@ var FrameHeaderSanitySensor = class {
4803
4959
  }
4804
4960
  };
4805
4961
  FrameHeaderSanitySensor = __decorateClass([
4806
- Injectable16(),
4962
+ Injectable17(),
4807
4963
  Sensor({ phase: "PRE_DECODE" })
4808
4964
  ], FrameHeaderSanitySensor);
4809
4965
 
4810
4966
  // src/sensors/header-tlv-limit.sensor.ts
4811
- import { Injectable as Injectable17 } from "@nestjs/common";
4967
+ import { Injectable as Injectable18 } from "@nestjs/common";
4812
4968
  var HeaderTLVLimitSensor = class {
4813
4969
  constructor() {
4814
4970
  this.name = "HeaderTLVLimitSensor";
@@ -4840,12 +4996,12 @@ var HeaderTLVLimitSensor = class {
4840
4996
  }
4841
4997
  };
4842
4998
  HeaderTLVLimitSensor = __decorateClass([
4843
- Injectable17(),
4999
+ Injectable18(),
4844
5000
  Sensor()
4845
5001
  ], HeaderTLVLimitSensor);
4846
5002
 
4847
5003
  // src/sensors/intent-allowlist.sensor.ts
4848
- import { Injectable as Injectable18 } from "@nestjs/common";
5004
+ import { Injectable as Injectable19 } from "@nestjs/common";
4849
5005
  var PUBLIC_INTENT_ALLOWLIST = [
4850
5006
  "public.",
4851
5007
  "schema.",
@@ -4880,12 +5036,12 @@ var IntentAllowlistSensor = class {
4880
5036
  }
4881
5037
  };
4882
5038
  IntentAllowlistSensor = __decorateClass([
4883
- Injectable18(),
5039
+ Injectable19(),
4884
5040
  Sensor()
4885
5041
  ], IntentAllowlistSensor);
4886
5042
 
4887
5043
  // src/sensors/intent-registry.sensor.ts
4888
- import { Injectable as Injectable19 } from "@nestjs/common";
5044
+ import { Injectable as Injectable20 } from "@nestjs/common";
4889
5045
  var IntentRegistrySensor = class {
4890
5046
  constructor(router) {
4891
5047
  this.router = router;
@@ -4908,12 +5064,12 @@ var IntentRegistrySensor = class {
4908
5064
  }
4909
5065
  };
4910
5066
  IntentRegistrySensor = __decorateClass([
4911
- Injectable19(),
5067
+ Injectable20(),
4912
5068
  Sensor({ phase: "POST_DECODE" })
4913
5069
  ], IntentRegistrySensor);
4914
5070
 
4915
5071
  // src/sensors/proof-presence.sensor.ts
4916
- import { Injectable as Injectable20 } from "@nestjs/common";
5072
+ import { Injectable as Injectable21 } from "@nestjs/common";
4917
5073
  var ProofPresenceSensor = class {
4918
5074
  constructor() {
4919
5075
  this.name = "ProofPresenceSensor";
@@ -4961,11 +5117,11 @@ var ProofPresenceSensor = class {
4961
5117
  };
4962
5118
  ProofPresenceSensor = __decorateClass([
4963
5119
  Sensor(),
4964
- Injectable20()
5120
+ Injectable21()
4965
5121
  ], ProofPresenceSensor);
4966
5122
 
4967
5123
  // src/sensors/protocol-strict.sensor.ts
4968
- import { Injectable as Injectable21, Logger as Logger11 } from "@nestjs/common";
5124
+ import { Injectable as Injectable22, Logger as Logger12 } from "@nestjs/common";
4969
5125
  var VALID_FLAGS = [
4970
5126
  0,
4971
5127
  // No flags
@@ -4983,7 +5139,7 @@ var VALID_FLAGS = [
4983
5139
  var ProtocolStrictSensor = class {
4984
5140
  constructor(config) {
4985
5141
  this.config = config;
4986
- this.logger = new Logger11(ProtocolStrictSensor.name);
5142
+ this.logger = new Logger12(ProtocolStrictSensor.name);
4987
5143
  /** Sensor identifier for logging and registry */
4988
5144
  this.name = "ProtocolStrictSensor";
4989
5145
  /**
@@ -5236,11 +5392,11 @@ var ProtocolStrictSensor = class {
5236
5392
  };
5237
5393
  ProtocolStrictSensor = __decorateClass([
5238
5394
  Sensor({ phase: "PRE_DECODE" }),
5239
- Injectable21()
5395
+ Injectable22()
5240
5396
  ], ProtocolStrictSensor);
5241
5397
 
5242
5398
  // src/sensors/receipt-policy.sensor.ts
5243
- import { Injectable as Injectable22 } from "@nestjs/common";
5399
+ import { Injectable as Injectable23 } from "@nestjs/common";
5244
5400
  var ReceiptPolicySensor = class {
5245
5401
  constructor() {
5246
5402
  this.name = "ReceiptPolicySensor";
@@ -5254,12 +5410,12 @@ var ReceiptPolicySensor = class {
5254
5410
  }
5255
5411
  };
5256
5412
  ReceiptPolicySensor = __decorateClass([
5257
- Injectable22(),
5413
+ Injectable23(),
5258
5414
  Sensor()
5259
5415
  ], ReceiptPolicySensor);
5260
5416
 
5261
5417
  // src/sensors/schema-validation.sensor.ts
5262
- import { Injectable as Injectable23 } from "@nestjs/common";
5418
+ import { Injectable as Injectable24 } from "@nestjs/common";
5263
5419
  function readU64be(b) {
5264
5420
  if (b.length !== 8)
5265
5421
  throw new AxisError("SCHEMA_TYPE_MISMATCH", "u64 must be 8 bytes", 400);
@@ -5434,11 +5590,11 @@ var SchemaValidationSensor = class {
5434
5590
  };
5435
5591
  SchemaValidationSensor = __decorateClass([
5436
5592
  Sensor(),
5437
- Injectable23()
5593
+ Injectable24()
5438
5594
  ], SchemaValidationSensor);
5439
5595
 
5440
5596
  // src/sensors/stream-scope.sensor.ts
5441
- import { Injectable as Injectable24 } from "@nestjs/common";
5597
+ import { Injectable as Injectable25 } from "@nestjs/common";
5442
5598
  var StreamScopeSensor = class {
5443
5599
  constructor() {
5444
5600
  /** Sensor identifier */
@@ -5484,11 +5640,11 @@ var StreamScopeSensor = class {
5484
5640
  };
5485
5641
  StreamScopeSensor = __decorateClass([
5486
5642
  Sensor(),
5487
- Injectable24()
5643
+ Injectable25()
5488
5644
  ], StreamScopeSensor);
5489
5645
 
5490
5646
  // src/sensors/tlv-parse.sensor.ts
5491
- import { Injectable as Injectable25 } from "@nestjs/common";
5647
+ import { Injectable as Injectable26 } from "@nestjs/common";
5492
5648
  var TLVParseSensor = class {
5493
5649
  constructor() {
5494
5650
  this.name = "TLVParseSensor";
@@ -5590,11 +5746,11 @@ var TLVParseSensor = class {
5590
5746
  };
5591
5747
  TLVParseSensor = __decorateClass([
5592
5748
  Sensor(),
5593
- Injectable25()
5749
+ Injectable26()
5594
5750
  ], TLVParseSensor);
5595
5751
 
5596
5752
  // src/sensors/varint-hardening.sensor.ts
5597
- import { Injectable as Injectable26 } from "@nestjs/common";
5753
+ import { Injectable as Injectable27 } from "@nestjs/common";
5598
5754
  var VarintHardeningSensor = class {
5599
5755
  constructor() {
5600
5756
  /** Sensor identifier */
@@ -5657,7 +5813,7 @@ var VarintHardeningSensor = class {
5657
5813
  };
5658
5814
  VarintHardeningSensor = __decorateClass([
5659
5815
  Sensor({ phase: "PRE_DECODE" }),
5660
- Injectable26()
5816
+ Injectable27()
5661
5817
  ], VarintHardeningSensor);
5662
5818
 
5663
5819
  // src/utils/index.ts
@@ -5728,14 +5884,21 @@ export {
5728
5884
  AXIS_UPLOAD_SESSION_STORE,
5729
5885
  AXIS_VERSION,
5730
5886
  ats1_exports as Ats1Codec,
5887
+ AxisContext,
5888
+ AxisDemoPubkey,
5889
+ AxisError,
5731
5890
  AxisFilesDownloadHandler,
5732
5891
  AxisFilesFinalizeHandler,
5733
5892
  AxisFrameZ,
5734
5893
  AxisIdDto,
5894
+ AxisIp,
5735
5895
  T as AxisPacketTags,
5736
5896
  AxisPartialType,
5897
+ AxisRaw,
5737
5898
  AxisResponseDto,
5899
+ AxisSensorChainService,
5738
5900
  AxisTlvDto,
5901
+ BAND,
5739
5902
  BodyProfile,
5740
5903
  CAPABILITIES,
5741
5904
  ContractViolationError,
@@ -5753,7 +5916,10 @@ export {
5753
5916
  FLAG_CHAIN_REQ,
5754
5917
  FLAG_HAS_WITNESS,
5755
5918
  HANDLER_METADATA_KEY,
5919
+ HANDLER_SENSORS_KEY,
5756
5920
  Handler,
5921
+ HandlerDiscoveryService,
5922
+ HandlerSensors,
5757
5923
  INTENT_BODY_KEY,
5758
5924
  INTENT_METADATA_KEY,
5759
5925
  INTENT_REQUIREMENTS,
@@ -5780,6 +5946,7 @@ export {
5780
5946
  NCERT_PUB,
5781
5947
  NCERT_SCOPE,
5782
5948
  NCERT_SIG,
5949
+ PRE_DECODE_BOUNDARY,
5783
5950
  PROOF_CAPABILITIES,
5784
5951
  PROOF_CAPSULE,
5785
5952
  PROOF_JWT,
@@ -5794,11 +5961,15 @@ export {
5794
5961
  RESPONSE_TAG_UPDATED_AT,
5795
5962
  RESPONSE_TAG_UPDATED_BY,
5796
5963
  RiskDecision,
5964
+ SENSOR_METADATA_KEY,
5797
5965
  Schema2002_PasskeyLoginOptionsRes,
5798
5966
  Schema2011_PasskeyLoginVerifyReq,
5799
5967
  Schema2012_PasskeyLoginVerifyRes,
5800
5968
  Schema2021_PasskeyRegisterOptionsReq,
5969
+ Sensor,
5801
5970
  SensorDecisions,
5971
+ SensorDiscoveryService,
5972
+ SensorRegistry,
5802
5973
  TLV,
5803
5974
  TLV_ACTOR_ID,
5804
5975
  TLV_AUD,
@@ -5860,6 +6031,7 @@ export {
5860
6031
  computeReceiptHash,
5861
6032
  computeSignaturePayload,
5862
6033
  core_exports as core,
6034
+ createObservation,
5863
6035
  crypto_exports as crypto,
5864
6036
  decodeArray,
5865
6037
  decodeAxis1Frame,
@@ -5876,8 +6048,10 @@ export {
5876
6048
  encodeQueueMessage,
5877
6049
  encodeTLVs,
5878
6050
  encodeVarint,
6051
+ endStage,
5879
6052
  engine_exports as engine,
5880
6053
  extractDtoSchema,
6054
+ finalizeObservation,
5881
6055
  generateEd25519KeyPair,
5882
6056
  getSignTarget,
5883
6057
  hasScope,
@@ -5896,6 +6070,7 @@ export {
5896
6070
  parseAutoClaimEntries,
5897
6071
  parseScope,
5898
6072
  parseStreamEntries,
6073
+ recordSensor,
5899
6074
  resolveTimeout,
5900
6075
  schemas_exports as schemas,
5901
6076
  security_exports as security,
@@ -5904,6 +6079,7 @@ export {
5904
6079
  sha256,
5905
6080
  signFrame,
5906
6081
  stableJsonStringify,
6082
+ startStage,
5907
6083
  tlv,
5908
6084
  u64be,
5909
6085
  unpackPasskeyLoginOptionsReq,