@nextera.one/axis-server-sdk 1.3.0 → 1.4.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.js CHANGED
@@ -166,12 +166,15 @@ __export(index_exports, {
166
166
  buildAts1Hdr: () => buildAts1Hdr,
167
167
  buildDtoDecoder: () => buildDtoDecoder,
168
168
  buildPacket: () => buildPacket,
169
+ buildQueueMessage: () => buildQueueMessage,
169
170
  buildReceiptHash: () => buildReceiptHash,
170
171
  buildTLVs: () => buildTLVs,
172
+ buildUnsignedWitness: () => buildUnsignedWitness,
171
173
  bytes: () => bytes,
172
174
  canAccessResource: () => canAccessResource,
173
175
  canonicalJson: () => canonicalJson,
174
176
  canonicalJsonExcluding: () => canonicalJsonExcluding,
177
+ canonicalizeObservation: () => canonicalizeObservation,
175
178
  classifyIntent: () => classifyIntent,
176
179
  computeReceiptHash: () => computeReceiptHash,
177
180
  computeSignaturePayload: () => computeSignaturePayload,
@@ -181,6 +184,7 @@ __export(index_exports, {
181
184
  decodeAxis1Frame: () => decodeAxis1Frame,
182
185
  decodeFrame: () => decodeFrame,
183
186
  decodeObject: () => import_axis_protocol.decodeObject,
187
+ decodeQueueMessage: () => decodeQueueMessage,
184
188
  decodeTLVs: () => import_axis_protocol.decodeTLVs,
185
189
  decodeTLVsList: () => import_axis_protocol.decodeTLVsList,
186
190
  decodeVarint: () => import_axis_protocol3.decodeVarint,
@@ -188,6 +192,7 @@ __export(index_exports, {
188
192
  encVarint: () => encVarint,
189
193
  encodeAxis1Frame: () => encodeAxis1Frame,
190
194
  encodeFrame: () => encodeFrame,
195
+ encodeQueueMessage: () => encodeQueueMessage,
191
196
  encodeTLVs: () => import_axis_protocol.encodeTLVs,
192
197
  encodeVarint: () => import_axis_protocol3.encodeVarint,
193
198
  engine: () => engine_exports,
@@ -195,6 +200,7 @@ __export(index_exports, {
195
200
  generateEd25519KeyPair: () => generateEd25519KeyPair,
196
201
  getSignTarget: () => getSignTarget,
197
202
  hasScope: () => hasScope,
203
+ hashObservation: () => hashObservation,
198
204
  isAdminOpcode: () => isAdminOpcode,
199
205
  isKnownOpcode: () => isKnownOpcode,
200
206
  isTimestampValid: () => isTimestampValid,
@@ -206,7 +212,9 @@ __export(index_exports, {
206
212
  packPasskeyLoginVerifyReq: () => packPasskeyLoginVerifyReq,
207
213
  packPasskeyLoginVerifyRes: () => packPasskeyLoginVerifyRes,
208
214
  packPasskeyRegisterOptionsReq: () => packPasskeyRegisterOptionsReq,
215
+ parseAutoClaimEntries: () => parseAutoClaimEntries,
209
216
  parseScope: () => parseScope,
217
+ parseStreamEntries: () => parseStreamEntries,
210
218
  resolveTimeout: () => resolveTimeout,
211
219
  schemas: () => schemas_exports,
212
220
  security: () => security_exports,
@@ -214,6 +222,7 @@ __export(index_exports, {
214
222
  sensors: () => sensors_exports,
215
223
  sha256: () => sha256,
216
224
  signFrame: () => signFrame,
225
+ stableJsonStringify: () => stableJsonStringify,
217
226
  tlv: () => tlv,
218
227
  u64be: () => u64be,
219
228
  unpackPasskeyLoginOptionsReq: () => unpackPasskeyLoginOptionsReq,
@@ -224,7 +233,8 @@ __export(index_exports, {
224
233
  validateFrameShape: () => validateFrameShape,
225
234
  varintLength: () => import_axis_protocol3.varintLength,
226
235
  varintU: () => varintU,
227
- verifyFrameSignature: () => verifyFrameSignature
236
+ verifyFrameSignature: () => verifyFrameSignature,
237
+ verifyResponse: () => verifyResponse
228
238
  });
229
239
  module.exports = __toCommonJS(index_exports);
230
240
 
@@ -919,9 +929,213 @@ IntentRouter = __decorateClass([
919
929
  __decorateParam(0, (0, import_common2.Optional)())
920
930
  ], IntentRouter);
921
931
 
932
+ // src/engine/observation/stable-json.ts
933
+ function normalize(value) {
934
+ if (Array.isArray(value)) {
935
+ return value.map((item) => normalize(item));
936
+ }
937
+ if (value && typeof value === "object") {
938
+ const entries = Object.entries(value).filter(([, nested]) => nested !== void 0).sort(([left], [right]) => left.localeCompare(right));
939
+ const normalized = {};
940
+ for (const [key, nested] of entries) {
941
+ normalized[key] = normalize(nested);
942
+ }
943
+ return normalized;
944
+ }
945
+ return value;
946
+ }
947
+ function stableJsonStringify(value) {
948
+ return JSON.stringify(normalize(value));
949
+ }
950
+
951
+ // src/engine/observation/observation-queue.codec.ts
952
+ function buildQueueMessage(observation, sourceNodeId, previous, lastError) {
953
+ const now = Date.now();
954
+ return {
955
+ v: 1,
956
+ observation,
957
+ attempts: previous ? previous.attempts + 1 : 0,
958
+ firstEnqueuedAt: previous?.firstEnqueuedAt ?? now,
959
+ lastEnqueuedAt: now,
960
+ sourceNodeId,
961
+ lastError
962
+ };
963
+ }
964
+ function encodeQueueMessage(message) {
965
+ return JSON.stringify(message);
966
+ }
967
+ function decodeQueueMessage(raw) {
968
+ try {
969
+ const parsed = JSON.parse(raw);
970
+ if (!parsed || parsed.v !== 1 || !parsed.observation?.id) {
971
+ return null;
972
+ }
973
+ return parsed;
974
+ } catch {
975
+ return null;
976
+ }
977
+ }
978
+ function parseStreamEntries(raw) {
979
+ if (!Array.isArray(raw)) {
980
+ return [];
981
+ }
982
+ const entries = [];
983
+ for (const streamRow of raw) {
984
+ if (!Array.isArray(streamRow) || streamRow.length < 2) {
985
+ continue;
986
+ }
987
+ const messageRows = streamRow[1];
988
+ if (!Array.isArray(messageRows)) {
989
+ continue;
990
+ }
991
+ for (const row of messageRows) {
992
+ if (!Array.isArray(row) || row.length < 2) {
993
+ continue;
994
+ }
995
+ const id = String(row[0]);
996
+ const fields = Array.isArray(row[1]) ? row[1] : [];
997
+ const fieldMap = fieldsToMap(fields);
998
+ const payload = fieldMap.get("payload");
999
+ if (!payload) {
1000
+ continue;
1001
+ }
1002
+ const message = decodeQueueMessage(payload);
1003
+ if (!message) {
1004
+ continue;
1005
+ }
1006
+ entries.push({ id, message });
1007
+ }
1008
+ }
1009
+ return entries;
1010
+ }
1011
+ function parseAutoClaimEntries(raw) {
1012
+ if (!Array.isArray(raw) || raw.length < 2) {
1013
+ return [];
1014
+ }
1015
+ const rows = Array.isArray(raw[1]) ? raw[1] : [];
1016
+ return parseStreamEntries([["stream", rows]]);
1017
+ }
1018
+ function fieldsToMap(fields) {
1019
+ const map3 = /* @__PURE__ */ new Map();
1020
+ for (let i = 0; i < fields.length; i += 2) {
1021
+ const key = fields[i];
1022
+ const value = fields[i + 1];
1023
+ if (key !== void 0 && value !== void 0) {
1024
+ map3.set(String(key), String(value));
1025
+ }
1026
+ }
1027
+ return map3;
1028
+ }
1029
+
1030
+ // src/engine/observation/observation-hash.ts
1031
+ var import_crypto = require("crypto");
1032
+ function canonicalizeObservation(obs) {
1033
+ const obj = {
1034
+ id: obs.id,
1035
+ startMs: obs.startMs,
1036
+ endMs: obs.endMs,
1037
+ transport: obs.transport,
1038
+ ip: obs.ip,
1039
+ intent: obs.intent,
1040
+ actorId: obs.actorId,
1041
+ capsuleId: obs.capsuleId,
1042
+ decision: obs.decision,
1043
+ resultCode: obs.resultCode,
1044
+ statusCode: obs.statusCode,
1045
+ durationMs: obs.durationMs,
1046
+ stages: obs.stages.map((s) => ({
1047
+ name: s.name,
1048
+ status: s.status,
1049
+ startMs: s.startMs,
1050
+ endMs: s.endMs,
1051
+ durationMs: s.durationMs,
1052
+ reason: s.reason,
1053
+ code: s.code
1054
+ })),
1055
+ sensors: obs.sensors.map((s) => ({
1056
+ name: s.name,
1057
+ allowed: s.allowed,
1058
+ riskScore: s.riskScore,
1059
+ durationMs: s.durationMs,
1060
+ reasons: s.reasons,
1061
+ code: s.code
1062
+ }))
1063
+ };
1064
+ return stableJsonStringify(obj);
1065
+ }
1066
+ function hashObservation(obs) {
1067
+ const canonical = canonicalizeObservation(obs);
1068
+ return (0, import_crypto.createHash)("sha256").update(canonical).digest("hex");
1069
+ }
1070
+ function buildUnsignedWitness(obs) {
1071
+ if (!obs.decision || !obs.endMs) {
1072
+ return null;
1073
+ }
1074
+ return {
1075
+ v: 1,
1076
+ observationId: obs.id,
1077
+ payloadHash: hashObservation(obs),
1078
+ sealedAt: Date.now(),
1079
+ summary: {
1080
+ intent: obs.intent,
1081
+ actorId: obs.actorId,
1082
+ decision: obs.decision,
1083
+ statusCode: obs.statusCode,
1084
+ durationMs: obs.durationMs,
1085
+ sensorCount: obs.sensors.length,
1086
+ stageCount: obs.stages.length
1087
+ }
1088
+ };
1089
+ }
1090
+
922
1091
  // src/core/constants.ts
923
1092
  var import_axis_protocol2 = require("@nextera.one/axis-protocol");
924
1093
 
1094
+ // src/engine/observation/response-observer.ts
1095
+ var SENSITIVE_RESPONSE_TAGS = [4, 5, 6];
1096
+ function verifyResponse(ctx, response) {
1097
+ if (!response.effect || typeof response.effect !== "string") {
1098
+ return {
1099
+ passed: false,
1100
+ code: "OBSERVER_INVALID_EFFECT",
1101
+ reason: "Response effect is missing or invalid"
1102
+ };
1103
+ }
1104
+ if (response.ok && (!response.body || response.body.length === 0)) {
1105
+ return {
1106
+ passed: false,
1107
+ code: "OBSERVER_EMPTY_BODY",
1108
+ reason: "Successful response must contain a body"
1109
+ };
1110
+ }
1111
+ if (response.body && response.body.length > import_axis_protocol2.MAX_BODY_LEN) {
1112
+ return {
1113
+ passed: false,
1114
+ code: "OBSERVER_BODY_OVERFLOW",
1115
+ reason: `Response body exceeds ${import_axis_protocol2.MAX_BODY_LEN} bytes`
1116
+ };
1117
+ }
1118
+ if (response.headers) {
1119
+ for (const tag of SENSITIVE_RESPONSE_TAGS) {
1120
+ if (response.headers.has(tag)) {
1121
+ return {
1122
+ passed: false,
1123
+ code: "OBSERVER_DATA_LEAK",
1124
+ reason: `Response must not contain sensitive TLV tag ${tag}`
1125
+ };
1126
+ }
1127
+ }
1128
+ }
1129
+ if (response.effect.includes("Error:") || response.effect.includes("stack") || response.effect.includes("at /")) {
1130
+ return {
1131
+ passed: false,
1132
+ code: "OBSERVER_INFO_LEAK",
1133
+ reason: "Response effect may contain internal error details"
1134
+ };
1135
+ }
1136
+ return { passed: true };
1137
+ }
1138
+
925
1139
  // src/core/varint.ts
926
1140
  var import_axis_protocol3 = require("@nextera.one/axis-protocol");
927
1141
 
@@ -1197,7 +1411,7 @@ __export(ats1_exports, {
1197
1411
  tlvsToMap: () => tlvsToMap,
1198
1412
  validateTLVsAgainstSchema: () => validateTLVsAgainstSchema
1199
1413
  });
1200
- var import_crypto = require("crypto");
1414
+ var import_crypto2 = require("crypto");
1201
1415
  var DEFAULT_LIMITS = {
1202
1416
  maxVarintBytes: 10,
1203
1417
  maxTlvCount: 512,
@@ -1247,7 +1461,7 @@ function decodeU64BE(buf) {
1247
1461
  return buf.readBigUInt64BE(0);
1248
1462
  }
1249
1463
  function sha2562(data) {
1250
- return (0, import_crypto.createHash)("sha256").update(data).digest();
1464
+ return (0, import_crypto2.createHash)("sha256").update(data).digest();
1251
1465
  }
1252
1466
  function encodeTLV(tag, value) {
1253
1467
  if (!Number.isInteger(tag) || tag <= 0)
@@ -1836,7 +2050,7 @@ function packPasskeyLoginVerifyRes(params) {
1836
2050
  }
1837
2051
 
1838
2052
  // src/codec/tlv.encode.ts
1839
- var import_crypto2 = require("crypto");
2053
+ var import_crypto3 = require("crypto");
1840
2054
  function encVarint(x) {
1841
2055
  if (x < 0n) throw new Error("VARINT_NEG");
1842
2056
  const out = [];
@@ -1864,7 +2078,7 @@ function bytes(b) {
1864
2078
  return Buffer.isBuffer(b) ? b : Buffer.from(b);
1865
2079
  }
1866
2080
  function nonce16() {
1867
- return (0, import_crypto2.randomBytes)(16);
2081
+ return (0, import_crypto3.randomBytes)(16);
1868
2082
  }
1869
2083
  function tlv(type, value) {
1870
2084
  if (!Number.isSafeInteger(type) || type < 0) throw new Error("TLV_BAD_TYPE");
@@ -2410,9 +2624,9 @@ function isAdminOpcode(op) {
2410
2624
  }
2411
2625
 
2412
2626
  // src/core/receipt.ts
2413
- var import_crypto3 = require("crypto");
2627
+ var import_crypto4 = require("crypto");
2414
2628
  function buildReceiptHash(prevHash, pid, actorId, intent, effect, ts) {
2415
- const h = (0, import_crypto3.createHash)("sha256");
2629
+ const h = (0, import_crypto4.createHash)("sha256");
2416
2630
  if (prevHash) h.update(prevHash);
2417
2631
  h.update(pid);
2418
2632
  h.update(Buffer.from(actorId, "utf8"));
@@ -3247,15 +3461,16 @@ __export(engine_exports, {
3247
3461
  createObservation: () => createObservation,
3248
3462
  endStage: () => endStage,
3249
3463
  finalizeObservation: () => finalizeObservation,
3464
+ observation: () => observation_exports,
3250
3465
  recordSensor: () => recordSensor,
3251
3466
  startStage: () => startStage
3252
3467
  });
3253
3468
 
3254
3469
  // src/engine/axis-observation.ts
3255
- var import_crypto4 = require("crypto");
3470
+ var import_crypto5 = require("crypto");
3256
3471
  function createObservation(transport, ip) {
3257
3472
  return {
3258
- id: (0, import_crypto4.randomBytes)(16).toString("hex"),
3473
+ id: (0, import_crypto5.randomBytes)(16).toString("hex"),
3259
3474
  startMs: Date.now(),
3260
3475
  transport,
3261
3476
  ip,
@@ -3533,6 +3748,21 @@ SensorRegistry = __decorateClass([
3533
3748
  (0, import_common9.Injectable)()
3534
3749
  ], SensorRegistry);
3535
3750
 
3751
+ // src/engine/observation/index.ts
3752
+ var observation_exports = {};
3753
+ __export(observation_exports, {
3754
+ buildQueueMessage: () => buildQueueMessage,
3755
+ buildUnsignedWitness: () => buildUnsignedWitness,
3756
+ canonicalizeObservation: () => canonicalizeObservation,
3757
+ decodeQueueMessage: () => decodeQueueMessage,
3758
+ encodeQueueMessage: () => encodeQueueMessage,
3759
+ hashObservation: () => hashObservation,
3760
+ parseAutoClaimEntries: () => parseAutoClaimEntries,
3761
+ parseStreamEntries: () => parseStreamEntries,
3762
+ stableJsonStringify: () => stableJsonStringify,
3763
+ verifyResponse: () => verifyResponse
3764
+ });
3765
+
3536
3766
  // src/loom/index.ts
3537
3767
  var loom_exports = {};
3538
3768
  __export(loom_exports, {
@@ -4275,7 +4505,7 @@ CapabilityEnforcementSensor = __decorateClass([
4275
4505
 
4276
4506
  // src/sensors/chunk-hash.sensor.ts
4277
4507
  var import_common14 = require("@nestjs/common");
4278
- var import_crypto5 = require("crypto");
4508
+ var import_crypto6 = require("crypto");
4279
4509
  var ChunkHashSensor = class {
4280
4510
  constructor() {
4281
4511
  /** Sensor identifier */
@@ -4334,7 +4564,7 @@ var ChunkHashSensor = class {
4334
4564
  reason: "Missing sha256Chunk TLV in header"
4335
4565
  };
4336
4566
  }
4337
- const actual = (0, import_crypto5.createHash)("sha256").update(bodyBytes).digest();
4567
+ const actual = (0, import_crypto6.createHash)("sha256").update(bodyBytes).digest();
4338
4568
  if (!Buffer.from(actual).equals(Buffer.from(expected))) {
4339
4569
  return {
4340
4570
  action: "DENY",
@@ -5766,12 +5996,15 @@ function toBuffer(value) {
5766
5996
  buildAts1Hdr,
5767
5997
  buildDtoDecoder,
5768
5998
  buildPacket,
5999
+ buildQueueMessage,
5769
6000
  buildReceiptHash,
5770
6001
  buildTLVs,
6002
+ buildUnsignedWitness,
5771
6003
  bytes,
5772
6004
  canAccessResource,
5773
6005
  canonicalJson,
5774
6006
  canonicalJsonExcluding,
6007
+ canonicalizeObservation,
5775
6008
  classifyIntent,
5776
6009
  computeReceiptHash,
5777
6010
  computeSignaturePayload,
@@ -5781,6 +6014,7 @@ function toBuffer(value) {
5781
6014
  decodeAxis1Frame,
5782
6015
  decodeFrame,
5783
6016
  decodeObject,
6017
+ decodeQueueMessage,
5784
6018
  decodeTLVs,
5785
6019
  decodeTLVsList,
5786
6020
  decodeVarint,
@@ -5788,6 +6022,7 @@ function toBuffer(value) {
5788
6022
  encVarint,
5789
6023
  encodeAxis1Frame,
5790
6024
  encodeFrame,
6025
+ encodeQueueMessage,
5791
6026
  encodeTLVs,
5792
6027
  encodeVarint,
5793
6028
  engine,
@@ -5795,6 +6030,7 @@ function toBuffer(value) {
5795
6030
  generateEd25519KeyPair,
5796
6031
  getSignTarget,
5797
6032
  hasScope,
6033
+ hashObservation,
5798
6034
  isAdminOpcode,
5799
6035
  isKnownOpcode,
5800
6036
  isTimestampValid,
@@ -5806,7 +6042,9 @@ function toBuffer(value) {
5806
6042
  packPasskeyLoginVerifyReq,
5807
6043
  packPasskeyLoginVerifyRes,
5808
6044
  packPasskeyRegisterOptionsReq,
6045
+ parseAutoClaimEntries,
5809
6046
  parseScope,
6047
+ parseStreamEntries,
5810
6048
  resolveTimeout,
5811
6049
  schemas,
5812
6050
  security,
@@ -5814,6 +6052,7 @@ function toBuffer(value) {
5814
6052
  sensors,
5815
6053
  sha256,
5816
6054
  signFrame,
6055
+ stableJsonStringify,
5817
6056
  tlv,
5818
6057
  u64be,
5819
6058
  unpackPasskeyLoginOptionsReq,
@@ -5824,6 +6063,7 @@ function toBuffer(value) {
5824
6063
  validateFrameShape,
5825
6064
  varintLength,
5826
6065
  varintU,
5827
- verifyFrameSignature
6066
+ verifyFrameSignature,
6067
+ verifyResponse
5828
6068
  });
5829
6069
  //# sourceMappingURL=index.js.map