@openmbee/opensysml 0.9.2 → 0.10.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.
Files changed (67) hide show
  1. package/README.md +355 -33
  2. package/dist/browser/index.d.ts +9 -0
  3. package/dist/browser/index.js +16 -0
  4. package/dist/browser/wasm-worker.d.ts +1 -0
  5. package/dist/browser/wasm-worker.js +2 -0
  6. package/dist/browser/wasm.d.ts +17 -0
  7. package/dist/browser/wasm.js +94 -0
  8. package/dist/core/arguments.d.ts +4 -0
  9. package/dist/core/arguments.js +19 -0
  10. package/dist/core/capabilities.d.ts +90 -9
  11. package/dist/core/capabilities.js +111 -10
  12. package/dist/core/connection.d.ts +203 -2
  13. package/dist/core/connection.js +810 -17
  14. package/dist/core/conversion.d.ts +153 -0
  15. package/dist/core/conversion.js +191 -0
  16. package/dist/core/document.d.ts +188 -0
  17. package/dist/core/document.js +457 -0
  18. package/dist/core/edit.d.ts +446 -0
  19. package/dist/core/edit.js +1994 -0
  20. package/dist/core/engines.d.ts +64 -0
  21. package/dist/core/engines.js +74 -0
  22. package/dist/core/errors.d.ts +164 -2
  23. package/dist/core/errors.js +209 -3
  24. package/dist/core/exploration.d.ts +71 -0
  25. package/dist/core/exploration.js +116 -0
  26. package/dist/core/graphs.d.ts +15 -0
  27. package/dist/core/graphs.js +3 -0
  28. package/dist/core/index.d.ts +30 -9
  29. package/dist/core/index.js +14 -5
  30. package/dist/core/model.d.ts +168 -8
  31. package/dist/core/model.js +258 -31
  32. package/dist/core/package.d.ts +2 -0
  33. package/dist/core/package.js +2 -0
  34. package/dist/core/query.d.ts +50 -0
  35. package/dist/core/query.js +197 -0
  36. package/dist/core/render-view.d.ts +97 -0
  37. package/dist/core/render-view.js +120 -0
  38. package/dist/core/sources.d.ts +34 -0
  39. package/dist/core/sources.js +134 -0
  40. package/dist/core/status.d.ts +9 -2
  41. package/dist/core/status.js +24 -8
  42. package/dist/core/typed.d.ts +71 -0
  43. package/dist/core/typed.js +245 -0
  44. package/dist/core/values.d.ts +127 -8
  45. package/dist/core/values.js +536 -30
  46. package/dist/core/verdict.d.ts +271 -0
  47. package/dist/core/verdict.js +567 -0
  48. package/dist/core/wasm.d.ts +114 -0
  49. package/dist/core/wasm.js +514 -0
  50. package/dist/generated/sysml_pb.d.ts +1062 -15
  51. package/dist/generated/sysml_pb.js +200 -100
  52. package/dist/node/generate-cli.d.ts +2 -0
  53. package/dist/node/generate-cli.js +10 -0
  54. package/dist/node/generate.d.ts +99 -0
  55. package/dist/node/generate.js +757 -0
  56. package/dist/node/index.d.ts +29 -2
  57. package/dist/node/index.js +211 -10
  58. package/dist/node/service.d.ts +5 -3
  59. package/dist/node/service.js +32 -26
  60. package/dist/node/wasm-source.d.ts +18 -0
  61. package/dist/node/wasm-source.js +103 -0
  62. package/dist/node/wasm-worker.d.ts +1 -0
  63. package/dist/node/wasm-worker.js +10 -0
  64. package/dist/node/wasm.d.ts +17 -0
  65. package/dist/node/wasm.js +63 -0
  66. package/package.json +19 -7
  67. package/release-digests.json +105 -0
@@ -0,0 +1,514 @@
1
+ import { fromJson, toJson, } from "@bufbuild/protobuf";
2
+ import { Code, ConnectError, createContextValues, } from "@connectrpc/connect";
3
+ import { getAbortSignalReason, runUnaryCall } from "@connectrpc/connect/protocol";
4
+ import { Connection } from "./connection.js";
5
+ import { ClosedConnectionError, OpenSysMLError } from "./errors.js";
6
+ import { encodingOf, interceptors, timeoutOf } from "./transport.js";
7
+ const goConstructors = new Map();
8
+ let goConstructorLoads = Promise.resolve();
9
+ let inlineStartup = Promise.resolve();
10
+ /**
11
+ * Adapts the Go host global to the asynchronous host interface.
12
+ */
13
+ export function wasmHostFromGlobal(surface) {
14
+ const global = globalThis;
15
+ const hostSurface = surface ?? global.sysmlWasm;
16
+ if (hostSurface === undefined ||
17
+ typeof hostSurface.version !== "string" ||
18
+ typeof hostSurface.call !== "function") {
19
+ throw new OpenSysMLError("the Go runtime did not expose globalThis.sysmlWasm");
20
+ }
21
+ let closed = false;
22
+ return {
23
+ version: hostSurface.version,
24
+ call(method, params) {
25
+ if (closed) {
26
+ return Promise.reject(new ClosedConnectionError());
27
+ }
28
+ try {
29
+ return Promise.resolve(hostSurface.call(method, params));
30
+ }
31
+ catch (cause) {
32
+ return Promise.resolve(errorEnvelope(cause));
33
+ }
34
+ },
35
+ close() {
36
+ closed = true;
37
+ return Promise.resolve();
38
+ },
39
+ };
40
+ }
41
+ /**
42
+ * Starts a Go WebAssembly module in this realm and captures its host global.
43
+ */
44
+ export async function instantiateInline(module, Go) {
45
+ const starting = inlineStartup.then(() => instantiateInlineNow(module, Go));
46
+ inlineStartup = starting.then(() => undefined, () => undefined);
47
+ return await starting;
48
+ }
49
+ async function instantiateInlineNow(module, Go) {
50
+ const runtime = globalThis;
51
+ delete runtime.sysmlWasm;
52
+ const go = new Go();
53
+ const instance = module instanceof WebAssembly.Module
54
+ ? await WebAssembly.instantiate(module, go.importObject)
55
+ : (await WebAssembly.instantiate(module, go.importObject)).instance;
56
+ let startError;
57
+ void go.run(instance).catch((error) => {
58
+ startError = error;
59
+ });
60
+ await new Promise((resolve) => setTimeout(resolve, 0));
61
+ const surface = globalWasmSurface();
62
+ delete runtime.sysmlWasm;
63
+ if (surface === undefined) {
64
+ throw new OpenSysMLError("the Go runtime did not expose globalThis.sysmlWasm", startError === undefined ? undefined : { cause: startError });
65
+ }
66
+ return wasmHostFromGlobal(surface);
67
+ }
68
+ /**
69
+ * Creates a Connect transport for the JSON envelope served by sysml-wasm.
70
+ */
71
+ export function createWasmTransport(host, options) {
72
+ const callUnary = (method, signal, timeoutMs, header, input, contextValues) => runUnaryCall({
73
+ req: {
74
+ stream: false,
75
+ service: method.parent,
76
+ method,
77
+ requestMethod: "POST",
78
+ url: `wasm://sysml-wasm/${method.parent.typeName}/${method.name}`,
79
+ header: new Headers(header),
80
+ contextValues: contextValues ?? createContextValues(),
81
+ message: input,
82
+ },
83
+ ...(signal === undefined ? {} : { signal }),
84
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
85
+ interceptors: interceptors(options),
86
+ next: async (request) => {
87
+ if (request.signal.aborted) {
88
+ throw abortError(request.signal);
89
+ }
90
+ const params = JSON.stringify(toJson(method.input, request.message));
91
+ const answer = host.call(method.name, params, request.signal);
92
+ const envelope = await withAbort(answer, request.signal);
93
+ const body = readEnvelope(envelope);
94
+ return {
95
+ stream: false,
96
+ service: method.parent,
97
+ method,
98
+ header: new Headers(),
99
+ message: fromJson(method.output, body, {
100
+ ignoreUnknownFields: true,
101
+ }),
102
+ trailer: new Headers(),
103
+ };
104
+ },
105
+ });
106
+ return {
107
+ unary: callUnary,
108
+ stream() {
109
+ return Promise.reject(new ConnectError("streaming methods are not supported by sysml-wasm", Code.Unimplemented));
110
+ },
111
+ };
112
+ }
113
+ /**
114
+ * Opens a Connection over a WASM host, negotiating its version and capabilities.
115
+ */
116
+ export async function connectWasmHost(host, options = {}) {
117
+ let timeoutMs;
118
+ try {
119
+ if (options.encoding !== undefined && encodingOf(options) !== "json") {
120
+ throw new OpenSysMLError("sysml-wasm supports JSON encoding only");
121
+ }
122
+ timeoutMs = timeoutOf(options);
123
+ }
124
+ catch (error) {
125
+ await host.close().catch(() => undefined);
126
+ throw error;
127
+ }
128
+ const required = options.version === undefined || options.version === "" || options.version === "latest"
129
+ ? undefined
130
+ : options.version;
131
+ const origin = `sysml-wasm ${host.version}`;
132
+ return Connection.open({
133
+ transport: createWasmTransport(host, options),
134
+ backend: {
135
+ origin,
136
+ release: () => host.close(),
137
+ warn: (message) => {
138
+ console.warn(message);
139
+ },
140
+ },
141
+ encoding: "json",
142
+ timeoutMs,
143
+ ...(required === undefined ? {} : { requiredVersion: required }),
144
+ ...(options.requireCapabilities === undefined
145
+ ? {}
146
+ : { requiredCapabilities: options.requireCapabilities }),
147
+ stale: {
148
+ address: origin,
149
+ remedy: required === undefined
150
+ ? "use a module reporting the expected version, or omit version"
151
+ : `use a module reporting ${required}, or omit version`,
152
+ },
153
+ });
154
+ }
155
+ /** Adapts a platform worker endpoint to the shared WASM host protocol. */
156
+ export class WorkerWasmHost {
157
+ endpoint;
158
+ version = "";
159
+ pending = new Map();
160
+ ready;
161
+ resolveReady;
162
+ rejectReady;
163
+ nextId = 1;
164
+ failure;
165
+ closed = false;
166
+ constructor(endpoint) {
167
+ this.endpoint = endpoint;
168
+ this.ready = new Promise((resolve, reject) => {
169
+ this.resolveReady = resolve;
170
+ this.rejectReady = reject;
171
+ });
172
+ endpoint.onMessage((message) => {
173
+ this.receive(message);
174
+ });
175
+ endpoint.onFailure((reason) => {
176
+ this.fail(reason);
177
+ });
178
+ }
179
+ async start(request, transfer) {
180
+ this.endpoint.post(request, transfer);
181
+ await this.ready;
182
+ return this;
183
+ }
184
+ async call(method, params, signal) {
185
+ if (signal?.aborted) {
186
+ throw abortError(signal);
187
+ }
188
+ this.throwIfFailed();
189
+ if (this.closed) {
190
+ throw new ConnectError("the sysml-wasm worker is closed", Code.Unavailable);
191
+ }
192
+ if (signal === undefined) {
193
+ await this.ready;
194
+ }
195
+ else {
196
+ await withAbort(this.ready, signal);
197
+ }
198
+ if (signal?.aborted) {
199
+ throw abortError(signal);
200
+ }
201
+ this.throwIfFailed();
202
+ this.throwIfClosed();
203
+ const id = this.nextId++;
204
+ return new Promise((resolve, reject) => {
205
+ if (signal === undefined) {
206
+ this.pending.set(id, { resolve, reject });
207
+ }
208
+ else {
209
+ const onAbort = () => {
210
+ this.removePending(id)?.reject(abortError(signal));
211
+ };
212
+ this.pending.set(id, { resolve, reject, signal, onAbort });
213
+ signal.addEventListener("abort", onAbort, { once: true });
214
+ if (signal.aborted) {
215
+ onAbort();
216
+ return;
217
+ }
218
+ }
219
+ try {
220
+ this.endpoint.post({ type: "call", id, method, params }, []);
221
+ }
222
+ catch (error) {
223
+ this.removePending(id)?.reject(ConnectError.from(error, Code.Unavailable));
224
+ }
225
+ });
226
+ }
227
+ async close() {
228
+ if (this.closed) {
229
+ return;
230
+ }
231
+ this.closed = true;
232
+ try {
233
+ this.endpoint.post({ type: "close" }, []);
234
+ }
235
+ catch {
236
+ // A worker that has already failed has no message loop to close.
237
+ }
238
+ const closed = new ConnectError("the sysml-wasm worker was closed", Code.Unavailable);
239
+ for (const id of this.pending.keys()) {
240
+ this.removePending(id)?.reject(closed);
241
+ }
242
+ await this.endpoint.terminate();
243
+ }
244
+ receive(message) {
245
+ if (message.type === "ready") {
246
+ this.version = message.version;
247
+ this.resolveReady();
248
+ return;
249
+ }
250
+ if (message.type === "failed") {
251
+ this.fail(new Error(message.message));
252
+ return;
253
+ }
254
+ const pending = this.removePending(message.id);
255
+ if (pending !== undefined) {
256
+ pending.resolve(message.envelope);
257
+ }
258
+ }
259
+ fail(reason) {
260
+ if (this.failure !== undefined || this.closed) {
261
+ return;
262
+ }
263
+ this.failure = ConnectError.from(reason, Code.Unavailable);
264
+ this.rejectReady(this.failure);
265
+ for (const id of this.pending.keys()) {
266
+ this.removePending(id)?.reject(this.failure);
267
+ }
268
+ }
269
+ removePending(id) {
270
+ const pending = this.pending.get(id);
271
+ if (pending !== undefined) {
272
+ this.pending.delete(id);
273
+ if (pending.signal !== undefined && pending.onAbort !== undefined) {
274
+ pending.signal.removeEventListener("abort", pending.onAbort);
275
+ }
276
+ }
277
+ return pending;
278
+ }
279
+ throwIfFailed() {
280
+ const failure = this.failure;
281
+ if (failure !== undefined) {
282
+ throw failure;
283
+ }
284
+ }
285
+ throwIfClosed() {
286
+ if (this.closed) {
287
+ throw new ConnectError("the sysml-wasm worker is closed", Code.Unavailable);
288
+ }
289
+ }
290
+ }
291
+ /**
292
+ * Serves the shared init/call protocol on a Node or browser worker port.
293
+ */
294
+ export function serveWasmPort(port, loaders = {}) {
295
+ let host;
296
+ let initializing = false;
297
+ let closed = false;
298
+ let calls = Promise.resolve();
299
+ const onMessage = (event) => {
300
+ const request = event.data;
301
+ if (request.type === "init") {
302
+ if (initializing || host !== undefined || closed) {
303
+ port.postMessage({ type: "failed", message: "the WASM worker is already initialized" });
304
+ return;
305
+ }
306
+ initializing = true;
307
+ void initialize(request.wasm, request.wasmExec);
308
+ return;
309
+ }
310
+ if (request.type === "close") {
311
+ closed = true;
312
+ void host?.close();
313
+ return;
314
+ }
315
+ calls = calls.then(async () => {
316
+ if (closed || host === undefined) {
317
+ port.postMessage({
318
+ type: "answer",
319
+ id: request.id,
320
+ envelope: errorEnvelope(new ConnectError("the WASM worker is unavailable", Code.Unavailable)),
321
+ });
322
+ return;
323
+ }
324
+ try {
325
+ port.postMessage({
326
+ type: "answer",
327
+ id: request.id,
328
+ envelope: await host.call(request.method, request.params),
329
+ });
330
+ }
331
+ catch (cause) {
332
+ port.postMessage({ type: "answer", id: request.id, envelope: errorEnvelope(cause) });
333
+ }
334
+ });
335
+ };
336
+ const initialize = async (source, wasmExec) => {
337
+ try {
338
+ const module = loaders.loadWasm
339
+ ? await loaders.loadWasm(source)
340
+ : await loadWasmSource(source);
341
+ const Go = loaders.loadGo
342
+ ? await loaders.loadGo(wasmExec)
343
+ : await loadGoConstructor(wasmExec);
344
+ host = await instantiateInline(module, Go);
345
+ port.postMessage({ type: "ready", version: host.version });
346
+ }
347
+ catch (cause) {
348
+ port.postMessage({ type: "failed", message: errorMessage(cause) });
349
+ }
350
+ };
351
+ port.addEventListener("message", onMessage);
352
+ port.start?.();
353
+ }
354
+ /** Loads and caches the Go constructor installed by wasm_exec.js. */
355
+ export function loadGoConstructor(wasmExec) {
356
+ if (wasmExec === undefined) {
357
+ return goConstructorLoads.then(() => {
358
+ const Go = globalGoConstructor();
359
+ if (Go === undefined) {
360
+ throw new OpenSysMLError("Go is unavailable; supply the matching wasm_exec.js");
361
+ }
362
+ return Go;
363
+ });
364
+ }
365
+ const cached = goConstructors.get(wasmExec);
366
+ if (cached !== undefined) {
367
+ return cached;
368
+ }
369
+ const loading = goConstructorLoads.then(() => loadGoConstructorFromScript(wasmExec));
370
+ goConstructors.set(wasmExec, loading);
371
+ goConstructorLoads = loading.then(() => undefined, () => undefined);
372
+ void loading.catch(() => {
373
+ if (goConstructors.get(wasmExec) === loading) {
374
+ goConstructors.delete(wasmExec);
375
+ }
376
+ });
377
+ return loading;
378
+ }
379
+ async function loadGoConstructorFromScript(wasmExec) {
380
+ const runtime = globalThis;
381
+ const previous = runtime.Go;
382
+ let loaded;
383
+ try {
384
+ try {
385
+ await import(wasmExec);
386
+ }
387
+ catch (cause) {
388
+ const importScripts = globalThis.importScripts;
389
+ if (importScripts === undefined) {
390
+ throw new OpenSysMLError(`could not load wasm_exec.js from ${wasmExec}`, { cause });
391
+ }
392
+ importScripts(wasmExec);
393
+ }
394
+ // Accept only a fresh constructor installed by this evaluation.
395
+ const current = runtime.Go;
396
+ if (current === undefined) {
397
+ if (previous !== undefined) {
398
+ throw new OpenSysMLError(`wasm_exec.js at ${wasmExec} did not install Go here; it may already have run in this realm. Omit wasmExec to use the installed Go, or load the runtime in a worker`);
399
+ }
400
+ throw new OpenSysMLError("Go is unavailable; supply the matching wasm_exec.js");
401
+ }
402
+ if (current === previous) {
403
+ throw new OpenSysMLError(`wasm_exec.js at ${wasmExec} did not install Go here; it may already have run in this realm. Omit wasmExec to use the installed Go, or load the runtime in a worker`);
404
+ }
405
+ loaded = current;
406
+ return current;
407
+ }
408
+ finally {
409
+ if (previous !== undefined) {
410
+ runtime.Go = previous;
411
+ }
412
+ else if (loaded === undefined) {
413
+ delete runtime.Go;
414
+ }
415
+ }
416
+ }
417
+ function globalGoConstructor() {
418
+ return globalThis.Go;
419
+ }
420
+ function readEnvelope(envelope) {
421
+ let parsed;
422
+ try {
423
+ parsed = JSON.parse(envelope);
424
+ }
425
+ catch (cause) {
426
+ throw ConnectError.from(cause, Code.Internal);
427
+ }
428
+ if (parsed === null || typeof parsed !== "object") {
429
+ throw new ConnectError("sysml-wasm returned an invalid JSON envelope", Code.Internal);
430
+ }
431
+ const response = parsed;
432
+ if (response.error !== undefined && response.error !== null) {
433
+ const status = typeof response.error.code === "number" &&
434
+ Object.values(Code).includes(response.error.code)
435
+ ? response.error.code
436
+ : Code.Unknown;
437
+ throw new ConnectError(typeof response.error.message === "string"
438
+ ? response.error.message
439
+ : "sysml-wasm returned an error", status);
440
+ }
441
+ if (!Object.hasOwn(response, "result")) {
442
+ throw new ConnectError("sysml-wasm returned an envelope without a result", Code.Internal);
443
+ }
444
+ return response.result;
445
+ }
446
+ function withAbort(answer, signal) {
447
+ if (signal.aborted) {
448
+ return Promise.reject(abortError(signal));
449
+ }
450
+ return new Promise((resolve, reject) => {
451
+ let settled = false;
452
+ const cleanup = () => {
453
+ signal.removeEventListener("abort", onAbort);
454
+ };
455
+ const finish = (callback, value) => {
456
+ if (!settled) {
457
+ settled = true;
458
+ cleanup();
459
+ callback(value);
460
+ }
461
+ };
462
+ const fail = (error) => {
463
+ if (!settled) {
464
+ settled = true;
465
+ cleanup();
466
+ reject(ConnectError.from(error, Code.Internal));
467
+ }
468
+ };
469
+ const onAbort = () => {
470
+ fail(abortError(signal));
471
+ };
472
+ signal.addEventListener("abort", onAbort, { once: true });
473
+ answer.then((value) => {
474
+ finish(resolve, value);
475
+ }, fail);
476
+ });
477
+ }
478
+ function abortError(signal) {
479
+ return ConnectError.from(getAbortSignalReason(signal), Code.Canceled);
480
+ }
481
+ function errorEnvelope(error) {
482
+ const connectError = ConnectError.from(error, Code.Internal);
483
+ return JSON.stringify({
484
+ jsonrpc: "2.0",
485
+ id: null,
486
+ error: { code: connectError.code, message: connectError.rawMessage },
487
+ });
488
+ }
489
+ export async function loadWasmSource(source) {
490
+ if (source instanceof WebAssembly.Module ||
491
+ source instanceof ArrayBuffer ||
492
+ ArrayBuffer.isView(source)) {
493
+ return source;
494
+ }
495
+ const response = source instanceof Response ? source : await fetch(source);
496
+ if (!response.ok) {
497
+ throw new OpenSysMLError(`could not fetch the WebAssembly module: ${response.status}`);
498
+ }
499
+ if (typeof WebAssembly.compileStreaming === "function") {
500
+ try {
501
+ return await WebAssembly.compileStreaming(response.clone());
502
+ }
503
+ catch {
504
+ // Some servers omit the application/wasm content type required by streaming.
505
+ }
506
+ }
507
+ return response.arrayBuffer();
508
+ }
509
+ function errorMessage(error) {
510
+ return error instanceof Error ? error.message : String(error);
511
+ }
512
+ function globalWasmSurface() {
513
+ return globalThis.sysmlWasm;
514
+ }