mqtt-scenario-sim 1.0.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/config.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveTopicTemplate = resolveTopicTemplate;
37
+ exports.loadConfig = loadConfig;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const yaml = __importStar(require("js-yaml"));
41
+ function resolveTopicTemplate(template, labels) {
42
+ return template.replace(/\{(\w+)\}/g, (_, key) => labels[key] ?? key);
43
+ }
44
+ function loadConfig(configPath) {
45
+ const filePath = configPath ?? path.join(__dirname, '..', 'examples', 'minimal.yaml');
46
+ const raw = fs.readFileSync(filePath, 'utf-8');
47
+ const cfg = yaml.load(raw);
48
+ const mqtt = {
49
+ host: process.env['MQTT_HOST'] ?? cfg.mqtt?.host ?? 'localhost',
50
+ port: process.env['MQTT_PORT']
51
+ ? parseInt(process.env['MQTT_PORT'], 10)
52
+ : (cfg.mqtt?.port ?? 1883),
53
+ };
54
+ const publishIntervalMs = process.env['PUBLISH_INTERVAL_MS']
55
+ ? parseInt(process.env['PUBLISH_INTERVAL_MS'], 10)
56
+ : (cfg.publishIntervalMs ?? 5000);
57
+ const encodingType = (process.env['ENCODING'] ?? cfg.encoding?.type ?? 'json');
58
+ const encoding = {
59
+ type: encodingType,
60
+ protoFile: process.env['PROTO_FILE'] ?? cfg.encoding?.protoFile,
61
+ messageType: process.env['PROTO_MESSAGE_TYPE'] ?? cfg.encoding?.messageType,
62
+ fieldMap: process.env['PROTO_FIELD_MAP']
63
+ ? JSON.parse(process.env['PROTO_FIELD_MAP'])
64
+ : cfg.encoding?.fieldMap,
65
+ };
66
+ const sources = (cfg.sources ?? []).map((s) => ({
67
+ labels: s.labels ?? {},
68
+ topic: s.topic ?? '',
69
+ metrics: s.metrics ?? [],
70
+ effects: s.effects,
71
+ }));
72
+ if (sources.length === 0) {
73
+ throw new Error('Config must define at least one source.');
74
+ }
75
+ return { mqtt, publishIntervalMs, encoding, sources };
76
+ }
77
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CS,oDAAoB;AAE7B,gCAsCC;AApFD,uCAAyB;AACzB,2CAA6B;AAC7B,8CAAgC;AAsChC,SAAS,oBAAoB,CAAC,QAAgB,EAAE,MAA8B;IAC5E,OAAO,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;AACxE,CAAC;AAID,SAAgB,UAAU,CAAC,UAAmB;IAC5C,MAAM,QAAQ,GAAG,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAA6B,CAAC;IAEvD,MAAM,IAAI,GAAG;QACX,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,WAAW;QAC/D,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YAC5B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;YACxC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC;KAC7B,CAAC;IAEF,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;QAC1D,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,EAAE,CAAC;QAClD,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC,CAAC;IAEpC,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,MAAM,CAAwB,CAAC;IACtG,MAAM,QAAQ,GAAmB;QAC/B,IAAI,EAAE,YAAY;QAClB,SAAS,EAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAY,GAAG,CAAC,QAAQ,EAAE,SAAS;QACzE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,WAAW;QAC3E,QAAQ,EAAK,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;YACzC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;YAC5C,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ;KAC3B,CAAC;IAEF,MAAM,OAAO,GAAmB,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9D,MAAM,EAAG,CAAC,CAAC,MAAM,IAAI,EAAE;QACvB,KAAK,EAAI,CAAC,CAAC,KAAK,IAAI,EAAE;QACtB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE;QACxB,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC,CAAC,CAAC;IAEJ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACxD,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface EffectConfig {
2
+ name: string;
3
+ effects: Record<string, number>;
4
+ }
5
+ export type EffectState = Record<string, boolean>;
6
+ export declare function computeBias(effectConfigs: EffectConfig[], activeEffects: EffectState, metric: string, span: number): number;
7
+ export declare function parseEffectCommand(raw: unknown): {
8
+ effect: string;
9
+ state: boolean;
10
+ } | null;
11
+ export declare function applyEffect(state: EffectState, effect: string, on: boolean): EffectState;
12
+ //# sourceMappingURL=effects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,wBAAgB,WAAW,CACzB,aAAa,EAAE,YAAY,EAAE,EAC7B,aAAa,EAAE,WAAW,EAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,MAAM,CAQR;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,OAAO,GACX;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM3C;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,OAAO,GACV,WAAW,CAEb"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeBias = computeBias;
4
+ exports.parseEffectCommand = parseEffectCommand;
5
+ exports.applyEffect = applyEffect;
6
+ function computeBias(effectConfigs, activeEffects, metric, span) {
7
+ let bias = 0;
8
+ for (const cfg of effectConfigs) {
9
+ if (activeEffects[cfg.name] && cfg.effects[metric] !== undefined) {
10
+ bias += cfg.effects[metric] * span;
11
+ }
12
+ }
13
+ return bias;
14
+ }
15
+ function parseEffectCommand(raw) {
16
+ if (typeof raw !== 'object' || raw === null)
17
+ return null;
18
+ const msg = raw;
19
+ if (typeof msg['effect'] !== 'string')
20
+ return null;
21
+ if (typeof msg['state'] !== 'boolean')
22
+ return null;
23
+ return { effect: msg['effect'], state: msg['state'] };
24
+ }
25
+ function applyEffect(state, effect, on) {
26
+ return { ...state, [effect]: on };
27
+ }
28
+ //# sourceMappingURL=effects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effects.js","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":";;AAOA,kCAaC;AAED,gDAQC;AAED,kCAMC;AA/BD,SAAgB,WAAW,CACzB,aAA6B,EAC7B,aAA0B,EAC1B,MAAc,EACd,IAAY;IAEZ,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;YACjE,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAE,GAAG,IAAI,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,kBAAkB,CAChC,GAAY;IAEZ,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,IAAI,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAW,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAY,EAAE,CAAC;AAC7E,CAAC;AAED,SAAgB,WAAW,CACzB,KAAkB,EAClB,MAAc,EACd,EAAW;IAEX,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC;AACpC,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface Reading {
2
+ labels: Record<string, string>;
3
+ metric: string;
4
+ value: number;
5
+ units: string;
6
+ timestamp: number;
7
+ }
8
+ export type EncodeFunction = (reading: Reading) => Buffer | Promise<Buffer>;
9
+ export interface EncodingConfig {
10
+ type: 'json' | 'protobuf';
11
+ protoFile?: string;
12
+ messageType?: string;
13
+ fieldMap?: Record<string, string>;
14
+ }
15
+ export declare function buildEncoder(config: EncodingConfig): EncodeFunction;
16
+ export declare const jsonEncoder: EncodeFunction;
17
+ //# sourceMappingURL=encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../src/encoder.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE5E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAuBD,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CA4BnE;AAED,eAAO,MAAM,WAAW,EAAE,cACsC,CAAC"}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.jsonEncoder = void 0;
37
+ exports.buildEncoder = buildEncoder;
38
+ const path = __importStar(require("path"));
39
+ const protobuf = __importStar(require("protobufjs"));
40
+ function applyFieldMap(reading, fieldMap) {
41
+ if (!fieldMap) {
42
+ return { ...reading.labels, ...reading };
43
+ }
44
+ const flat = { ...reading.labels, ...reading };
45
+ const mapped = {};
46
+ for (const [from, to] of Object.entries(fieldMap)) {
47
+ if (flat[from] !== undefined) {
48
+ mapped[to] = flat[from];
49
+ }
50
+ }
51
+ // Pass through unmapped fields
52
+ for (const [k, v] of Object.entries(flat)) {
53
+ if (!fieldMap[k])
54
+ mapped[k] = v;
55
+ }
56
+ return mapped;
57
+ }
58
+ function buildEncoder(config) {
59
+ if (config.type === 'json') {
60
+ return (reading) => Buffer.from(JSON.stringify(applyFieldMap(reading, config.fieldMap)));
61
+ }
62
+ if (!config.protoFile) {
63
+ throw new Error('encoding.protoFile is required when encoding.type is "protobuf"');
64
+ }
65
+ if (!config.messageType) {
66
+ throw new Error('encoding.messageType is required when encoding.type is "protobuf"');
67
+ }
68
+ const protoFile = path.resolve(config.protoFile);
69
+ const messageType = config.messageType;
70
+ const fieldMap = config.fieldMap;
71
+ let cachedType = null;
72
+ return async (reading) => {
73
+ if (!cachedType) {
74
+ const root = await protobuf.load(protoFile);
75
+ cachedType = root.lookupType(messageType);
76
+ }
77
+ const msg = applyFieldMap(reading, fieldMap);
78
+ const errMsg = cachedType.verify(msg);
79
+ if (errMsg)
80
+ throw new Error(`Protobuf verify failed: ${errMsg}`);
81
+ return Buffer.from(cachedType.encode(cachedType.create(msg)).finish());
82
+ };
83
+ }
84
+ const jsonEncoder = (reading) => Buffer.from(JSON.stringify({ ...reading.labels, ...reading }));
85
+ exports.jsonEncoder = jsonEncoder;
86
+ //# sourceMappingURL=encoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoder.js","sourceRoot":"","sources":["../src/encoder.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,oCA4BC;AArED,2CAA6B;AAC7B,qDAAuC;AAmBvC,SAAS,aAAa,CACpB,OAAgB,EAChB,QAA4C;IAE5C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;IAC3C,CAAC;IACD,MAAM,IAAI,GAA4B,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;IACxE,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClD,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,+BAA+B;IAC/B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,YAAY,CAAC,MAAsB;IACjD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,SAAS,GAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,MAAM,WAAW,GAAI,MAAM,CAAC,WAAW,CAAC;IACxC,MAAM,QAAQ,GAAO,MAAM,CAAC,QAAQ,CAAC;IAErC,IAAI,UAAU,GAAyB,IAAI,CAAC;IAE5C,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC5C,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,GAAG,GAAM,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,EAAE,CAAC,CAAC;QACjE,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC;AACJ,CAAC;AAEM,MAAM,WAAW,GAAmB,CAAC,OAAO,EAAE,EAAE,CACrD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC;AADpD,QAAA,WAAW,eACyC"}
@@ -0,0 +1,13 @@
1
+ export { startSimulator } from './simulator';
2
+ export type { Simulator, StateSnapshot, MetricSnapshot, PublishEvent } from './simulator';
3
+ export { buildEncoder, jsonEncoder } from './encoder';
4
+ export type { EncodeFunction, EncodingConfig, Reading } from './encoder';
5
+ export { loadConfig } from './config';
6
+ export type { SimulatorConfig, SourceConfig, MetricConfig } from './config';
7
+ export type { EffectConfig, EffectState } from './effects';
8
+ export type { ScenarioId } from './scenarios';
9
+ export { SCENARIO_KEYS, SCENARIO_LABELS, SCENARIO_DETAIL } from './scenarios';
10
+ export type { SensorMode, SensorRange } from './sensors';
11
+ export { logger } from './logger';
12
+ export type { LogLevel } from './logger';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACtD,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9E,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = exports.SCENARIO_DETAIL = exports.SCENARIO_LABELS = exports.SCENARIO_KEYS = exports.loadConfig = exports.jsonEncoder = exports.buildEncoder = exports.startSimulator = void 0;
4
+ var simulator_1 = require("./simulator");
5
+ Object.defineProperty(exports, "startSimulator", { enumerable: true, get: function () { return simulator_1.startSimulator; } });
6
+ var encoder_1 = require("./encoder");
7
+ Object.defineProperty(exports, "buildEncoder", { enumerable: true, get: function () { return encoder_1.buildEncoder; } });
8
+ Object.defineProperty(exports, "jsonEncoder", { enumerable: true, get: function () { return encoder_1.jsonEncoder; } });
9
+ var config_1 = require("./config");
10
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
11
+ var scenarios_1 = require("./scenarios");
12
+ Object.defineProperty(exports, "SCENARIO_KEYS", { enumerable: true, get: function () { return scenarios_1.SCENARIO_KEYS; } });
13
+ Object.defineProperty(exports, "SCENARIO_LABELS", { enumerable: true, get: function () { return scenarios_1.SCENARIO_LABELS; } });
14
+ Object.defineProperty(exports, "SCENARIO_DETAIL", { enumerable: true, get: function () { return scenarios_1.SCENARIO_DETAIL; } });
15
+ var logger_1 = require("./logger");
16
+ Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA6C;AAApC,2GAAA,cAAc,OAAA;AAEvB,qCAAsD;AAA7C,uGAAA,YAAY,OAAA;AAAE,sGAAA,WAAW,OAAA;AAElC,mCAAsC;AAA7B,oGAAA,UAAU,OAAA;AAInB,yCAA8E;AAArE,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,4GAAA,eAAe,OAAA;AAExD,mCAAkC;AAAzB,gGAAA,MAAM,OAAA"}
@@ -0,0 +1,9 @@
1
+ export type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'debug';
2
+ export declare const logger: {
3
+ setLevel(level: string): void;
4
+ debug(...args: unknown[]): void;
5
+ info(...args: unknown[]): void;
6
+ warn(...args: unknown[]): void;
7
+ error(...args: unknown[]): void;
8
+ };
9
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AActE,eAAO,MAAM,MAAM;oBACD,MAAM,GAAG,IAAI;mBASd,OAAO,EAAE,GAAG,IAAI;kBACjB,OAAO,EAAE,GAAG,IAAI;kBAChB,OAAO,EAAE,GAAG,IAAI;mBACf,OAAO,EAAE,GAAG,IAAI;CAChC,CAAC"}
package/dist/logger.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = void 0;
4
+ const LEVELS = {
5
+ silent: 0,
6
+ error: 1,
7
+ warn: 2,
8
+ info: 3,
9
+ debug: 4,
10
+ };
11
+ const VALID_LEVELS = Object.keys(LEVELS);
12
+ let current = LEVELS['info'];
13
+ exports.logger = {
14
+ setLevel(level) {
15
+ const l = level.toLowerCase();
16
+ if (!VALID_LEVELS.includes(l)) {
17
+ console.warn(`[logger] unknown level "${level}", using "info". Valid: ${VALID_LEVELS.join(', ')}`);
18
+ return;
19
+ }
20
+ current = LEVELS[l];
21
+ },
22
+ debug(...args) { if (current >= 4)
23
+ console.log(...args); },
24
+ info(...args) { if (current >= 3)
25
+ console.log(...args); },
26
+ warn(...args) { if (current >= 2)
27
+ console.warn(...args); },
28
+ error(...args) { if (current >= 1)
29
+ console.error(...args); },
30
+ };
31
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;AAEA,MAAM,MAAM,GAA6B;IACvC,MAAM,EAAE,CAAC;IACT,KAAK,EAAG,CAAC;IACT,IAAI,EAAI,CAAC;IACT,IAAI,EAAI,CAAC;IACT,KAAK,EAAG,CAAC;CACV,CAAC;AAEF,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAe,CAAC;AAEvD,IAAI,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;AAEhB,QAAA,MAAM,GAAG;IACpB,QAAQ,CAAC,KAAa;QACpB,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAc,CAAC;QAC1C,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,2BAA2B,KAAK,2BAA2B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnG,OAAO;QACT,CAAC;QACD,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,GAAG,IAAe,IAAU,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,CAAC,GAAG,IAAe,IAAW,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,CAAC,GAAG,IAAe,IAAW,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5E,KAAK,CAAC,GAAG,IAAe,IAAU,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;CAC9E,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { ResolvedRange } from './sensors';
2
+ export type ScenarioId = 'normal' | 'out_of_range' | 'trending_to_breach' | 'stable_healthy' | 'recovery' | 'oscillating';
3
+ export declare const SCENARIO_KEYS: Record<string, ScenarioId>;
4
+ export declare const SCENARIO_LABELS: Record<ScenarioId, string>;
5
+ export declare const SCENARIO_DETAIL: Record<ScenarioId, string>;
6
+ export declare function scenarioValue(id: ScenarioId, resolved: ResolvedRange, tick: number, rand: number): number | null;
7
+ //# sourceMappingURL=scenarios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarios.d.ts","sourceRoot":"","sources":["../src/scenarios.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR,cAAc,GACd,oBAAoB,GACpB,gBAAgB,GAChB,UAAU,GACV,aAAa,CAAC;AAElB,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAcpD,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAOtD,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAgBtD,CAAC;AAEF,wBAAgB,aAAa,CAC3B,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAkCf"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SCENARIO_DETAIL = exports.SCENARIO_LABELS = exports.SCENARIO_KEYS = void 0;
4
+ exports.scenarioValue = scenarioValue;
5
+ exports.SCENARIO_KEYS = {
6
+ '0': 'normal',
7
+ 'n': 'normal',
8
+ 'normal': 'normal',
9
+ '1': 'out_of_range',
10
+ 'out_of_range': 'out_of_range',
11
+ '2': 'trending_to_breach',
12
+ 'trending_to_breach': 'trending_to_breach',
13
+ '3': 'stable_healthy',
14
+ 'stable_healthy': 'stable_healthy',
15
+ '4': 'recovery',
16
+ 'recovery': 'recovery',
17
+ '5': 'oscillating',
18
+ 'oscillating': 'oscillating',
19
+ };
20
+ exports.SCENARIO_LABELS = {
21
+ normal: "0 / n — Normal (uses each metric's configured mode)",
22
+ out_of_range: '1 — Out of range (values 30% above max)',
23
+ trending_to_breach: '2 — Trending to breach (rising toward max; visible after ~2 min)',
24
+ stable_healthy: '3 — Stable & healthy (held at midpoint ideal)',
25
+ recovery: '4 — Recovery (starts out-of-range, decays to ideal over ~5 min)',
26
+ oscillating: '5 — Oscillating (±10% swing around ideal)',
27
+ };
28
+ exports.SCENARIO_DETAIL = {
29
+ normal: "Each metric runs its configured mode: sinusoidal, drift, normal, or spike.",
30
+ out_of_range: 'All metrics emit 30% above their max boundary. Tests threshold breach detection.',
31
+ trending_to_breach: 'Metrics rise from 70% toward 99% of max (0.5% of span per tick). ' +
32
+ 'Tests early-warning alert logic. Allow ~2 min for analysis caches to fill.',
33
+ stable_healthy: 'All metrics held at their midpoint ideal (±0.3% noise). Tests steady-state handling.',
34
+ recovery: 'Starts 30% above max; decays linearly to midpoint ideal over ~5 min. ' +
35
+ 'Tests resolved-alert and recovery detection.',
36
+ oscillating: 'Rapid ±10% oscillation around midpoint ideal (full cycle every 8 ticks). ' +
37
+ 'Tests alert flapping suppression and jitter handling.',
38
+ };
39
+ function scenarioValue(id, resolved, tick, rand) {
40
+ if (id === 'normal')
41
+ return null;
42
+ const { min, max } = resolved;
43
+ const span = max - min;
44
+ const ideal = (min + max) / 2;
45
+ switch (id) {
46
+ case 'out_of_range':
47
+ return round2(max + span * 0.30);
48
+ case 'trending_to_breach': {
49
+ const start = min + span * 0.70;
50
+ const ceiling = min + span * 0.99;
51
+ const rising = Math.min(start + tick * span * 0.005, ceiling);
52
+ return round2(rising + (rand - 0.5) * span * 0.003);
53
+ }
54
+ case 'stable_healthy':
55
+ return round2(ideal + (rand - 0.5) * span * 0.003);
56
+ case 'recovery': {
57
+ const DECAY_TICKS = 60;
58
+ const start = max + span * 0.30;
59
+ const progress = Math.min(tick / DECAY_TICKS, 1);
60
+ return round2(start + (ideal - start) * progress + (rand - 0.5) * span * 0.003);
61
+ }
62
+ case 'oscillating': {
63
+ const amplitude = span * 0.10;
64
+ const wave = Math.sin((2 * Math.PI * tick) / 8) * amplitude;
65
+ return round2(ideal + wave + (rand - 0.5) * span * 0.005);
66
+ }
67
+ }
68
+ }
69
+ function round2(v) {
70
+ return Math.round(v * 100) / 100;
71
+ }
72
+ //# sourceMappingURL=scenarios.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarios.js","sourceRoot":"","sources":["../src/scenarios.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ export type SensorMode = 'sinusoidal' | 'normal' | 'drift' | 'spike';
2
+ export interface SensorRange {
3
+ low: number;
4
+ high: number;
5
+ }
6
+ export interface ResolvedRange {
7
+ baseline: number;
8
+ amplitude: number;
9
+ min: number;
10
+ max: number;
11
+ driftRate: number;
12
+ spikeProbability: number;
13
+ spikeMagnitude: number;
14
+ }
15
+ export interface SensorState {
16
+ config: {
17
+ mode: SensorMode;
18
+ periodSeconds: number;
19
+ intervalMs: number;
20
+ };
21
+ resolved: ResolvedRange;
22
+ phase: number;
23
+ driftValue: number;
24
+ currentBias: number;
25
+ lastValue: number | null;
26
+ lastPublishedAt: number | null;
27
+ }
28
+ export declare function resolveRange(range: SensorRange, overrides?: {
29
+ baseline?: number;
30
+ amplitude?: number;
31
+ driftRate?: number;
32
+ spikeProbability?: number;
33
+ spikeMagnitude?: number;
34
+ min?: number;
35
+ max?: number;
36
+ }): ResolvedRange;
37
+ export declare function createSensorState(cfg: {
38
+ mode: SensorMode;
39
+ range: SensorRange;
40
+ baseline?: number;
41
+ amplitude?: number;
42
+ driftRate?: number;
43
+ spikeProbability?: number;
44
+ spikeMagnitude?: number;
45
+ min?: number;
46
+ max?: number;
47
+ periodSeconds?: number;
48
+ intervalMs: number;
49
+ }): SensorState;
50
+ export declare function nextValue(state: SensorState, bias?: number): number;
51
+ export declare function advanceBias(state: SensorState, target: number): void;
52
+ //# sourceMappingURL=sensors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensors.d.ts","sourceRoot":"","sources":["../src/sensors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;AAErE,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE;QACN,IAAI,EAAE,UAAU,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,EAClB,SAAS,GAAE;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACT,GACL,aAAa,CAWf;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE;IACrC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,WAAW,CAed;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,GAAE,MAAU,GAAG,MAAM,CAuCtE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAGpE"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRange = resolveRange;
4
+ exports.createSensorState = createSensorState;
5
+ exports.nextValue = nextValue;
6
+ exports.advanceBias = advanceBias;
7
+ function resolveRange(range, overrides = {}) {
8
+ const span = range.high - range.low;
9
+ return {
10
+ baseline: overrides.baseline ?? (range.low + range.high) / 2,
11
+ amplitude: overrides.amplitude ?? span / 2,
12
+ min: overrides.min ?? range.low,
13
+ max: overrides.max ?? range.high,
14
+ driftRate: overrides.driftRate ?? span * 0.002,
15
+ spikeProbability: overrides.spikeProbability ?? 0.03,
16
+ spikeMagnitude: overrides.spikeMagnitude ?? span * 0.25,
17
+ };
18
+ }
19
+ function createSensorState(cfg) {
20
+ const resolved = resolveRange(cfg.range, cfg);
21
+ return {
22
+ config: {
23
+ mode: cfg.mode,
24
+ periodSeconds: cfg.periodSeconds ?? 3600,
25
+ intervalMs: cfg.intervalMs,
26
+ },
27
+ resolved,
28
+ phase: Math.random() * 2 * Math.PI,
29
+ driftValue: resolved.baseline,
30
+ currentBias: 0,
31
+ lastValue: null,
32
+ lastPublishedAt: null,
33
+ };
34
+ }
35
+ function nextValue(state, bias = 0) {
36
+ const { resolved, config } = state;
37
+ const { baseline, amplitude, min, max } = resolved;
38
+ let raw;
39
+ switch (config.mode) {
40
+ case 'sinusoidal': {
41
+ const ticksPerPeriod = (config.periodSeconds * 1000) / config.intervalMs;
42
+ state.phase += (2 * Math.PI) / ticksPerPeriod;
43
+ raw = baseline + amplitude * Math.sin(state.phase);
44
+ break;
45
+ }
46
+ case 'normal': {
47
+ const u1 = Math.random(), u2 = Math.random();
48
+ const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
49
+ raw = baseline + (amplitude * 0.3) * z;
50
+ break;
51
+ }
52
+ case 'drift': {
53
+ state.driftValue += resolved.driftRate * (Math.random() > 0.5 ? 1 : -1);
54
+ if (state.driftValue > max)
55
+ state.driftValue = max - resolved.driftRate;
56
+ if (state.driftValue < min)
57
+ state.driftValue = min + resolved.driftRate;
58
+ raw = state.driftValue;
59
+ break;
60
+ }
61
+ case 'spike': {
62
+ const spike = Math.random() < resolved.spikeProbability
63
+ ? (Math.random() > 0.5 ? 1 : -1) * resolved.spikeMagnitude
64
+ : 0;
65
+ const u1 = Math.random(), u2 = Math.random();
66
+ const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
67
+ raw = baseline + (amplitude * 0.2) * z + spike;
68
+ break;
69
+ }
70
+ }
71
+ const clamped = Math.max(min, Math.min(max, raw + bias));
72
+ return Math.round(clamped * 100) / 100;
73
+ }
74
+ function advanceBias(state, target) {
75
+ const alpha = 0.2;
76
+ state.currentBias = state.currentBias + alpha * (target - state.currentBias);
77
+ }
78
+ //# sourceMappingURL=sensors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensors.js","sourceRoot":"","sources":["../src/sensors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import * as mqtt from 'mqtt';
2
+ import { SimulatorConfig } from './config';
3
+ import { EncodeFunction } from './encoder';
4
+ import { ScenarioId } from './scenarios';
5
+ import { EffectState } from './effects';
6
+ export interface MetricSnapshot {
7
+ labels: Record<string, string>;
8
+ metric: string;
9
+ units: string;
10
+ value: number | null;
11
+ lastPublishedAt: number | null;
12
+ }
13
+ export interface StateSnapshot {
14
+ scenario: ScenarioId;
15
+ metrics: MetricSnapshot[];
16
+ }
17
+ export interface PublishEvent {
18
+ labels: Record<string, string>;
19
+ topic: string;
20
+ metric: string;
21
+ units: string;
22
+ value: number;
23
+ scenario: ScenarioId;
24
+ timestamp: number;
25
+ }
26
+ export interface Simulator {
27
+ stop(): void;
28
+ setScenario(id: ScenarioId, sourceKey?: string, durationSeconds?: number): void;
29
+ getScenario(sourceKey?: string): ScenarioId;
30
+ getState(): StateSnapshot;
31
+ getEffectStates(): Record<string, EffectState>;
32
+ onPublish(listener: (event: PublishEvent) => void): () => void;
33
+ }
34
+ export declare function startSimulator(config: SimulatorConfig, client: mqtt.MqttClient, encode: EncodeFunction): Simulator;
35
+ //# sourceMappingURL=simulator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simulator.d.ts","sourceRoot":"","sources":["../src/simulator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAoD,MAAM,UAAU,CAAC;AAE7F,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAkC,MAAM,aAAa,CAAC;AACzE,OAAO,EAAgB,WAAW,EAAgD,MAAM,WAAW,CAAC;AAGpG,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,IAAI,IAAI,CAAC;IACb,WAAW,CAAC,EAAE,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChF,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC5C,QAAQ,IAAI,aAAa,CAAC;IAC1B,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC/C,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAChE;AAgBD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,IAAI,CAAC,UAAU,EACvB,MAAM,EAAE,cAAc,GACrB,SAAS,CAoJX"}