@nextera.one/axis-server-sdk 1.2.0 → 1.2.1

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
@@ -33,6 +33,7 @@ var __decorateClass = (decorators, target, key, kind) => {
33
33
  if (kind && result) __defProp(target, key, result);
34
34
  return result;
35
35
  };
36
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
36
37
 
37
38
  // src/index.ts
38
39
  var index_exports = {};
@@ -41,8 +42,13 @@ __export(index_exports, {
41
42
  ATS1_SCHEMA: () => ATS1_SCHEMA,
42
43
  AXIS_MAGIC: () => import_axis_protocol2.AXIS_MAGIC,
43
44
  AXIS_OPCODES: () => AXIS_OPCODES,
45
+ AXIS_UPLOAD_FILE_STORE: () => AXIS_UPLOAD_FILE_STORE,
46
+ AXIS_UPLOAD_RECEIPT_SIGNER: () => AXIS_UPLOAD_RECEIPT_SIGNER,
47
+ AXIS_UPLOAD_SESSION_STORE: () => AXIS_UPLOAD_SESSION_STORE,
44
48
  AXIS_VERSION: () => import_axis_protocol2.AXIS_VERSION,
45
49
  Ats1Codec: () => ats1_exports,
50
+ AxisFilesDownloadHandler: () => AxisFilesDownloadHandler,
51
+ AxisFilesFinalizeHandler: () => AxisFilesFinalizeHandler,
46
52
  AxisFrameZ: () => AxisFrameZ,
47
53
  AxisIdDto: () => AxisIdDto,
48
54
  AxisPacketTags: () => T,
@@ -55,6 +61,7 @@ __export(index_exports, {
55
61
  DEFAULT_CONTRACTS: () => DEFAULT_CONTRACTS,
56
62
  DEFAULT_TIMEOUT: () => DEFAULT_TIMEOUT,
57
63
  Decision: () => Decision,
64
+ DiskUploadFileStore: () => DiskUploadFileStore,
58
65
  ERR_BAD_SIGNATURE: () => import_axis_protocol2.ERR_BAD_SIGNATURE,
59
66
  ERR_CONTRACT_VIOLATION: () => import_axis_protocol2.ERR_CONTRACT_VIOLATION,
60
67
  ERR_INVALID_PACKET: () => import_axis_protocol2.ERR_INVALID_PACKET,
@@ -66,14 +73,18 @@ __export(index_exports, {
66
73
  FLAG_HAS_WITNESS: () => import_axis_protocol2.FLAG_HAS_WITNESS,
67
74
  HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
68
75
  Handler: () => Handler,
76
+ INTENT_BODY_KEY: () => INTENT_BODY_KEY,
69
77
  INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
70
78
  INTENT_REQUIREMENTS: () => INTENT_REQUIREMENTS,
71
79
  INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
72
80
  INTENT_SENSITIVITY_MAP: () => INTENT_SENSITIVITY_MAP,
81
+ INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
73
82
  INTENT_TIMEOUTS: () => INTENT_TIMEOUTS,
74
83
  Intent: () => Intent,
84
+ IntentBody: () => IntentBody,
75
85
  IntentRouter: () => IntentRouter,
76
86
  IntentSensitivity: () => IntentSensitivity,
87
+ IntentSensors: () => IntentSensors,
77
88
  MAX_BODY_LEN: () => import_axis_protocol2.MAX_BODY_LEN,
78
89
  MAX_FRAME_LEN: () => import_axis_protocol2.MAX_FRAME_LEN,
79
90
  MAX_HDR_LEN: () => import_axis_protocol2.MAX_HDR_LEN,
@@ -245,8 +256,26 @@ function Intent(action, options) {
245
256
  };
246
257
  }
247
258
 
248
- // src/decorators/tlv-field.decorator.ts
259
+ // src/decorators/intent-body.decorator.ts
249
260
  var import_reflect_metadata2 = require("reflect-metadata");
261
+ var INTENT_BODY_KEY = "axis:intent:body";
262
+ function IntentBody(decoder) {
263
+ return (target, propertyKey) => {
264
+ Reflect.defineMetadata(INTENT_BODY_KEY, decoder, target, propertyKey);
265
+ };
266
+ }
267
+
268
+ // src/decorators/intent-sensors.decorator.ts
269
+ var import_reflect_metadata3 = require("reflect-metadata");
270
+ var INTENT_SENSORS_KEY = "axis:intent:sensors";
271
+ function IntentSensors(sensors) {
272
+ return (target, propertyKey) => {
273
+ Reflect.defineMetadata(INTENT_SENSORS_KEY, sensors, target, propertyKey);
274
+ };
275
+ }
276
+
277
+ // src/decorators/tlv-field.decorator.ts
278
+ var import_reflect_metadata4 = require("reflect-metadata");
250
279
  var TLV_FIELDS_KEY = "axis:tlv:fields";
251
280
  var TLV_VALIDATORS_KEY = "axis:tlv:validators";
252
281
  function TlvField(tag, options) {
@@ -304,7 +333,7 @@ function TlvRange(min, max, message) {
304
333
  }
305
334
 
306
335
  // src/decorators/dto-schema.util.ts
307
- var import_reflect_metadata3 = require("reflect-metadata");
336
+ var import_reflect_metadata5 = require("reflect-metadata");
308
337
 
309
338
  // src/core/tlv.ts
310
339
  var import_axis_protocol = require("@nextera.one/axis-protocol");
@@ -405,7 +434,7 @@ __decorateClass([
405
434
  ], AxisIdDto.prototype, "id", 2);
406
435
 
407
436
  // src/base/axis-partial-type.ts
408
- var import_reflect_metadata4 = require("reflect-metadata");
437
+ var import_reflect_metadata6 = require("reflect-metadata");
409
438
  function AxisPartialType(BaseDto) {
410
439
  class PartialDto extends BaseDto {
411
440
  }
@@ -452,10 +481,145 @@ __decorateClass([
452
481
 
453
482
  // src/engine/intent.router.ts
454
483
  var import_common2 = require("@nestjs/common");
484
+
485
+ // src/sensor/axis-sensor.ts
486
+ var Decision = /* @__PURE__ */ ((Decision2) => {
487
+ Decision2["ALLOW"] = "ALLOW";
488
+ Decision2["DENY"] = "DENY";
489
+ Decision2["THROTTLE"] = "THROTTLE";
490
+ Decision2["FLAG"] = "FLAG";
491
+ return Decision2;
492
+ })(Decision || {});
493
+ function normalizeSensorDecision(sensorDecision) {
494
+ if ("action" in sensorDecision) {
495
+ switch (sensorDecision.action) {
496
+ case "ALLOW":
497
+ return {
498
+ allow: true,
499
+ riskScore: 0,
500
+ reasons: [],
501
+ meta: sensorDecision.meta
502
+ };
503
+ case "DENY":
504
+ return {
505
+ allow: false,
506
+ riskScore: 100,
507
+ reasons: [sensorDecision.code, sensorDecision.reason].filter(
508
+ Boolean
509
+ ),
510
+ meta: sensorDecision.meta,
511
+ retryAfterMs: sensorDecision.retryAfterMs
512
+ };
513
+ case "THROTTLE":
514
+ return {
515
+ allow: false,
516
+ riskScore: 50,
517
+ reasons: ["RATE_LIMIT"],
518
+ retryAfterMs: sensorDecision.retryAfterMs,
519
+ meta: sensorDecision.meta
520
+ };
521
+ case "FLAG":
522
+ return {
523
+ allow: true,
524
+ riskScore: sensorDecision.scoreDelta,
525
+ reasons: sensorDecision.reasons,
526
+ meta: sensorDecision.meta
527
+ };
528
+ }
529
+ }
530
+ return {
531
+ allow: sensorDecision.allow,
532
+ riskScore: sensorDecision.riskScore,
533
+ reasons: sensorDecision.reasons,
534
+ tags: sensorDecision.tags,
535
+ meta: sensorDecision.meta,
536
+ tighten: sensorDecision.tighten,
537
+ retryAfterMs: sensorDecision.retryAfterMs
538
+ };
539
+ }
540
+ var SensorDecisions = {
541
+ allow(meta, tags) {
542
+ return {
543
+ decision: "ALLOW" /* ALLOW */,
544
+ allow: true,
545
+ riskScore: 0,
546
+ reasons: [],
547
+ tags,
548
+ meta
549
+ };
550
+ },
551
+ deny(code, reason, meta) {
552
+ return {
553
+ decision: "DENY" /* DENY */,
554
+ allow: false,
555
+ riskScore: 100,
556
+ code,
557
+ reasons: [code, reason].filter(Boolean),
558
+ meta
559
+ };
560
+ },
561
+ throttle(retryAfterMs, meta) {
562
+ return {
563
+ decision: "THROTTLE" /* THROTTLE */,
564
+ allow: false,
565
+ riskScore: 50,
566
+ retryAfterMs,
567
+ code: "RATE_LIMIT",
568
+ reasons: ["RATE_LIMIT"],
569
+ meta
570
+ };
571
+ },
572
+ flag(scoreDelta, reasons, meta) {
573
+ return {
574
+ decision: "FLAG" /* FLAG */,
575
+ allow: true,
576
+ riskScore: scoreDelta,
577
+ scoreDelta,
578
+ reasons,
579
+ meta
580
+ };
581
+ }
582
+ };
583
+
584
+ // src/engine/intent.router.ts
455
585
  var IntentRouter = class {
456
- constructor() {
586
+ constructor(moduleRef) {
587
+ this.moduleRef = moduleRef;
588
+ this.logger = new import_common2.Logger(IntentRouter.name);
457
589
  /** Internal registry of dynamic intent handlers */
458
590
  this.handlers = /* @__PURE__ */ new Map();
591
+ /** Per-intent sensor classes (resolved at call time) */
592
+ this.intentSensors = /* @__PURE__ */ new Map();
593
+ /** Per-intent body decoders */
594
+ this.intentDecoders = /* @__PURE__ */ new Map();
595
+ /** Per-intent TLV schemas */
596
+ this.intentSchemas = /* @__PURE__ */ new Map();
597
+ /** Per-intent custom validators */
598
+ this.intentValidators = /* @__PURE__ */ new Map();
599
+ /** Per-intent operation kind */
600
+ this.intentKinds = /* @__PURE__ */ new Map();
601
+ }
602
+ getSchema(intent) {
603
+ return this.intentSchemas.get(intent);
604
+ }
605
+ getValidators(intent) {
606
+ return this.intentValidators.get(intent);
607
+ }
608
+ has(intent) {
609
+ return this.handlers.has(intent) || IntentRouter.BUILTIN_INTENTS.has(intent);
610
+ }
611
+ getRegisteredIntents() {
612
+ return [...IntentRouter.BUILTIN_INTENTS, ...this.handlers.keys()];
613
+ }
614
+ getIntentEntry(intent) {
615
+ if (!this.has(intent)) return null;
616
+ return {
617
+ schema: this.intentSchemas.get(intent),
618
+ validators: this.intentValidators.get(intent),
619
+ hasSensors: this.intentSensors.has(intent),
620
+ builtin: IntentRouter.BUILTIN_INTENTS.has(intent),
621
+ kind: this.intentKinds.get(intent)
622
+ };
459
623
  }
460
624
  /**
461
625
  * Registers a handler for a specific intent.
@@ -491,6 +655,16 @@ var IntentRouter = class {
491
655
  } else {
492
656
  this.register(intentName, fn);
493
657
  }
658
+ this.registerIntentMeta(intentName, Object.getPrototypeOf(instance), String(route.methodName));
659
+ }
660
+ const proto = Object.getPrototypeOf(instance);
661
+ for (const key of Object.getOwnPropertyNames(proto)) {
662
+ const meta = Reflect.getMetadata(INTENT_METADATA_KEY, proto, key);
663
+ if (!meta?.intent) continue;
664
+ if (!this.handlers.has(meta.intent)) {
665
+ this.register(meta.intent, instance[key].bind(instance));
666
+ }
667
+ this.registerIntentMeta(meta.intent, proto, key);
494
668
  }
495
669
  }
496
670
  /**
@@ -514,6 +688,7 @@ var IntentRouter = class {
514
688
  intent = new TextDecoder().decode(intentBytes);
515
689
  let effect;
516
690
  if (intent === "system.ping" || intent === "public.ping") {
691
+ this.logger.debug("PING received");
517
692
  effect = {
518
693
  ok: true,
519
694
  effect: "pong",
@@ -554,6 +729,7 @@ var IntentRouter = class {
554
729
  if (!innerIntent) {
555
730
  throw new Error("INTENT.EXEC missing inner intent");
556
731
  }
732
+ this.logger.debug(`EXEC: routing to inner intent '${innerIntent}'`);
557
733
  const innerFrame = {
558
734
  ...frame,
559
735
  headers: new Map(frame.headers),
@@ -569,8 +745,23 @@ var IntentRouter = class {
569
745
  if (!handler) {
570
746
  throw new Error(`Intent not found: ${intent}`);
571
747
  }
748
+ const sensorClasses = this.intentSensors.get(intent);
749
+ if (sensorClasses && sensorClasses.length > 0) {
750
+ await this.runIntentSensors(sensorClasses, intent, frame);
751
+ }
752
+ const decoder = this.intentDecoders.get(intent);
753
+ let decodedBody = frame.body;
754
+ if (decoder) {
755
+ try {
756
+ decodedBody = decoder(Buffer.from(frame.body));
757
+ } catch (decodeErr) {
758
+ throw new Error(
759
+ `IntentBody decode failed for ${intent}: ${decodeErr.message}`
760
+ );
761
+ }
762
+ }
572
763
  if (typeof handler === "function") {
573
- const resultBody = await handler(frame.body, frame.headers);
764
+ const resultBody = decoder ? await handler(decodedBody, frame.headers) : await handler(frame.body, frame.headers);
574
765
  effect = {
575
766
  ok: true,
576
767
  effect: "complete",
@@ -580,10 +771,7 @@ var IntentRouter = class {
580
771
  if (typeof handler.handle === "function") {
581
772
  effect = await handler.handle(frame);
582
773
  } else if (typeof handler.execute === "function") {
583
- const bodyRes = await handler.execute(
584
- frame.body,
585
- frame.headers
586
- );
774
+ const bodyRes = decoder ? await handler.execute(decodedBody, frame.headers) : await handler.execute(frame.body, frame.headers);
587
775
  effect = {
588
776
  ok: true,
589
777
  effect: "complete",
@@ -596,20 +784,130 @@ var IntentRouter = class {
596
784
  }
597
785
  }
598
786
  }
599
- this.recordLatency(intent, start);
787
+ this.logIntent(intent, start, true);
600
788
  return effect;
601
789
  } catch (e) {
602
- console.error(`Error routing intent ${intent}:`, e.message);
790
+ this.logIntent(intent, start, false, e.message);
603
791
  throw e;
604
792
  }
605
793
  }
606
- recordLatency(intent, start) {
794
+ logIntent(intent, start, ok, error) {
607
795
  const diff = process.hrtime(start);
608
- void diff;
796
+ const ms = (diff[0] * 1e3 + diff[1] / 1e6).toFixed(2);
797
+ if (ok) {
798
+ this.logger.debug(`${intent} completed in ${ms}ms`);
799
+ } else {
800
+ this.logger.warn(`${intent} failed in ${ms}ms - ${error}`);
801
+ }
802
+ }
803
+ registerIntentMeta(intent, proto, methodName) {
804
+ const decoder = Reflect.getMetadata(INTENT_BODY_KEY, proto, methodName);
805
+ if (decoder) {
806
+ this.intentDecoders.set(intent, decoder);
807
+ }
808
+ const sensors = Reflect.getMetadata(INTENT_SENSORS_KEY, proto, methodName);
809
+ if (sensors && Array.isArray(sensors) && sensors.length > 0) {
810
+ this.intentSensors.set(intent, sensors);
811
+ }
812
+ const meta = Reflect.getMetadata(INTENT_METADATA_KEY, proto, methodName);
813
+ if (meta) {
814
+ this.storeSchema(meta);
815
+ if (meta.kind) {
816
+ this.intentKinds.set(intent, meta.kind);
817
+ }
818
+ }
819
+ }
820
+ async runIntentSensors(sensorClasses, intent, frame) {
821
+ if (!this.moduleRef) return;
822
+ for (const SensorClass of sensorClasses) {
823
+ let sensor;
824
+ try {
825
+ sensor = this.moduleRef.get(SensorClass, { strict: false });
826
+ } catch {
827
+ this.logger.warn(
828
+ `@IntentSensors: could not resolve ${SensorClass.name} for ${intent}`
829
+ );
830
+ continue;
831
+ }
832
+ const sensorInput = {
833
+ rawBytes: frame.body,
834
+ intent,
835
+ body: frame.body,
836
+ headerTLVs: frame.headers,
837
+ metadata: { phase: "intent", intent }
838
+ };
839
+ if (sensor.supports && !sensor.supports(sensorInput)) continue;
840
+ const decision = normalizeSensorDecision(await sensor.run(sensorInput));
841
+ if (!decision.allow) {
842
+ const reason = decision.reasons[0] || `${sensor.name}:DENIED`;
843
+ this.logger.warn(
844
+ `Intent sensor ${sensor.name} denied ${intent}: ${reason}`
845
+ );
846
+ throw new Error(`SENSOR_DENY:${reason}`);
847
+ }
848
+ }
849
+ }
850
+ storeSchema(meta) {
851
+ if (meta.dto) {
852
+ if (meta.tlv && meta.tlv.length > 0) {
853
+ this.logger.warn(
854
+ `${meta.intent}: both 'dto' and 'tlv' specified - using dto, ignoring tlv`
855
+ );
856
+ }
857
+ const extracted = extractDtoSchema(meta.dto);
858
+ const schema2 = {
859
+ intent: meta.intent,
860
+ version: 1,
861
+ bodyProfile: meta.bodyProfile || "TLV_MAP",
862
+ fields: extracted.fields.map((f) => ({
863
+ name: f.name,
864
+ tlv: f.tag,
865
+ kind: f.kind,
866
+ required: f.required,
867
+ maxLen: f.maxLen,
868
+ max: f.max,
869
+ scope: f.scope
870
+ }))
871
+ };
872
+ this.intentSchemas.set(meta.intent, schema2);
873
+ if (extracted.validators.size > 0) {
874
+ this.intentValidators.set(meta.intent, extracted.validators);
875
+ }
876
+ if (!this.intentDecoders.has(meta.intent)) {
877
+ this.intentDecoders.set(meta.intent, buildDtoDecoder(meta.dto));
878
+ }
879
+ return;
880
+ }
881
+ if (!meta.tlv || meta.tlv.length === 0) return;
882
+ const schema = {
883
+ intent: meta.intent,
884
+ version: 1,
885
+ bodyProfile: meta.bodyProfile || "TLV_MAP",
886
+ fields: meta.tlv.map((f) => ({
887
+ name: f.name,
888
+ tlv: f.tag,
889
+ kind: f.kind,
890
+ required: f.required,
891
+ maxLen: f.maxLen,
892
+ max: f.max,
893
+ scope: f.scope
894
+ }))
895
+ };
896
+ this.intentSchemas.set(meta.intent, schema);
609
897
  }
610
898
  };
899
+ /** Intents handled inline in route() — not in `handlers` map */
900
+ IntentRouter.BUILTIN_INTENTS = /* @__PURE__ */ new Set([
901
+ "system.ping",
902
+ "public.ping",
903
+ "system.time",
904
+ "system.echo",
905
+ "INTENT.EXEC",
906
+ "axis.intent.exec"
907
+ ]);
611
908
  IntentRouter = __decorateClass([
612
- (0, import_common2.Injectable)()
909
+ (0, import_common2.Injectable)(),
910
+ __decorateParam(0, (0, import_common2.Optional)())
613
911
  ], IntentRouter);
614
912
 
615
913
  // src/core/constants.ts
@@ -1985,105 +2283,6 @@ function buildPacket(hdr, body, sig, flags = 0) {
1985
2283
  };
1986
2284
  }
1987
2285
 
1988
- // src/sensor/axis-sensor.ts
1989
- var Decision = /* @__PURE__ */ ((Decision2) => {
1990
- Decision2["ALLOW"] = "ALLOW";
1991
- Decision2["DENY"] = "DENY";
1992
- Decision2["THROTTLE"] = "THROTTLE";
1993
- Decision2["FLAG"] = "FLAG";
1994
- return Decision2;
1995
- })(Decision || {});
1996
- function normalizeSensorDecision(sensorDecision) {
1997
- if ("action" in sensorDecision) {
1998
- switch (sensorDecision.action) {
1999
- case "ALLOW":
2000
- return {
2001
- allow: true,
2002
- riskScore: 0,
2003
- reasons: [],
2004
- meta: sensorDecision.meta
2005
- };
2006
- case "DENY":
2007
- return {
2008
- allow: false,
2009
- riskScore: 100,
2010
- reasons: [sensorDecision.code, sensorDecision.reason].filter(
2011
- Boolean
2012
- ),
2013
- meta: sensorDecision.meta,
2014
- retryAfterMs: sensorDecision.retryAfterMs
2015
- };
2016
- case "THROTTLE":
2017
- return {
2018
- allow: false,
2019
- riskScore: 50,
2020
- reasons: ["RATE_LIMIT"],
2021
- retryAfterMs: sensorDecision.retryAfterMs,
2022
- meta: sensorDecision.meta
2023
- };
2024
- case "FLAG":
2025
- return {
2026
- allow: true,
2027
- riskScore: sensorDecision.scoreDelta,
2028
- reasons: sensorDecision.reasons,
2029
- meta: sensorDecision.meta
2030
- };
2031
- }
2032
- }
2033
- return {
2034
- allow: sensorDecision.allow,
2035
- riskScore: sensorDecision.riskScore,
2036
- reasons: sensorDecision.reasons,
2037
- tags: sensorDecision.tags,
2038
- meta: sensorDecision.meta,
2039
- tighten: sensorDecision.tighten,
2040
- retryAfterMs: sensorDecision.retryAfterMs
2041
- };
2042
- }
2043
- var SensorDecisions = {
2044
- allow(meta, tags) {
2045
- return {
2046
- decision: "ALLOW" /* ALLOW */,
2047
- allow: true,
2048
- riskScore: 0,
2049
- reasons: [],
2050
- tags,
2051
- meta
2052
- };
2053
- },
2054
- deny(code, reason, meta) {
2055
- return {
2056
- decision: "DENY" /* DENY */,
2057
- allow: false,
2058
- riskScore: 100,
2059
- code,
2060
- reasons: [code, reason].filter(Boolean),
2061
- meta
2062
- };
2063
- },
2064
- throttle(retryAfterMs, meta) {
2065
- return {
2066
- decision: "THROTTLE" /* THROTTLE */,
2067
- allow: false,
2068
- riskScore: 50,
2069
- retryAfterMs,
2070
- code: "RATE_LIMIT",
2071
- reasons: ["RATE_LIMIT"],
2072
- meta
2073
- };
2074
- },
2075
- flag(scoreDelta, reasons, meta) {
2076
- return {
2077
- decision: "FLAG" /* FLAG */,
2078
- allow: true,
2079
- riskScore: scoreDelta,
2080
- scoreDelta,
2081
- reasons,
2082
- meta
2083
- };
2084
- }
2085
- };
2086
-
2087
2286
  // src/security/scopes.ts
2088
2287
  function hasScope(scopes, required) {
2089
2288
  if (!Array.isArray(scopes) || scopes.length === 0) {
@@ -2381,14 +2580,246 @@ function isTimestampValid(ts, skewSeconds = 120) {
2381
2580
  const diff = Math.abs(now - ts);
2382
2581
  return diff <= skewSeconds;
2383
2582
  }
2583
+
2584
+ // src/upload/axis-files.handlers.ts
2585
+ var import_common3 = require("@nestjs/common");
2586
+ var crypto2 = __toESM(require("crypto"));
2587
+
2588
+ // src/upload/upload.tokens.ts
2589
+ var AXIS_UPLOAD_SESSION_STORE = "AXIS_UPLOAD_SESSION_STORE";
2590
+ var AXIS_UPLOAD_FILE_STORE = "AXIS_UPLOAD_FILE_STORE";
2591
+ var AXIS_UPLOAD_RECEIPT_SIGNER = "AXIS_UPLOAD_RECEIPT_SIGNER";
2592
+
2593
+ // src/upload/axis-files.handlers.ts
2594
+ var AxisFilesDownloadHandler = class {
2595
+ constructor(sessions, files) {
2596
+ this.sessions = sessions;
2597
+ this.files = files;
2598
+ this.logger = new import_common3.Logger(AxisFilesDownloadHandler.name);
2599
+ this.name = "axis.files.download";
2600
+ this.open = true;
2601
+ this.description = "File download handler";
2602
+ }
2603
+ async execute(body, headers) {
2604
+ const h = headers;
2605
+ if (!h) throw new Error("MISSING_HEADERS");
2606
+ const uploadIdBytes = h.get(20);
2607
+ if (!uploadIdBytes) throw new Error("MISSING_UPLOAD_ID");
2608
+ const uploadId = new TextDecoder().decode(uploadIdBytes);
2609
+ let rangeStart = 0;
2610
+ let rangeLen = -1;
2611
+ const startBytes = h.get(21);
2612
+ if (startBytes) {
2613
+ const { value } = (0, import_axis_protocol3.decodeVarint)(startBytes);
2614
+ rangeStart = value;
2615
+ }
2616
+ const lenBytes = h.get(22);
2617
+ if (lenBytes) {
2618
+ const { value } = (0, import_axis_protocol3.decodeVarint)(lenBytes);
2619
+ rangeLen = value;
2620
+ }
2621
+ const session = await this.sessions.findByFileId(uploadId);
2622
+ if (!session) {
2623
+ throw new Error(`SESSION_NOT_FOUND: ${uploadId}`);
2624
+ }
2625
+ if (session.status !== "COMPLETE") {
2626
+ throw new Error(`FILE_NOT_READY: Status is ${session.status}`);
2627
+ }
2628
+ const stat = await this.files.statFinal(
2629
+ uploadId,
2630
+ session.filename
2631
+ );
2632
+ const fileSize = stat.size;
2633
+ if (rangeStart < 0) rangeStart = 0;
2634
+ if (rangeStart >= fileSize) throw new Error("RANGE_OUT_OF_BOUNDS");
2635
+ let end = fileSize;
2636
+ if (rangeLen >= 0) {
2637
+ end = Math.min(rangeStart + rangeLen, fileSize);
2638
+ }
2639
+ const actualLen = end - rangeStart;
2640
+ const buffer = await this.files.readFinalRange(
2641
+ uploadId,
2642
+ session.filename,
2643
+ rangeStart,
2644
+ actualLen
2645
+ );
2646
+ const responseHeaders = /* @__PURE__ */ new Map();
2647
+ responseHeaders.set(30, (0, import_axis_protocol3.encodeVarint)(fileSize));
2648
+ responseHeaders.set(31, (0, import_axis_protocol3.encodeVarint)(rangeStart));
2649
+ responseHeaders.set(32, (0, import_axis_protocol3.encodeVarint)(actualLen));
2650
+ return {
2651
+ ok: true,
2652
+ effect: "FILE_PART",
2653
+ body: buffer,
2654
+ headers: responseHeaders
2655
+ };
2656
+ }
2657
+ };
2658
+ __decorateClass([
2659
+ Intent("file.download", { absolute: true, kind: "read" })
2660
+ ], AxisFilesDownloadHandler.prototype, "execute", 1);
2661
+ AxisFilesDownloadHandler = __decorateClass([
2662
+ Handler("axis.files.download"),
2663
+ (0, import_common3.Injectable)(),
2664
+ __decorateParam(0, (0, import_common3.Inject)(AXIS_UPLOAD_SESSION_STORE)),
2665
+ __decorateParam(1, (0, import_common3.Inject)(AXIS_UPLOAD_FILE_STORE))
2666
+ ], AxisFilesDownloadHandler);
2667
+ var AxisFilesFinalizeHandler = class {
2668
+ constructor(sessions, files, keyring) {
2669
+ this.sessions = sessions;
2670
+ this.files = files;
2671
+ this.keyring = keyring;
2672
+ this.logger = new import_common3.Logger(AxisFilesFinalizeHandler.name);
2673
+ this.name = "axis.files.finalize";
2674
+ this.open = false;
2675
+ this.description = "File upload finalization handler";
2676
+ }
2677
+ async execute(body, headers) {
2678
+ const bodyStr = new TextDecoder().decode(body);
2679
+ const req = JSON.parse(bodyStr);
2680
+ const { fileId, expectedHash } = req;
2681
+ if (!fileId) throw new Error("MISSING_FILE_ID");
2682
+ const session = await this.sessions.findByFileId(fileId);
2683
+ if (!session) throw new Error("SESSION_NOT_FOUND");
2684
+ if (!await this.files.hasTemp(fileId)) {
2685
+ throw new Error("CHUNKS_NOT_FOUND");
2686
+ }
2687
+ const hash = crypto2.createHash("sha256");
2688
+ const rs = this.files.createTempReadStream(fileId);
2689
+ for await (const chunk of rs) {
2690
+ hash.update(chunk);
2691
+ }
2692
+ const finalHash = hash.digest("hex");
2693
+ if (expectedHash && finalHash !== expectedHash) {
2694
+ throw new Error("HASH_MISMATCH");
2695
+ }
2696
+ const finalPath = await this.files.moveTempToFinal(
2697
+ fileId,
2698
+ session.filename
2699
+ );
2700
+ await this.sessions.updateStatus(fileId, "COMPLETE", null);
2701
+ if (!this.keyring) {
2702
+ this.logger.warn("Receipt signer not configured; returning unsigned receipt");
2703
+ return {
2704
+ ok: true,
2705
+ effect: "FILE_FINALIZED",
2706
+ body: new TextEncoder().encode(
2707
+ JSON.stringify({
2708
+ uploadId: fileId,
2709
+ sha256_final: finalHash,
2710
+ totalSize: session.totalSize,
2711
+ tsMs: Date.now(),
2712
+ path: finalPath
2713
+ })
2714
+ )
2715
+ };
2716
+ }
2717
+ const receiptData = {
2718
+ uploadId: fileId,
2719
+ sha256_final: finalHash,
2720
+ totalSize: session.totalSize,
2721
+ tsMs: Date.now()
2722
+ };
2723
+ const receiptJson = JSON.stringify(receiptData);
2724
+ const receiptBody = new TextEncoder().encode(receiptJson);
2725
+ const SIG_PRESENT = 1;
2726
+ const responseFrame = {
2727
+ flags: SIG_PRESENT,
2728
+ headers: /* @__PURE__ */ new Map(),
2729
+ body: receiptBody,
2730
+ sig: new Uint8Array(0)
2731
+ };
2732
+ const signTarget = getSignTarget(responseFrame);
2733
+ const { sig, kid } = this.keyring.signActive(signTarget);
2734
+ responseFrame.sig = sig;
2735
+ return {
2736
+ ok: true,
2737
+ effect: "FILE_FINALIZED",
2738
+ data: encodeFrame(responseFrame),
2739
+ headers: /* @__PURE__ */ new Map([[1, new TextEncoder().encode(kid)]])
2740
+ };
2741
+ }
2742
+ };
2743
+ __decorateClass([
2744
+ Intent("file.finalize", { absolute: true, kind: "action" })
2745
+ ], AxisFilesFinalizeHandler.prototype, "execute", 1);
2746
+ AxisFilesFinalizeHandler = __decorateClass([
2747
+ Handler("axis.files.finalize"),
2748
+ (0, import_common3.Injectable)(),
2749
+ __decorateParam(0, (0, import_common3.Inject)(AXIS_UPLOAD_SESSION_STORE)),
2750
+ __decorateParam(1, (0, import_common3.Inject)(AXIS_UPLOAD_FILE_STORE)),
2751
+ __decorateParam(2, (0, import_common3.Optional)()),
2752
+ __decorateParam(2, (0, import_common3.Inject)(AXIS_UPLOAD_RECEIPT_SIGNER))
2753
+ ], AxisFilesFinalizeHandler);
2754
+
2755
+ // src/upload/disk-upload-file.store.ts
2756
+ var fs = __toESM(require("fs"));
2757
+ var path = __toESM(require("path"));
2758
+ var DiskUploadFileStore = class {
2759
+ constructor(options) {
2760
+ this.uploadDir = options.uploadDir;
2761
+ this.chunkDir = options.chunkDir;
2762
+ }
2763
+ getFinalPath(fileId, filename) {
2764
+ const safeFilename = filename ? path.basename(filename) : fileId;
2765
+ return path.join(this.uploadDir, safeFilename);
2766
+ }
2767
+ getTempPath(fileId) {
2768
+ const safeId = path.basename(fileId);
2769
+ return path.join(this.chunkDir, safeId);
2770
+ }
2771
+ async statFinal(fileId, filename) {
2772
+ const finalPath = this.getFinalPath(fileId, filename);
2773
+ if (!fs.existsSync(finalPath)) {
2774
+ throw new Error("FILE_MISSING_ON_DISK");
2775
+ }
2776
+ const stat = fs.statSync(finalPath);
2777
+ return { path: finalPath, size: stat.size };
2778
+ }
2779
+ async readFinalRange(fileId, filename, start, length) {
2780
+ const finalPath = this.getFinalPath(fileId, filename);
2781
+ const buffer = Buffer.alloc(length);
2782
+ const fd = fs.openSync(finalPath, "r");
2783
+ try {
2784
+ fs.readSync(fd, buffer, 0, length, start);
2785
+ } finally {
2786
+ fs.closeSync(fd);
2787
+ }
2788
+ return buffer;
2789
+ }
2790
+ async hasTemp(fileId) {
2791
+ const tempPath = this.getTempPath(fileId);
2792
+ return fs.existsSync(tempPath);
2793
+ }
2794
+ async moveTempToFinal(fileId, filename) {
2795
+ const tempPath = this.getTempPath(fileId);
2796
+ const finalPath = this.getFinalPath(fileId, filename);
2797
+ try {
2798
+ await fs.promises.rename(tempPath, finalPath);
2799
+ } catch {
2800
+ await fs.promises.copyFile(tempPath, finalPath);
2801
+ await fs.promises.unlink(tempPath);
2802
+ }
2803
+ return finalPath;
2804
+ }
2805
+ createTempReadStream(fileId) {
2806
+ const tempPath = this.getTempPath(fileId);
2807
+ return fs.createReadStream(tempPath);
2808
+ }
2809
+ };
2384
2810
  // Annotate the CommonJS export names for ESM import in node:
2385
2811
  0 && (module.exports = {
2386
2812
  ATS1_HDR,
2387
2813
  ATS1_SCHEMA,
2388
2814
  AXIS_MAGIC,
2389
2815
  AXIS_OPCODES,
2816
+ AXIS_UPLOAD_FILE_STORE,
2817
+ AXIS_UPLOAD_RECEIPT_SIGNER,
2818
+ AXIS_UPLOAD_SESSION_STORE,
2390
2819
  AXIS_VERSION,
2391
2820
  Ats1Codec,
2821
+ AxisFilesDownloadHandler,
2822
+ AxisFilesFinalizeHandler,
2392
2823
  AxisFrameZ,
2393
2824
  AxisIdDto,
2394
2825
  AxisPacketTags,
@@ -2401,6 +2832,7 @@ function isTimestampValid(ts, skewSeconds = 120) {
2401
2832
  DEFAULT_CONTRACTS,
2402
2833
  DEFAULT_TIMEOUT,
2403
2834
  Decision,
2835
+ DiskUploadFileStore,
2404
2836
  ERR_BAD_SIGNATURE,
2405
2837
  ERR_CONTRACT_VIOLATION,
2406
2838
  ERR_INVALID_PACKET,
@@ -2412,14 +2844,18 @@ function isTimestampValid(ts, skewSeconds = 120) {
2412
2844
  FLAG_HAS_WITNESS,
2413
2845
  HANDLER_METADATA_KEY,
2414
2846
  Handler,
2847
+ INTENT_BODY_KEY,
2415
2848
  INTENT_METADATA_KEY,
2416
2849
  INTENT_REQUIREMENTS,
2417
2850
  INTENT_ROUTES_KEY,
2418
2851
  INTENT_SENSITIVITY_MAP,
2852
+ INTENT_SENSORS_KEY,
2419
2853
  INTENT_TIMEOUTS,
2420
2854
  Intent,
2855
+ IntentBody,
2421
2856
  IntentRouter,
2422
2857
  IntentSensitivity,
2858
+ IntentSensors,
2423
2859
  MAX_BODY_LEN,
2424
2860
  MAX_FRAME_LEN,
2425
2861
  MAX_HDR_LEN,