@cognipilot/rumoca-core 0.9.4 → 0.9.6

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.
@@ -1,3 +1,3 @@
1
1
  {
2
- "packageBuiltTimeUtc": "2026-06-14T02:32:57Z"
2
+ "packageBuiltTimeUtc": "2026-06-20T01:17:39Z"
3
3
  }
@@ -0,0 +1,164 @@
1
+ import { diffsolAvailable as diffsolAddonAvailable, simulateWithDiffsol } from './rumoca_diffsol.js';
2
+
3
+ const loadedSourceRootCaches = new WeakMap();
4
+
5
+ function trimMaybeString(value) {
6
+ return typeof value === 'string' ? value.trim() : '';
7
+ }
8
+
9
+ function encodeUrlPath(path) {
10
+ return path.split('/').map(encodeURIComponent).join('/');
11
+ }
12
+
13
+ function normalizeStringArray(values) {
14
+ return Array.isArray(values)
15
+ ? values.map(trimMaybeString).filter(Boolean)
16
+ : [];
17
+ }
18
+
19
+ function sourceRootMatchesEntry(entry, sourceRoot) {
20
+ return Array.isArray(entry?.matches)
21
+ && entry.matches.some((needle) => sourceRoot.includes(needle));
22
+ }
23
+
24
+ export function normalizeSimulationSolver(solver) {
25
+ const normalized = trimMaybeString(solver).toLowerCase();
26
+ return normalized === 'bdf' || normalized === 'rk-like' ? normalized : 'auto';
27
+ }
28
+
29
+ export function createSourceRootCacheResolver({ manifestUrl, fetchImpl = fetch }) {
30
+ let manifestPromise = null;
31
+
32
+ async function loadManifest() {
33
+ if (!manifestPromise) {
34
+ manifestPromise = (async () => {
35
+ const response = await fetchImpl(manifestUrl);
36
+ if (!response.ok) {
37
+ throw new Error(`Source-root manifest is unavailable (${response.status})`);
38
+ }
39
+ return { url: manifestUrl, payload: await response.json() };
40
+ })().catch((error) => {
41
+ manifestPromise = null;
42
+ throw error;
43
+ });
44
+ }
45
+ return manifestPromise;
46
+ }
47
+
48
+ return {
49
+ async cacheUrlFor(sourceRoots) {
50
+ const roots = normalizeStringArray(sourceRoots);
51
+ if (roots.length === 0) {
52
+ return '';
53
+ }
54
+ const { url, payload } = await loadManifest();
55
+ const entries = Array.isArray(payload?.roots) ? payload.roots : [];
56
+ for (const sourceRoot of roots) {
57
+ if (!entries.some((entry) => sourceRootMatchesEntry(entry, sourceRoot))) {
58
+ throw new Error(`Source root is not staged for this runtime: ${sourceRoot}`);
59
+ }
60
+ }
61
+ const cache = trimMaybeString(payload?.cache);
62
+ if (!cache) {
63
+ throw new Error('Parsed source-root cache is missing from the runtime manifest.');
64
+ }
65
+ return new URL(encodeUrlPath(cache), url).href;
66
+ },
67
+ };
68
+ }
69
+
70
+ export async function fetchGzipBytes(url, fetchImpl = fetch) {
71
+ const response = await fetchImpl(url);
72
+ if (!response.ok) {
73
+ throw new Error(`Parsed source-root cache is unavailable (${response.status})`);
74
+ }
75
+ if (!url.endsWith('.gz')) {
76
+ throw new Error('Parsed source-root cache must be gzip-compressed.');
77
+ }
78
+ if (typeof DecompressionStream !== 'function') {
79
+ throw new Error('This browser cannot decompress the parsed source-root cache.');
80
+ }
81
+ const stream = response.body || new Blob([await response.arrayBuffer()]).stream();
82
+ const decompressed = stream.pipeThrough(new DecompressionStream('gzip'));
83
+ return new Uint8Array(await new Response(decompressed).arrayBuffer());
84
+ }
85
+
86
+ export async function ensureParsedSourceRootCache(wasm, cacheUrl) {
87
+ if (!cacheUrl) {
88
+ return false;
89
+ }
90
+ if (!wasm || typeof wasm.merge_parsed_source_roots_binary !== 'function') {
91
+ throw new Error('merge_parsed_source_roots_binary missing in this WASM build');
92
+ }
93
+ const cached = loadedSourceRootCaches.get(wasm);
94
+ if (cached?.url === cacheUrl) {
95
+ await cached.promise;
96
+ return true;
97
+ }
98
+ const promise = (async () => {
99
+ wasm.merge_parsed_source_roots_binary(await fetchGzipBytes(cacheUrl));
100
+ if (typeof wasm.prime_source_root_completion_cache === 'function') {
101
+ wasm.prime_source_root_completion_cache();
102
+ }
103
+ })();
104
+ loadedSourceRootCaches.set(wasm, { url: cacheUrl, promise });
105
+ try {
106
+ await promise;
107
+ } catch (error) {
108
+ if (loadedSourceRootCaches.get(wasm)?.promise === promise) {
109
+ loadedSourceRootCaches.delete(wasm);
110
+ }
111
+ throw error;
112
+ }
113
+ return true;
114
+ }
115
+
116
+ export async function prepareGpuSimulationWithRuntime({ wasm, source, modelName, sourceRootCacheUrl = '' }) {
117
+ await ensureParsedSourceRootCache(wasm, sourceRootCacheUrl);
118
+ if (typeof wasm.prepare_gpu_simulation !== 'function') {
119
+ throw new Error('prepare_gpu_simulation missing in this WASM build');
120
+ }
121
+ return wasm.prepare_gpu_simulation(source, modelName);
122
+ }
123
+
124
+ export async function simulateModelWithRuntime({
125
+ wasm,
126
+ pkgBase,
127
+ source,
128
+ modelName,
129
+ tEnd = 0,
130
+ dt = 0,
131
+ solver = 'auto',
132
+ sourceRootCacheUrl = '',
133
+ parameterOverrides = {},
134
+ }) {
135
+ await ensureParsedSourceRootCache(wasm, sourceRootCacheUrl);
136
+ const normalizedSolver = normalizeSimulationSolver(solver);
137
+ const parameterOverridesJson = JSON.stringify(parameterOverrides || {});
138
+ if (normalizedSolver === 'bdf') {
139
+ return simulateWithDiffsol(wasm, pkgBase, source, modelName, tEnd, dt, parameterOverridesJson);
140
+ }
141
+ if (typeof wasm.simulate_model !== 'function') {
142
+ throw new Error('simulate_model missing in this WASM build');
143
+ }
144
+ return JSON.parse(wasm.simulate_model(source, modelName, tEnd, dt, normalizedSolver, parameterOverridesJson));
145
+ }
146
+
147
+ export async function renderDaeTextWithRuntime({
148
+ wasm,
149
+ source,
150
+ modelName,
151
+ sourceRootCacheUrl = '',
152
+ }) {
153
+ await ensureParsedSourceRootCache(wasm, sourceRootCacheUrl);
154
+ const compiled = wasm.compile(source, modelName);
155
+ const envelope = JSON.parse(compiled);
156
+ const daeJson = JSON.stringify(envelope.dae_native || envelope.dae);
157
+ const rendered = wasm.render_target(daeJson, modelName, 'dae-modelica', '', '{}');
158
+ const files = Array.isArray(rendered?.files) ? rendered.files : [];
159
+ return files.map((file) => file.content || '').join('\n');
160
+ }
161
+
162
+ export async function diffsolAvailable(pkgBase) {
163
+ return diffsolAddonAvailable(pkgBase);
164
+ }