miravo 0.6.0 → 0.6.2

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.
Files changed (187) hide show
  1. package/LICENSE +199 -0
  2. package/README.md +29 -59
  3. package/bin/miravo.js +84 -0
  4. package/package.json +21 -37
  5. package/console-dist/assets/activity-DsWeRq4h.js +0 -1
  6. package/console-dist/assets/api-4AqKvsm9.js +0 -1
  7. package/console-dist/assets/arrow-right-Ea_UhTNi.js +0 -1
  8. package/console-dist/assets/arrow-up-down-DFSjzzl2.js +0 -1
  9. package/console-dist/assets/blueprint-card-classes-DBFCDy0M.js +0 -1
  10. package/console-dist/assets/box-C1WaoOMF.js +0 -1
  11. package/console-dist/assets/card-BjeP32PN.js +0 -1
  12. package/console-dist/assets/catalog-BJzyzbLR.js +0 -1
  13. package/console-dist/assets/catalog-DKjEm-c4.js +0 -1
  14. package/console-dist/assets/catalog-template-icons-BrUeHaCY.js +0 -1
  15. package/console-dist/assets/checkbox-DZlJXTE4.js +0 -1
  16. package/console-dist/assets/chunk-OE4NN4TA-CEjpfhS6.js +0 -3
  17. package/console-dist/assets/combobox-BGnuCYxO.js +0 -1
  18. package/console-dist/assets/control-CPhvwx9o.js +0 -1
  19. package/console-dist/assets/control-Cg2up9NA.js +0 -1
  20. package/console-dist/assets/copy-button-WkbNkMcd.js +0 -1
  21. package/console-dist/assets/createLucideIcon-Bwxw859K.js +0 -1
  22. package/console-dist/assets/deploy-tab-JeWDwPoZ.js +0 -1
  23. package/console-dist/assets/dist-BhbDML0a.js +0 -1
  24. package/console-dist/assets/dist-Cy8XTNFT.js +0 -2
  25. package/console-dist/assets/download-DQ6NH16U.js +0 -1
  26. package/console-dist/assets/engine-store-CrLnz692.js +0 -1
  27. package/console-dist/assets/events-CXm29Ok4.js +0 -1
  28. package/console-dist/assets/events-D01IxhnP.js +0 -1
  29. package/console-dist/assets/fira-code-cyrillic-ext-wght-normal-DhYMMuQd.woff2 +0 -0
  30. package/console-dist/assets/fira-code-cyrillic-wght-normal-Y3u8pIsh.woff2 +0 -0
  31. package/console-dist/assets/fira-code-greek-ext-wght-normal-wWus70Ix.woff2 +0 -0
  32. package/console-dist/assets/fira-code-greek-wght-normal-B2SviObF.woff2 +0 -0
  33. package/console-dist/assets/fira-code-latin-ext-wght-normal-Dvfvaomy.woff2 +0 -0
  34. package/console-dist/assets/fira-code-latin-wght-normal-CHoedHDv.woff2 +0 -0
  35. package/console-dist/assets/fira-code-symbols2-wght-normal-CE6EOz_n.woff2 +0 -0
  36. package/console-dist/assets/fleet-CfxbKXt9.js +0 -1
  37. package/console-dist/assets/fleet-lotMGVqe.js +0 -1
  38. package/console-dist/assets/format-kXTonpDJ.js +0 -1
  39. package/console-dist/assets/gauge-Ci8zNZlk.js +0 -1
  40. package/console-dist/assets/get-error-message-3Q5Q-2G5.js +0 -1
  41. package/console-dist/assets/index-CVPKSDvJ.js +0 -12
  42. package/console-dist/assets/index-DJkgDeun.css +0 -2
  43. package/console-dist/assets/input-BWEQFptx.js +0 -1
  44. package/console-dist/assets/instance-detail-C5IVwuh3.js +0 -1
  45. package/console-dist/assets/karla-latin-ext-wght-normal-Dq0rrjgs.woff2 +0 -0
  46. package/console-dist/assets/karla-latin-wght-normal-C3-ma4ov.woff2 +0 -0
  47. package/console-dist/assets/label-uephX5ZG.js +0 -1
  48. package/console-dist/assets/layers-CUsLQ1fq.js +0 -1
  49. package/console-dist/assets/login-C3RJli0m.js +0 -126
  50. package/console-dist/assets/models-B_UioWQ5.js +0 -1
  51. package/console-dist/assets/models-_IPlPiZ7.js +0 -1
  52. package/console-dist/assets/not-found-B8gAm08S.js +0 -1
  53. package/console-dist/assets/platform-targets-R3T-4eJ7.js +0 -1
  54. package/console-dist/assets/platforms-BWh0BQ3Y.js +0 -1
  55. package/console-dist/assets/platforms-DStNbtVc.js +0 -1
  56. package/console-dist/assets/proxy-CsnYqnPp.js +0 -9
  57. package/console-dist/assets/query-keys-BvtE7BMs.js +0 -1
  58. package/console-dist/assets/radio-CoHegOv5.js +0 -1
  59. package/console-dist/assets/rolldown-runtime-COnpUsM8.js +0 -1
  60. package/console-dist/assets/schibsted-grotesk-latin-ext-wght-normal-hsMS0n0O.woff2 +0 -0
  61. package/console-dist/assets/schibsted-grotesk-latin-wght-normal-Bb8VGrTG.woff2 +0 -0
  62. package/console-dist/assets/select-CeO4vP0G.js +0 -1
  63. package/console-dist/assets/select-display-items-CIzY8953.js +0 -1
  64. package/console-dist/assets/server-D9Kfn8fQ.js +0 -1
  65. package/console-dist/assets/shallow-6lGjQhtJ.js +0 -1
  66. package/console-dist/assets/tags-CiXOIHtY.js +0 -4
  67. package/console-dist/assets/tags-FQCXIxrP.js +0 -1
  68. package/console-dist/assets/tooltip-HGLF366Q.js +0 -1
  69. package/console-dist/assets/transition-nav-link-Df4Rk6vV.js +0 -1
  70. package/console-dist/assets/transition-types-CPlGtM8w.js +0 -1
  71. package/console-dist/assets/triangle-alert-adNk_sea.js +0 -1
  72. package/console-dist/assets/use-platform-stream-DGbK1k2L.js +0 -2
  73. package/console-dist/assets/use-transition-navigate-CCpcWXB0.js +0 -2
  74. package/console-dist/assets/validation-Blvud9_O.js +0 -1
  75. package/console-dist/assets/vendor-charts-CAZdaPlq.js +0 -60
  76. package/console-dist/assets/vendor-table-wd8JuMmT.js +0 -4
  77. package/console-dist/assets/vendor-ui-ByahnaY0.js +0 -1
  78. package/console-dist/favicon.svg +0 -37
  79. package/console-dist/index.html +0 -82
  80. package/console-dist/miravo-logo.png +0 -0
  81. package/src/__tests__/integration/executable-methods-runner.ts +0 -262
  82. package/src/__tests__/integration/executable-methods.integration.ts +0 -2348
  83. package/src/__tests__/integration/opcua-concurrent-clients.integration.ts +0 -314
  84. package/src/commands/adapter.ts +0 -249
  85. package/src/commands/apply.test.ts +0 -62
  86. package/src/commands/apply.ts +0 -216
  87. package/src/commands/cleanup.test.ts +0 -34
  88. package/src/commands/cleanup.ts +0 -201
  89. package/src/commands/cli-test-setup.ts +0 -91
  90. package/src/commands/export.test.ts +0 -51
  91. package/src/commands/export.ts +0 -404
  92. package/src/commands/fork.ts +0 -219
  93. package/src/commands/inject.test.ts +0 -57
  94. package/src/commands/inject.ts +0 -212
  95. package/src/commands/load.ts +0 -167
  96. package/src/commands/logs.ts +0 -173
  97. package/src/commands/models.test.ts +0 -162
  98. package/src/commands/models.ts +0 -338
  99. package/src/commands/pause.ts +0 -67
  100. package/src/commands/platforms.test.ts +0 -186
  101. package/src/commands/platforms.ts +0 -371
  102. package/src/commands/ps.ts +0 -116
  103. package/src/commands/remove.ts +0 -38
  104. package/src/commands/reset.ts +0 -44
  105. package/src/commands/rm.ts +0 -97
  106. package/src/commands/spawn.ts +0 -45
  107. package/src/commands/speed.ts +0 -40
  108. package/src/commands/start/adapter-config.ts +0 -157
  109. package/src/commands/start/catalog-le-dt.test.ts +0 -50
  110. package/src/commands/start/catalog-le-dt.ts +0 -187
  111. package/src/commands/start/catalog-model-schema.ts +0 -89
  112. package/src/commands/start/catalog-template-detail.ts +0 -54
  113. package/src/commands/start/daemon.ts +0 -255
  114. package/src/commands/start/display.ts +0 -150
  115. package/src/commands/start/engine-setup.ts +0 -247
  116. package/src/commands/start/events.ts +0 -126
  117. package/src/commands/start/index.ts +0 -897
  118. package/src/commands/start/protocol-plans.ts +0 -239
  119. package/src/commands/start/template-loader.ts +0 -197
  120. package/src/commands/start/template-resolver.ts +0 -185
  121. package/src/commands/start/types.ts +0 -73
  122. package/src/commands/start.test.ts +0 -480
  123. package/src/commands/status.test.ts +0 -20
  124. package/src/commands/status.ts +0 -470
  125. package/src/commands/stop.test.ts +0 -84
  126. package/src/commands/stop.ts +0 -169
  127. package/src/commands/templates.test.ts +0 -58
  128. package/src/commands/templates.ts +0 -277
  129. package/src/index.ts +0 -166
  130. package/src/lib/admin-auth.ts +0 -157
  131. package/src/lib/admin-client.test.ts +0 -51
  132. package/src/lib/admin-client.ts +0 -326
  133. package/src/lib/admin-platform-routes.ts +0 -1017
  134. package/src/lib/admin-platform-stream.test.ts +0 -434
  135. package/src/lib/admin-platform-stream.ts +0 -788
  136. package/src/lib/admin-responses.ts +0 -211
  137. package/src/lib/admin-server.test.ts +0 -781
  138. package/src/lib/admin-server.ts +0 -797
  139. package/src/lib/auth-store.ts +0 -87
  140. package/src/lib/daemon-registry.test.ts +0 -429
  141. package/src/lib/daemon-registry.ts +0 -343
  142. package/src/lib/le/le-apply.test.ts +0 -591
  143. package/src/lib/le/le-apply.ts +0 -832
  144. package/src/lib/le/le-auth.ts +0 -89
  145. package/src/lib/le/le-cleanup.test.ts +0 -168
  146. package/src/lib/le/le-cleanup.ts +0 -399
  147. package/src/lib/le/le-cli-helpers.ts +0 -77
  148. package/src/lib/le/le-client.ts +0 -184
  149. package/src/lib/le/le-concurrency.test.ts +0 -157
  150. package/src/lib/le/le-concurrency.ts +0 -78
  151. package/src/lib/le/le-connection-test.ts +0 -42
  152. package/src/lib/le/le-devicehub-properties.test.ts +0 -53
  153. package/src/lib/le/le-devicehub-properties.ts +0 -33
  154. package/src/lib/le/le-devicehub.ts +0 -213
  155. package/src/lib/le/le-digital-twins.ts +0 -285
  156. package/src/lib/le/le-drivers.ts +0 -23
  157. package/src/lib/le/le-endpoint.ts +0 -40
  158. package/src/lib/le/le-environments.test.ts +0 -73
  159. package/src/lib/le/le-environments.ts +0 -156
  160. package/src/lib/le/le-markers.ts +0 -87
  161. package/src/lib/le/le-plan.test.ts +0 -26
  162. package/src/lib/le/le-plan.ts +0 -109
  163. package/src/lib/le/le-platform-operations.test.ts +0 -198
  164. package/src/lib/le/le-platform-operations.ts +0 -340
  165. package/src/lib/le/le-static-model-schema.ts +0 -78
  166. package/src/lib/le/le-static-planner.test.ts +0 -255
  167. package/src/lib/le/le-static-planner.ts +0 -442
  168. package/src/lib/le/le-template-exporter.test.ts +0 -527
  169. package/src/lib/le/le-template-exporter.ts +0 -459
  170. package/src/lib/le/le-value-types.ts +0 -23
  171. package/src/lib/mqtt-client.ts +0 -115
  172. package/src/lib/parse.test.ts +0 -123
  173. package/src/lib/parse.ts +0 -87
  174. package/src/lib/resolve-simulation.test.ts +0 -118
  175. package/src/lib/resolve-simulation.ts +0 -181
  176. package/src/lib/session-store.ts +0 -110
  177. package/src/lib/shutdown.test.ts +0 -562
  178. package/src/lib/shutdown.ts +0 -621
  179. package/src/lib/template-category.test.ts +0 -71
  180. package/src/lib/template-category.ts +0 -72
  181. package/src/lib/template-locator.ts +0 -55
  182. package/src/lib/template-utils.ts +0 -45
  183. package/src/lib/ws-hub.ts +0 -281
  184. package/src/logger.test.ts +0 -172
  185. package/src/logger.ts +0 -402
  186. package/src/output.test.ts +0 -64
  187. package/src/output.ts +0 -160
@@ -1,37 +0,0 @@
1
- <svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
2
- <defs>
3
- <!-- Subtle mirror gradient -->
4
- <linearGradient id="mirror" x1="0" y1="0" x2="0" y2="1">
5
- <stop offset="0%" stop-color="#f6d28a"/>
6
- <stop offset="50%" stop-color="#e5a218"/>
7
- <stop offset="100%" stop-color="#c58514"/>
8
- </linearGradient>
9
- </defs>
10
-
11
- <!-- Left M shape -->
12
- <path d="M10 12 L30 12 L21 28 L10 28 Z"
13
- fill="#e5a218"
14
- stroke="#e5a218"
15
- stroke-width="1.2"
16
- stroke-linejoin="round"/>
17
- <path d="M10 28 L21 28 L21 52 L10 48 Z"
18
- fill="#e5a218"
19
- stroke="#e5a218"
20
- stroke-width="1.2"
21
- stroke-linejoin="round"/>
22
-
23
- <!-- Right mirrored M -->
24
- <path d="M54 12 L34 12 L43 28 L54 28 Z"
25
- fill="#e5a218"
26
- stroke="#e5a218"
27
- stroke-width="1.2"
28
- stroke-linejoin="round"/>
29
- <path d="M54 28 L43 28 L43 52 L54 48 Z"
30
- fill="#e5a218"
31
- stroke="#e5a218"
32
- stroke-width="1.2"
33
- stroke-linejoin="round"/>
34
-
35
- <!-- Mirror axis (thin + subtle reflective feel) -->
36
- <rect x="31.5" y="10" width="1" height="44" rx="0.5" fill="url(#mirror)" opacity="0.9"/>
37
- </svg>
@@ -1,82 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <link rel="preload" href="/assets/fira-code-latin-wght-normal-CHoedHDv.woff2" as="font" type="font/woff2" crossorigin="anonymous">
5
- <link rel="preload" href="/assets/karla-latin-wght-normal-C3-ma4ov.woff2" as="font" type="font/woff2" crossorigin="anonymous">
6
- <link rel="preload" href="/assets/schibsted-grotesk-latin-wght-normal-Bb8VGrTG.woff2" as="font" type="font/woff2" crossorigin="anonymous">
7
-
8
- <meta charset="UTF-8" />
9
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
10
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11
- <meta name="theme-color" content="#0b0f12" />
12
- <style>
13
- html,
14
- body,
15
- #root {
16
- height: 100%;
17
- }
18
- html,
19
- body {
20
- margin: 0;
21
- background: #0b0f12;
22
- color-scheme: dark;
23
- }
24
- </style>
25
- <title>Miravo</title>
26
- <script type="module" crossorigin src="/assets/index-CVPKSDvJ.js"></script>
27
- <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-COnpUsM8.js">
28
- <link rel="modulepreload" crossorigin href="/assets/vendor-charts-CAZdaPlq.js">
29
- <link rel="modulepreload" crossorigin href="/assets/chunk-OE4NN4TA-CEjpfhS6.js">
30
- <link rel="modulepreload" crossorigin href="/assets/vendor-ui-ByahnaY0.js">
31
- <link rel="modulepreload" crossorigin href="/assets/api-4AqKvsm9.js">
32
- <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-Bwxw859K.js">
33
- <link rel="modulepreload" crossorigin href="/assets/query-keys-BvtE7BMs.js">
34
- <link rel="modulepreload" crossorigin href="/assets/input-BWEQFptx.js">
35
- <link rel="modulepreload" crossorigin href="/assets/proxy-CsnYqnPp.js">
36
- <link rel="modulepreload" crossorigin href="/assets/activity-DsWeRq4h.js">
37
- <link rel="modulepreload" crossorigin href="/assets/arrow-right-Ea_UhTNi.js">
38
- <link rel="modulepreload" crossorigin href="/assets/select-CeO4vP0G.js">
39
- <link rel="modulepreload" crossorigin href="/assets/platform-targets-R3T-4eJ7.js">
40
- <link rel="modulepreload" crossorigin href="/assets/dist-BhbDML0a.js">
41
- <link rel="modulepreload" crossorigin href="/assets/tooltip-HGLF366Q.js">
42
- <link rel="modulepreload" crossorigin href="/assets/copy-button-WkbNkMcd.js">
43
- <link rel="modulepreload" crossorigin href="/assets/checkbox-DZlJXTE4.js">
44
- <link rel="modulepreload" crossorigin href="/assets/radio-CoHegOv5.js">
45
- <link rel="modulepreload" crossorigin href="/assets/triangle-alert-adNk_sea.js">
46
- <link rel="modulepreload" crossorigin href="/assets/format-kXTonpDJ.js">
47
- <link rel="modulepreload" crossorigin href="/assets/label-uephX5ZG.js">
48
- <link rel="modulepreload" crossorigin href="/assets/use-platform-stream-DGbK1k2L.js">
49
- <link rel="modulepreload" crossorigin href="/assets/catalog-template-icons-BrUeHaCY.js">
50
- <link rel="modulepreload" crossorigin href="/assets/layers-CUsLQ1fq.js">
51
- <link rel="modulepreload" crossorigin href="/assets/server-D9Kfn8fQ.js">
52
- <link rel="modulepreload" crossorigin href="/assets/dist-Cy8XTNFT.js">
53
- <link rel="modulepreload" crossorigin href="/assets/platforms-BWh0BQ3Y.js">
54
- <link rel="modulepreload" crossorigin href="/assets/vendor-table-wd8JuMmT.js">
55
- <link rel="modulepreload" crossorigin href="/assets/arrow-up-down-DFSjzzl2.js">
56
- <link rel="modulepreload" crossorigin href="/assets/download-DQ6NH16U.js">
57
- <link rel="modulepreload" crossorigin href="/assets/engine-store-CrLnz692.js">
58
- <link rel="modulepreload" crossorigin href="/assets/get-error-message-3Q5Q-2G5.js">
59
- <link rel="modulepreload" crossorigin href="/assets/card-BjeP32PN.js">
60
- <link rel="modulepreload" crossorigin href="/assets/combobox-BGnuCYxO.js">
61
- <link rel="modulepreload" crossorigin href="/assets/tags-CiXOIHtY.js">
62
- <link rel="modulepreload" crossorigin href="/assets/box-C1WaoOMF.js">
63
- <link rel="modulepreload" crossorigin href="/assets/blueprint-card-classes-DBFCDy0M.js">
64
- <link rel="modulepreload" crossorigin href="/assets/shallow-6lGjQhtJ.js">
65
- <link rel="modulepreload" crossorigin href="/assets/use-transition-navigate-CCpcWXB0.js">
66
- <link rel="modulepreload" crossorigin href="/assets/transition-nav-link-Df4Rk6vV.js">
67
- <link rel="modulepreload" crossorigin href="/assets/validation-Blvud9_O.js">
68
- <link rel="modulepreload" crossorigin href="/assets/control-CPhvwx9o.js">
69
- <link rel="modulepreload" crossorigin href="/assets/deploy-tab-JeWDwPoZ.js">
70
- <link rel="modulepreload" crossorigin href="/assets/models-B_UioWQ5.js">
71
- <link rel="modulepreload" crossorigin href="/assets/catalog-BJzyzbLR.js">
72
- <link rel="modulepreload" crossorigin href="/assets/gauge-Ci8zNZlk.js">
73
- <link rel="modulepreload" crossorigin href="/assets/select-display-items-CIzY8953.js">
74
- <link rel="modulepreload" crossorigin href="/assets/transition-types-CPlGtM8w.js">
75
- <link rel="modulepreload" crossorigin href="/assets/fleet-CfxbKXt9.js">
76
- <link rel="modulepreload" crossorigin href="/assets/events-D01IxhnP.js">
77
- <link rel="stylesheet" crossorigin href="/assets/index-DJkgDeun.css">
78
- </head>
79
- <body>
80
- <div id="root"></div>
81
- </body>
82
- </html>
Binary file
@@ -1,262 +0,0 @@
1
- import {
2
- createControlPlane,
3
- createEngine,
4
- loadTemplate,
5
- loadTwinModel,
6
- resolveModelPath,
7
- } from "@miravo/core";
8
- import { MQTTAdapter } from "@miravo/mqtt";
9
- import { OPCUAAdapter } from "@miravo/opcua";
10
- import type { MiravoTemplate, TwinModel } from "@miravo/shared";
11
- import { startAdminServer } from "../../lib/admin-server.ts";
12
- import { createSessionStore } from "../../lib/session-store.ts";
13
- import { buildUNSBasePath, forEachTwin } from "../../lib/template-utils.ts";
14
-
15
- interface RunnerArgs {
16
- readonly template: string;
17
- readonly modelsDir: string;
18
- readonly readyFile: string;
19
- readonly rbeEnabled: boolean;
20
- readonly rbeDeadband: number;
21
- }
22
-
23
- interface ReadyHealthPayload {
24
- readonly status?: unknown;
25
- }
26
-
27
- function parseArgs(argv: readonly string[]): RunnerArgs {
28
- const values = new Map<string, string>();
29
- for (let index = 0; index < argv.length; index += 2) {
30
- const key = argv[index];
31
- const value = argv[index + 1];
32
- if (!key?.startsWith("--") || value === undefined) {
33
- throw new Error(
34
- "Invalid smoke runner arguments. Expected --template <path> --models-dir <path> --ready-file <path>.",
35
- );
36
- }
37
- values.set(key.slice(2), value);
38
- }
39
-
40
- const template = values.get("template");
41
- const modelsDir = values.get("models-dir");
42
- const readyFile = values.get("ready-file");
43
- if (!template || !modelsDir || !readyFile) {
44
- throw new Error(
45
- "Missing smoke runner arguments. Provide --template, --models-dir, and --ready-file.",
46
- );
47
- }
48
-
49
- const rbeEnabled = values.get("rbe-enabled") === "true";
50
- const rbeDeadband = Number.parseFloat(values.get("rbe-deadband") ?? "0");
51
-
52
- return { template, modelsDir, readyFile, rbeEnabled, rbeDeadband };
53
- }
54
-
55
- function resolveSimulationName(template: MiravoTemplate): string {
56
- const namespace = template.namespace;
57
- if (!namespace) {
58
- throw new Error("Smoke template is missing namespace metadata.");
59
- }
60
- if ("enterprise" in namespace) {
61
- return `${namespace.enterprise}-${namespace.site}`.toLowerCase();
62
- }
63
- return namespace.prefix.toLowerCase();
64
- }
65
-
66
- async function loadModels(
67
- template: MiravoTemplate,
68
- modelsDir: string,
69
- ): Promise<Map<string, TwinModel>> {
70
- const models = new Map<string, TwinModel>();
71
- if (template.models) {
72
- for (const inlineModel of template.models) {
73
- models.set(inlineModel.model.name, inlineModel);
74
- }
75
- }
76
-
77
- const referencedModelNames = new Set<string>();
78
- forEachTwin(template, (_area, _line, twin) => {
79
- referencedModelNames.add(twin.model);
80
- });
81
-
82
- for (const modelName of referencedModelNames) {
83
- if (models.has(modelName)) {
84
- continue;
85
- }
86
- const modelPath = await resolveModelPath(modelName, [modelsDir]);
87
- const model = await loadTwinModel(modelPath);
88
- models.set(modelName, model);
89
- }
90
-
91
- return models;
92
- }
93
-
94
- async function waitForAdminReady(adminUrl: string, timeoutMs: number): Promise<void> {
95
- const deadline = Date.now() + timeoutMs;
96
- while (Date.now() < deadline) {
97
- try {
98
- const response = await fetch(new URL("/readyz", `${adminUrl}/`));
99
- if (response.status === 200) {
100
- const payload = (await response.json()) as ReadyHealthPayload;
101
- if (payload.status === "ok") {
102
- return;
103
- }
104
- }
105
- } catch {
106
- // Admin server can still be binding or the engine may not be running yet.
107
- }
108
- await Bun.sleep(25);
109
- }
110
-
111
- throw new Error(`Smoke runtime did not report ready within ${timeoutMs}ms.`);
112
- }
113
-
114
- async function main(): Promise<void> {
115
- const args = parseArgs(process.argv.slice(2));
116
- const template = await loadTemplate(args.template);
117
- const models = await loadModels(template, args.modelsDir);
118
- const simulationName = resolveSimulationName(template);
119
- const tickIntervalMs = template.settings?.tick_interval_ms ?? 100;
120
- const timeMultiplier = template.settings?.time_multiplier ?? 1;
121
- const seed = template.settings?.seed ?? 42;
122
-
123
- const engine = createEngine({
124
- simulationName,
125
- seed,
126
- tickIntervalMs,
127
- timeMultiplier,
128
- templateMetadata: {
129
- name: template.name,
130
- path: args.template,
131
- },
132
- });
133
-
134
- for (const [, model] of models) {
135
- engine.runtime.registerModel(model);
136
- }
137
-
138
- forEachTwin(template, (area, line, twin) => {
139
- engine.runtime.spawn(twin.model, twin.count, {
140
- variation: twin.variation,
141
- unsBasePath: buildUNSBasePath(template, area.name, line.name),
142
- ...(twin.parameters !== undefined ? { parameterOverrides: twin.parameters } : {}),
143
- ...(twin.starting_hours !== undefined ? { startingHours: twin.starting_hours } : {}),
144
- });
145
- });
146
-
147
- const mqttAdapter = new MQTTAdapter(engine.bus);
148
- await mqttAdapter.start({
149
- name: "mqtt",
150
- enabled: true,
151
- embedded: true,
152
- host: "127.0.0.1",
153
- port: 0,
154
- retain: false,
155
- simulationName,
156
- ...(args.rbeEnabled ? { rbe: { enabled: true, deadband: args.rbeDeadband } } : {}),
157
- });
158
- engine.registerAdapter(mqttAdapter);
159
-
160
- const opcuaAdapter = new OPCUAAdapter(engine.bus, engine);
161
- await opcuaAdapter.start({
162
- name: "opcua",
163
- enabled: true,
164
- host: "127.0.0.1",
165
- port: 0,
166
- security: "none",
167
- simulationName,
168
- });
169
- engine.registerAdapter(opcuaAdapter);
170
-
171
- const transport = mqttAdapter.getControlTransport();
172
- if (!transport) {
173
- throw new Error("Smoke runtime failed to resolve MQTT control transport.");
174
- }
175
-
176
- const controlPlane = createControlPlane({
177
- simulationName,
178
- engine,
179
- transport,
180
- bus: engine.bus,
181
- });
182
- controlPlane.start();
183
-
184
- let lastTickProgressAt = performance.now();
185
- const onTickProgress = () => {
186
- lastTickProgressAt = performance.now();
187
- };
188
- engine.bus.on("tick:complete", onTickProgress);
189
-
190
- const adminServer = startAdminServer({
191
- engine,
192
- network: { host: "127.0.0.1", port: 0, tickIntervalMs },
193
- protocols: {
194
- getLastTickProgressAt: () => lastTickProgressAt,
195
- },
196
- ws: {
197
- bus: engine.bus,
198
- },
199
- auth: {
200
- verifyPassword: async () => true,
201
- isDefaultPassword: false,
202
- sessionStore: createSessionStore(),
203
- changePassword: async () => {},
204
- },
205
- });
206
-
207
- await engine.start();
208
- await waitForAdminReady(adminServer.endpoint, Math.max(5_000, tickIntervalMs * 20));
209
-
210
- const [instanceId, instance] = [...engine.runtime.getInstances()][0] ?? [];
211
- if (!instanceId || !instance) {
212
- throw new Error("Smoke runtime did not spawn any instances from the template.");
213
- }
214
- if (!mqttAdapter.brokerUrl) {
215
- throw new Error("Smoke runtime did not expose an MQTT broker URL.");
216
- }
217
- if (!opcuaAdapter.endpointUrl) {
218
- throw new Error("Smoke runtime did not expose an OPC UA endpoint URL.");
219
- }
220
- if (opcuaAdapter.port <= 0) {
221
- throw new Error("Smoke runtime did not expose an OPC UA port.");
222
- }
223
-
224
- await Bun.write(
225
- args.readyFile,
226
- JSON.stringify({
227
- simulationName,
228
- adminUrl: adminServer.endpoint,
229
- mqttBrokerUrl: mqttAdapter.brokerUrl,
230
- opcuaEndpointUrl: opcuaAdapter.endpointUrl,
231
- instanceId,
232
- instancePath: instance.browsePath.join("/"),
233
- }),
234
- );
235
-
236
- let shuttingDown = false;
237
- const shutdown = async () => {
238
- if (shuttingDown) {
239
- return;
240
- }
241
- shuttingDown = true;
242
- adminServer.stop();
243
- engine.bus.off("tick:complete", onTickProgress);
244
- controlPlane.stop();
245
- await engine.stop("smoke runner shutdown");
246
- process.exit(0);
247
- };
248
-
249
- process.once("SIGINT", () => {
250
- void shutdown();
251
- });
252
- process.once("SIGTERM", () => {
253
- void shutdown();
254
- });
255
-
256
- await new Promise(() => {});
257
- }
258
-
259
- void main().catch((error) => {
260
- console.error(error instanceof Error ? (error.stack ?? error.message) : String(error));
261
- process.exit(1);
262
- });