@remix_labs/machine-starter 1.1890.0-dev → 1.1895.0-dev

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/common.js ADDED
@@ -0,0 +1,292 @@
1
+ import { nanoid } from "nanoid";
2
+ import { GROOVEBOX_BUILD } from "./groovebox_build.js";
3
+
4
+ let terminate = function(f) {};
5
+ if (globalThis.ThisIsNode) {
6
+ terminate = function(f) {
7
+ Process.on("exit", () => {
8
+ console.log("terminating machine worker");
9
+ f()
10
+ })
11
+ }
12
+ };
13
+
14
+ function CreateVMID() {
15
+ return nanoid()
16
+ }
17
+
18
+ let initialMask = 64 + 1024; // default for web
19
+ globalThis.MixSetMask = (m => {
20
+ initialMask = m;
21
+ });
22
+
23
+ function StartWASM(hub, baseURL, org, workspace, vmID, user, token, noOutputViaMQTT) {
24
+ return StartWASM2(hub, {
25
+ baseURL: baseURL,
26
+ org: org,
27
+ workspace: workspace,
28
+ token: token,
29
+ noOutputViaMQTT: noOutputViaMQTT,
30
+ machType: "WASM"
31
+ })
32
+ }
33
+
34
+ function StartWASM2(hub, config) {
35
+ console.log("GROOVEBOX_BUILD (machine-starter)", GROOVEBOX_BUILD);
36
+ return hub.newChannel().then(channel => {
37
+ // injected by either index.js or node.js
38
+ let worker = globalThis.GetMachineWASMWorker();
39
+ let localFFIs = {};
40
+ if (config.localFFIs) {
41
+ for (const [k, v] of Object.entries(config.localFFIs)) {
42
+ if (v.isRaw && (v.canFail || v.useJsonDecoder)) {
43
+ console.error("A raw, local FFI must neither be failing nor use the JSON decoder: " + k);
44
+ } else {
45
+ localFFIs[k] = {...v};
46
+ delete localFFIs[k].run;
47
+ }
48
+ }
49
+ }
50
+ let config_msg =
51
+ { "_rmx_type": "msg_vm_configure",
52
+ "baseURL": config.baseURL,
53
+ "org": config.org,
54
+ "workspace": config.workspace,
55
+ "vmID": config.vmID,
56
+ "user": config.user,
57
+ "token": config.token,
58
+ "hub": channel.port,
59
+ "outputViaMQTT": !(config.noOutputViaMQTT),
60
+ "machType": config.machType,
61
+ "debugMask": initialMask,
62
+ "localFFIs": localFFIs,
63
+ "grooveboxUrlPrefix": globalThis.GROOVEBOX_URL_PREFIX,
64
+ "allowInsecureHttp": globalThis.GROOVEBOX_ALLOW_INSECURE_HTTP,
65
+ "interceptFFI": config.interceptFFI,
66
+ "interceptDynloadFFI": config.interceptDynloadFFI,
67
+ };
68
+ worker.postMessage(config_msg, [ channel.port ]);
69
+ terminate(() => worker.terminate());
70
+ globalThis.MixSetMask = (m => {
71
+ worker.postMessage({ "_rmx_type": "msg_vm_logMask",
72
+ "mask": m
73
+ })
74
+ });
75
+ if (config.localFFIs)
76
+ setupLocalFFIs(hub, config); // don't await!
77
+ return worker;
78
+ })
79
+ }
80
+
81
+ class Token {
82
+ constructor(data, enabled, extras) {
83
+ // data: must be an Uint8Array
84
+ // enabled: a number with the bitset of enabled operations
85
+ // extras: a map
86
+ if (!data instanceof Uint8Array)
87
+ throw new Error("Token: data must be an Uint8Array");
88
+ if (typeof(enabled) != "number")
89
+ throw new Error("Token: enabled_ops must be a number");
90
+ this.data = data;
91
+ this.enabled = enabled;
92
+ this.extras = extras;
93
+ }
94
+ encode() {
95
+ return new Map([
96
+ [ "_rmx_type", "token" ],
97
+ [ "data", this.data ],
98
+ [ "enabled", this.enabled ],
99
+ [ "extras", this.extras ]
100
+ ]);
101
+ }
102
+ }
103
+
104
+ function decode_Token(m) {
105
+ return new Token(m.get("data"), m.get("enabled"), m.get("extras"))
106
+ }
107
+
108
+ class Case {
109
+ constructor(name, arg) {
110
+ if (typeof(name) != "string")
111
+ throw new Error("Case: name must be a string");
112
+ this.name = name;
113
+ this.arg = arg;
114
+ }
115
+ encode() {
116
+ return new Map([
117
+ [ "_rmx_type", "case" ],
118
+ [ "name", this.name ],
119
+ [ "arg", this.arg ],
120
+ ]);
121
+ }
122
+ }
123
+
124
+ function decode_Case(m) {
125
+ return new Case(m.get("name"), m.get("arg"))
126
+ }
127
+
128
+ class Opaque {
129
+ constructor(buf) {
130
+ if (!(buf instanceof Uint32Array))
131
+ throw new Error("Opaque: must be a Uint32Array");
132
+ this.data = buf;
133
+ }
134
+ encode() {
135
+ return new Map([
136
+ [ "_rmx_type", "opaque" ],
137
+ [ "data", this.data ],
138
+ ]);
139
+ }
140
+ }
141
+
142
+ function decode_Opaque(m) {
143
+ return new Opaque(m.get("data"))
144
+ }
145
+
146
+ function encode(val) {
147
+ switch (typeof(val)) {
148
+ case "object":
149
+ if (val === null) return val;
150
+ if (Array.isArray(val)) {
151
+ // array: map the array elements
152
+ val = val.map(encode)
153
+ } else if (Object.getPrototypeOf(val) === Object.prototype) {
154
+ // simple object: map the object elements
155
+ val = Object.fromEntries(Object.entries(val).map(([ key, elem ]) => [ key, encode(elem) ]))
156
+ } else if (val.encode instanceof Function) {
157
+ // map after encode(): map the map elements
158
+ val = new Map(Array.from(val.encode().entries()).map(([ key, elem ]) => [ key, encode(elem) ]))
159
+ };
160
+ return val;
161
+ default:
162
+ return val;
163
+ }
164
+ }
165
+
166
+ function decode(val) {
167
+ switch (typeof(val)) {
168
+ case "object":
169
+ if (val === null) return val;
170
+ if (Array.isArray(val)) {
171
+ // array: map the array elements
172
+ val = val.map(decode)
173
+ } else if (Object.getPrototypeOf(val) === Object.prototype) {
174
+ // simple object: map the object elements
175
+ val = Object.fromEntries(Object.entries(val).map(([ key, elem ]) => [ key, decode(elem) ]))
176
+ } else if (val instanceof Map) {
177
+ val = new Map(Array.from(val.entries()).map(([ key, elem ]) => [ key, decode(elem) ]))
178
+ let ty = val.get("_rmx_type");
179
+ switch (ty) {
180
+ case "token":
181
+ return decode_Token(val);
182
+ case "case":
183
+ return decode_Case(val);
184
+ case "opaque":
185
+ return decode_Opaque(val);
186
+ default:
187
+ throw new Error("decode: bad _rmx_type: " + ty);
188
+ }
189
+ };
190
+ return val;
191
+ default:
192
+ return val;
193
+ }
194
+ }
195
+
196
+ async function setupLocalFFIs(hub, config) {
197
+ let channel = await hub.newChannel();
198
+ let comm = new FFIComm(hub, channel);
199
+ let localFFIs = config.localFFIs;
200
+ await channel.setLocalSubTopic("/local/ffi/call");
201
+ await channel.setLocalPubTopic("/local/ffi/return");
202
+ let sub = await channel.subscribe("/local/ffi/call");
203
+ while (true) {
204
+ let msg = await sub.next();
205
+ let name = msg.payload.name;
206
+ let call_id = msg.payload.call_id;
207
+ let args = decode(msg.payload.args);
208
+ let fun = localFFIs[name];
209
+ try {
210
+ if (!fun)
211
+ throw new Error("no such local FFI: " + name);
212
+ let connector =
213
+ { call_id: call_id,
214
+ hub: hub,
215
+ channel: channel,
216
+ state: config.state,
217
+ };
218
+ let r = fun instanceof Function ? fun(connector, args) : fun.run(connector, args);
219
+ if (r instanceof Promise) {
220
+ await comm.later(call_id);
221
+ r.then(
222
+ (value) => comm.returnOrFail(fun, call_id, value),
223
+ (reason) => comm.error(call_id, reason.message, reason.stack));
224
+ } else {
225
+ await comm.returnOrFail(fun, call_id, r);
226
+ }
227
+ } catch (reason) {
228
+ await comm.error(call_id, reason.message, reason.stack);
229
+ }
230
+ }
231
+ }
232
+
233
+ class FFIComm {
234
+ constructor(hub, channel) {
235
+ this.hub = hub;
236
+ this.channel = channel;
237
+ }
238
+ later(call_id) {
239
+ let r_payload =
240
+ { call_id: call_id,
241
+ };
242
+ let response = this.hub.newLocalMessage("msg_ffi_later", "starter", r_payload);
243
+ return this.channel.publish("/local/ffi/return", response, false);
244
+ }
245
+ return_(fun, call_id, result) {
246
+ let r_payload =
247
+ { call_id: call_id,
248
+ value: fun.useJsonDecoder ? result : encode(result)
249
+ };
250
+ let response = this.hub.newLocalMessage("msg_ffi_return", "starter", r_payload);
251
+ return this.channel.publish("/local/ffi/return", response, false);
252
+ }
253
+ error(call_id, message, stack) {
254
+ let r_payload =
255
+ { call_id: call_id,
256
+ message: message,
257
+ stack: stack === undefined ? [] : stack,
258
+ };
259
+ let response = this.hub.newLocalMessage("msg_ffi_error", "starter", r_payload);
260
+ this.channel.publish("/local/ffi/return", response, false);
261
+ }
262
+ returnOrFail(fun, call_id, result) {
263
+ if (fun.canFail) {
264
+ var name, arg;
265
+ if (result instanceof Case) {
266
+ name = result.name;
267
+ arg = result.arg;
268
+ } else if (fun.useJsonDecoder && result._rmx_type && result._rmx_type.startsWith("{tag}case:")) {
269
+ name = result._rmx_type.substring(10);
270
+ arg = result._rmx_value;
271
+ } else {
272
+ return this.error(call_id, "expected result from local FFI that can fail");
273
+ }
274
+ switch (name) {
275
+ case "ok":
276
+ return this.return_(fun, call_id, arg);
277
+ case "error":
278
+ return this.error(call_id, arg);
279
+ default:
280
+ return this.error(call_id, "expected result from local FFI that can fail, found case value " + name);
281
+ }
282
+ } else {
283
+ return this.return_(fun, call_id, result);
284
+ }
285
+ }
286
+ }
287
+
288
+ // use worker.terminate() to shut a worker down!
289
+
290
+ export { CreateVMID, StartWASM, StartWASM2,
291
+ Token, Case, Opaque
292
+ }
@@ -1,2 +1,2 @@
1
- var GROOVEBOX_BUILD = "1890";
1
+ var GROOVEBOX_BUILD = "1895";
2
2
  export { GROOVEBOX_BUILD }
package/index.js CHANGED
@@ -1,306 +1,15 @@
1
- import { nanoid } from "nanoid";
2
- import { GROOVEBOX_BUILD } from "./groovebox_build.js";
3
-
4
- let terminate = function(f) {};
5
- if (globalThis.ThisIsNode) {
6
- terminate = function(f) {
7
- Process.on("exit", () => {
8
- console.log("terminating machine worker");
9
- f()
10
- })
11
- }
12
- };
13
-
14
- function CreateVMID() {
15
- return nanoid()
1
+ function workerify(code) {
2
+ let blob = new Blob([code], {type: 'application/javascript'});
3
+ return new Worker(URL.createObjectURL(blob));
16
4
  }
17
5
 
18
- let initialMask = 64 + 1024; // default for web
19
- globalThis.MixSetMask = (m => {
20
- initialMask = m;
21
- });
6
+ import MachineWASMWorker from './machine-wasm.worker.js';
22
7
 
23
- function StartWASM(hub, baseURL, org, workspace, vmID, user, token, noOutputViaMQTT) {
24
- return StartWASM2(hub, {
25
- baseURL: baseURL,
26
- org: org,
27
- workspace: workspace,
28
- vmID: vmID,
29
- user: user,
30
- token: token,
31
- noOutputViaMQTT: noOutputViaMQTT,
32
- machType: "WASM"
33
- })
8
+ function GetMachineWASMWorker() {
9
+ return workerify(MachineWASMWorker);
34
10
  }
35
11
 
36
- function StartWASM2(hub, config) {
37
- console.log("GROOVEBOX_BUILD (machine-starter)", GROOVEBOX_BUILD);
38
- return hub.newChannel().then(channel => {
39
- let worker;
40
- if (globalThis.ThisIsNode) {
41
- worker = new Worker(new URL("./machine-wasm.mjs", import.meta.url));
42
- } else {
43
- // FIXME: Stopgap solution until we figure out a way to bundle groovebox correctly
44
- let baseURL = globalThis.GROOVEBOX_URL_PREFIX || "/g";
45
-
46
- // already fire off the download of the wasm code:
47
- let code_url = new URL(`${baseURL}/machine-wasm-code.wasm`, window.location.href);
48
- fetch(code_url, {cache:"default"}).then(resp => { return resp.arrayBuffer() });
49
-
50
- let bundle = new URL(`${baseURL}/machine-wasm-core.js`, window.location.href);
51
- worker = new Worker(bundle);
52
- }
53
- let localFFIs = {};
54
- if (config.localFFIs) {
55
- for (const [k, v] of Object.entries(config.localFFIs)) {
56
- if (v.isRaw && (v.canFail || v.useJsonDecoder)) {
57
- console.error("A raw, local FFI must neither be failing nor use the JSON decoder: " + k);
58
- } else {
59
- localFFIs[k] = {...v};
60
- delete localFFIs[k].run;
61
- }
62
- }
63
- }
64
- let config_msg =
65
- { "_rmx_type": "msg_vm_configure",
66
- "baseURL": config.baseURL,
67
- "org": config.org,
68
- "workspace": config.workspace,
69
- "vmID": config.vmID,
70
- "user": config.user,
71
- "token": config.token,
72
- "hub": channel.port,
73
- "outputViaMQTT": !(config.noOutputViaMQTT),
74
- "machType": config.machType,
75
- "debugMask": initialMask,
76
- "localFFIs": localFFIs,
77
- "grooveboxUrlPrefix": globalThis.GROOVEBOX_URL_PREFIX,
78
- "allowInsecureHttp": globalThis.GROOVEBOX_ALLOW_INSECURE_HTTP,
79
- "interceptFFI": config.interceptFFI,
80
- "interceptDynloadFFI": config.interceptDynloadFFI,
81
- };
82
- worker.postMessage(config_msg, [ channel.port ]);
83
- terminate(() => worker.terminate());
84
- globalThis.MixSetMask = (m => {
85
- worker.postMessage({ "_rmx_type": "msg_vm_logMask",
86
- "mask": m
87
- })
88
- });
89
- if (config.localFFIs)
90
- setupLocalFFIs(hub, config); // don't await!
91
- return worker;
92
- })
93
- }
94
-
95
- class Token {
96
- constructor(data, enabled, extras) {
97
- // data: must be an Uint8Array
98
- // enabled: a number with the bitset of enabled operations
99
- // extras: a map
100
- if (!data instanceof Uint8Array)
101
- throw new Error("Token: data must be an Uint8Array");
102
- if (typeof(enabled) != "number")
103
- throw new Error("Token: enabled_ops must be a number");
104
- this.data = data;
105
- this.enabled = enabled;
106
- this.extras = extras;
107
- }
108
- encode() {
109
- return new Map([
110
- [ "_rmx_type", "token" ],
111
- [ "data", this.data ],
112
- [ "enabled", this.enabled ],
113
- [ "extras", this.extras ]
114
- ]);
115
- }
116
- }
117
-
118
- function decode_Token(m) {
119
- return new Token(m.get("data"), m.get("enabled"), m.get("extras"))
120
- }
121
-
122
- class Case {
123
- constructor(name, arg) {
124
- if (typeof(name) != "string")
125
- throw new Error("Case: name must be a string");
126
- this.name = name;
127
- this.arg = arg;
128
- }
129
- encode() {
130
- return new Map([
131
- [ "_rmx_type", "case" ],
132
- [ "name", this.name ],
133
- [ "arg", this.arg ],
134
- ]);
135
- }
136
- }
137
-
138
- function decode_Case(m) {
139
- return new Case(m.get("name"), m.get("arg"))
140
- }
141
-
142
- class Opaque {
143
- constructor(buf) {
144
- if (!(buf instanceof Uint32Array))
145
- throw new Error("Opaque: must be a Uint32Array");
146
- this.data = buf;
147
- }
148
- encode() {
149
- return new Map([
150
- [ "_rmx_type", "opaque" ],
151
- [ "data", this.data ],
152
- ]);
153
- }
154
- }
155
-
156
- function decode_Opaque(m) {
157
- return new Opaque(m.get("data"))
158
- }
159
-
160
- function encode(val) {
161
- switch (typeof(val)) {
162
- case "object":
163
- if (val === null) return val;
164
- if (Array.isArray(val)) {
165
- // array: map the array elements
166
- val = val.map(encode)
167
- } else if (Object.getPrototypeOf(val) === Object.prototype) {
168
- // simple object: map the object elements
169
- val = Object.fromEntries(Object.entries(val).map(([ key, elem ]) => [ key, encode(elem) ]))
170
- } else if (val.encode instanceof Function) {
171
- // map after encode(): map the map elements
172
- val = new Map(Array.from(val.encode().entries()).map(([ key, elem ]) => [ key, encode(elem) ]))
173
- };
174
- return val;
175
- default:
176
- return val;
177
- }
178
- }
179
-
180
- function decode(val) {
181
- switch (typeof(val)) {
182
- case "object":
183
- if (val === null) return val;
184
- if (Array.isArray(val)) {
185
- // array: map the array elements
186
- val = val.map(decode)
187
- } else if (Object.getPrototypeOf(val) === Object.prototype) {
188
- // simple object: map the object elements
189
- val = Object.fromEntries(Object.entries(val).map(([ key, elem ]) => [ key, decode(elem) ]))
190
- } else if (val instanceof Map) {
191
- val = new Map(Array.from(val.entries()).map(([ key, elem ]) => [ key, decode(elem) ]))
192
- let ty = val.get("_rmx_type");
193
- switch (ty) {
194
- case "token":
195
- return decode_Token(val);
196
- case "case":
197
- return decode_Case(val);
198
- case "opaque":
199
- return decode_Opaque(val);
200
- default:
201
- throw new Error("decode: bad _rmx_type: " + ty);
202
- }
203
- };
204
- return val;
205
- default:
206
- return val;
207
- }
208
- }
209
-
210
- async function setupLocalFFIs(hub, config) {
211
- let channel = await hub.newChannel();
212
- let comm = new FFIComm(hub, channel);
213
- let localFFIs = config.localFFIs;
214
- await channel.setLocalSubTopic("/local/ffi/call");
215
- await channel.setLocalPubTopic("/local/ffi/return");
216
- let sub = await channel.subscribe("/local/ffi/call");
217
- while (true) {
218
- let msg = await sub.next();
219
- let name = msg.payload.name;
220
- let call_id = msg.payload.call_id;
221
- let args = decode(msg.payload.args);
222
- let fun = localFFIs[name];
223
- try {
224
- if (!fun)
225
- throw new Error("no such local FFI: " + name);
226
- let connector =
227
- { call_id: call_id,
228
- hub: hub,
229
- channel: channel,
230
- state: config.state,
231
- };
232
- let r = fun instanceof Function ? fun(connector, args) : fun.run(connector, args);
233
- if (r instanceof Promise) {
234
- await comm.later(call_id);
235
- r.then(
236
- (value) => comm.returnOrFail(fun, call_id, value),
237
- (reason) => comm.error(call_id, reason.message, reason.stack));
238
- } else {
239
- await comm.returnOrFail(fun, call_id, r);
240
- }
241
- } catch (reason) {
242
- await comm.error(call_id, reason.message, reason.stack);
243
- }
244
- }
245
- }
246
-
247
- class FFIComm {
248
- constructor(hub, channel) {
249
- this.hub = hub;
250
- this.channel = channel;
251
- }
252
- later(call_id) {
253
- let r_payload =
254
- { call_id: call_id,
255
- };
256
- let response = this.hub.newLocalMessage("msg_ffi_later", "starter", r_payload);
257
- return this.channel.publish("/local/ffi/return", response, false);
258
- }
259
- return_(fun, call_id, result) {
260
- let r_payload =
261
- { call_id: call_id,
262
- value: fun.useJsonDecoder ? result : encode(result)
263
- };
264
- let response = this.hub.newLocalMessage("msg_ffi_return", "starter", r_payload);
265
- return this.channel.publish("/local/ffi/return", response, false);
266
- }
267
- error(call_id, message, stack) {
268
- let r_payload =
269
- { call_id: call_id,
270
- message: message,
271
- stack: stack === undefined ? [] : stack,
272
- };
273
- let response = this.hub.newLocalMessage("msg_ffi_error", "starter", r_payload);
274
- this.channel.publish("/local/ffi/return", response, false);
275
- }
276
- returnOrFail(fun, call_id, result) {
277
- if (fun.canFail) {
278
- var name, arg;
279
- if (result instanceof Case) {
280
- name = result.name;
281
- arg = result.arg;
282
- } else if (fun.useJsonDecoder && result._rmx_type && result._rmx_type.startsWith("{tag}case:")) {
283
- name = result._rmx_type.substring(10);
284
- arg = result._rmx_value;
285
- } else {
286
- return this.error(call_id, "expected result from local FFI that can fail");
287
- }
288
- switch (name) {
289
- case "ok":
290
- return this.return_(fun, call_id, arg);
291
- case "error":
292
- return this.error(call_id, arg);
293
- default:
294
- return this.error(call_id, "expected result from local FFI that can fail, found case value " + name);
295
- }
296
- } else {
297
- return this.return_(fun, call_id, result);
298
- }
299
- }
300
- }
12
+ globalThis.GetMachineWASMWorker = GetMachineWASMWorker;
301
13
 
302
- // use worker.terminate() to shut a worker down!
14
+ export * from './common.js';
303
15
 
304
- export { CreateVMID, StartWASM, StartWASM2,
305
- Token, Case, Opaque
306
- }
package/node.js CHANGED
@@ -14,8 +14,12 @@ global.Process = Process;
14
14
  // or the browser Worker to give the same interface). Webpack says ESM
15
15
  // is necessary but I'm not sure if this is true for either the main
16
16
  // script or the workers.
17
- import { MessageChannel, Worker } from "worker_threads";
18
- global.Worker = Worker;
17
+ import { Worker } from "worker_threads";
18
+
19
+ function GetMachineWASMWorker() {
20
+ return new Worker(new URL("./machine-wasm.mjs", import.meta.url));
21
+ }
22
+ global.GetMachineWASMWorker = GetMachineWASMWorker;
19
23
 
20
24
  import * as Hub from "@remix_labs/hub-client";
21
25
 
@@ -24,7 +28,7 @@ global.__filename = fileURLToPath(import.meta.url);
24
28
 
25
29
  import { CreateVMID, StartWASM, StartWASM2,
26
30
  Token, Case, Opaque
27
- } from "./index.js";
31
+ } from "./common.js";
28
32
 
29
33
  export { CreateVMID, StartWASM, StartWASM2,
30
34
  Token, Case, Opaque, Hub
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix_labs/machine-starter",
3
- "version": "1.1890.0-dev",
3
+ "version": "1.1895.0-dev",
4
4
  "description": "start the groove",
5
5
  "main": "node.js",
6
6
  "browser": "index.js",
@@ -11,7 +11,7 @@
11
11
  "author": "Remixlabs staff",
12
12
  "license": "ISC",
13
13
  "dependencies": {
14
- "@remix_labs/hub-client": "1.1890.0-dev",
14
+ "@remix_labs/hub-client": "1.1895.0-dev",
15
15
  "nanoid": "^3.1.12",
16
16
  "web-worker": "^1.2.0"
17
17
  },
package/webpack.config.js CHANGED
@@ -6,12 +6,37 @@ const __dirname = path.dirname(__filename);
6
6
 
7
7
  export default [
8
8
  {
9
+ name: 'web',
10
+ entry: './index.js',
11
+ mode: "production",
12
+ output: {
13
+ filename: 'machine-starter.js',
14
+ path: path.resolve(__dirname, '../dist')
15
+ },
16
+ optimization: {
17
+ minimize: false
18
+ },
19
+ module: {
20
+ rules: [
21
+ {
22
+ test: /\.worker.js$/,
23
+ type: 'asset/source'
24
+ },
25
+ {
26
+ // Needed for import.meta.url unless we bundle the web workers
27
+ // themselves as separate entries in this bundle.
28
+ test: /\.js$/,
29
+ loader: '@open-wc/webpack-import-meta-loader'
30
+ }
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ name: 'node',
9
36
  target: 'node',
10
37
  mode: "production",
11
38
  entry: {
12
39
  node: './start.mjs',
13
- //'hub-worker': './hub-worker.js',
14
- //'machine-wasm': './machine-wasm.js',
15
40
  },
16
41
  optimization: {
17
42
  minimize: false,
@@ -19,6 +44,8 @@ export default [
19
44
  module: {
20
45
  rules: [
21
46
  {
47
+ // Needed for import.meta.url unless we bundle the web workers
48
+ // themselves as separate entries in this bundle.
22
49
  test: /\.js$/,
23
50
  loader: '@open-wc/webpack-import-meta-loader'
24
51
  }
@@ -29,7 +56,7 @@ export default [
29
56
  },
30
57
  output: {
31
58
  chunkFormat: 'module',
32
- filename: 'machine-starter.mjs',
59
+ filename: 'machine-starter.node.mjs',
33
60
  library : {
34
61
  type: 'module',
35
62
  },