@jsenv/core 27.4.0 → 27.5.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 (86) hide show
  1. package/dist/js/autoreload.js +359 -0
  2. package/dist/js/execute_using_dynamic_import.js +1 -1
  3. package/dist/js/html_supervisor_installer.js +469 -254
  4. package/dist/js/html_supervisor_setup.js +3 -4
  5. package/dist/js/new_stylesheet.js +26 -58
  6. package/dist/js/server_events_client.js +307 -0
  7. package/dist/main.js +7558 -7311
  8. package/package.json +12 -10
  9. package/{README.md → readme.md} +8 -9
  10. package/src/build/build.js +12 -16
  11. package/src/build/start_build_server.js +24 -28
  12. package/src/dev/start_dev_server.js +34 -96
  13. package/src/execute/execute.js +17 -35
  14. package/src/omega/errors.js +20 -18
  15. package/src/omega/kitchen.js +7 -6
  16. package/src/omega/omega_server.js +96 -127
  17. package/src/omega/server/file_service.js +247 -46
  18. package/src/omega/url_graph.js +33 -20
  19. package/src/plugins/autoreload/client/autoreload.js +201 -0
  20. package/src/plugins/autoreload/{dev_sse/client → client}/autoreload_preference.js +0 -0
  21. package/src/plugins/autoreload/{dev_sse/client → client}/reload.js +29 -10
  22. package/src/plugins/autoreload/{dev_sse/client → client}/url_helpers.js +0 -0
  23. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -4
  24. package/src/plugins/autoreload/{dev_sse/jsenv_plugin_dev_sse_client.js → jsenv_plugin_autoreload_client.js} +8 -8
  25. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +196 -0
  26. package/src/{dev/plugins → plugins}/explorer/client/explorer.html +0 -0
  27. package/src/{dev/plugins → plugins}/explorer/client/jsenv.png +0 -0
  28. package/src/{dev/plugins → plugins}/explorer/jsenv_plugin_explorer.js +1 -3
  29. package/src/plugins/html_supervisor/client/error_formatter.js +300 -0
  30. package/src/plugins/html_supervisor/client/error_overlay.js +172 -0
  31. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +124 -54
  32. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
  33. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +72 -27
  34. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +97 -117
  35. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +66 -58
  36. package/src/plugins/plugin_controller.js +102 -67
  37. package/src/plugins/plugins.js +10 -8
  38. package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +102 -31
  39. package/src/plugins/server_events/client/server_events_client.js +17 -0
  40. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +48 -0
  41. package/src/plugins/server_events/server_events_dispatcher.js +69 -0
  42. package/src/{dev/plugins → plugins}/toolbar/client/animation/toolbar_animation.js +0 -0
  43. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/eventsource.css +0 -0
  44. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/toolbar_eventsource.js +0 -0
  45. package/src/{dev/plugins → plugins}/toolbar/client/execution/execution.css +0 -0
  46. package/src/{dev/plugins → plugins}/toolbar/client/execution/toolbar_execution.js +0 -0
  47. package/src/{dev/plugins → plugins}/toolbar/client/focus/focus.css +0 -0
  48. package/src/{dev/plugins → plugins}/toolbar/client/focus/toolbar_focus.js +0 -0
  49. package/src/{dev/plugins → plugins}/toolbar/client/jsenv_logo.svg +0 -0
  50. package/src/{dev/plugins → plugins}/toolbar/client/notification/toolbar_notification.js +0 -0
  51. package/src/{dev/plugins → plugins}/toolbar/client/responsive/overflow_menu.css +0 -0
  52. package/src/{dev/plugins → plugins}/toolbar/client/responsive/toolbar_responsive.js +0 -0
  53. package/src/{dev/plugins → plugins}/toolbar/client/settings/settings.css +0 -0
  54. package/src/{dev/plugins → plugins}/toolbar/client/settings/toolbar_settings.js +0 -0
  55. package/src/{dev/plugins → plugins}/toolbar/client/theme/jsenv_theme.css +0 -0
  56. package/src/{dev/plugins → plugins}/toolbar/client/theme/light_theme.css +0 -0
  57. package/src/{dev/plugins → plugins}/toolbar/client/theme/toolbar_theme.js +0 -0
  58. package/src/{dev/plugins → plugins}/toolbar/client/toolbar.html +0 -0
  59. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_injector.js +0 -0
  60. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.css +0 -0
  61. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.js +0 -0
  62. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.css +0 -0
  63. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.js +0 -0
  64. package/src/{dev/plugins → plugins}/toolbar/client/util/animation.js +0 -0
  65. package/src/{dev/plugins → plugins}/toolbar/client/util/dom.js +0 -0
  66. package/src/{dev/plugins → plugins}/toolbar/client/util/fetch_using_xhr.js +0 -0
  67. package/src/{dev/plugins → plugins}/toolbar/client/util/fetching.js +0 -0
  68. package/src/{dev/plugins → plugins}/toolbar/client/util/iframe_to_parent_href.js +0 -0
  69. package/src/{dev/plugins → plugins}/toolbar/client/util/jsenv_logger.js +0 -0
  70. package/src/{dev/plugins → plugins}/toolbar/client/util/preferences.js +0 -0
  71. package/src/{dev/plugins → plugins}/toolbar/client/util/responsive.js +0 -0
  72. package/src/{dev/plugins → plugins}/toolbar/client/util/util.js +0 -0
  73. package/src/{dev/plugins → plugins}/toolbar/client/variant/variant.js +0 -0
  74. package/src/{dev/plugins → plugins}/toolbar/jsenv_plugin_toolbar.js +0 -0
  75. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +4 -3
  76. package/src/plugins/transpilation/babel/new_stylesheet/client/new_stylesheet.js +25 -55
  77. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +44 -24
  78. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +6 -1
  79. package/src/plugins/url_analysis/html/html_urls.js +8 -8
  80. package/src/test/execute_plan.js +36 -54
  81. package/src/test/execute_test_plan.js +2 -2
  82. package/dist/js/event_source_client.js +0 -549
  83. package/src/helpers/event_source/sse_service.js +0 -53
  84. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
  85. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -192
  86. package/src/plugins/html_supervisor/client/error_in_document.js +0 -345
@@ -1,549 +0,0 @@
1
- import { urlHotMetas } from "./import_meta_hot.js";
2
- import { parseSrcSet, stringifySrcSet } from "@jsenv/ast/src/html/html_src_set.js";
3
-
4
- /* eslint-env browser */
5
- const STATUSES = {
6
- CONNECTING: "connecting",
7
- CONNECTED: "connected",
8
- DISCONNECTED: "disconnected"
9
- };
10
- const createEventSourceConnection = (eventSourceUrl, {
11
- retryMaxAttempt = Infinity,
12
- retryAllocatedMs = Infinity,
13
- lastEventId
14
- } = {}) => {
15
- const {
16
- EventSource
17
- } = window;
18
-
19
- if (typeof EventSource !== "function") {
20
- return () => {};
21
- }
22
-
23
- let eventSource;
24
- const events = {};
25
- const eventSourceOrigin = new URL(eventSourceUrl).origin;
26
-
27
- const addEventCallbacks = eventCallbacks => {
28
- Object.keys(eventCallbacks).forEach(eventName => {
29
- const eventCallback = eventCallbacks[eventName];
30
-
31
- events[eventName] = e => {
32
- if (e.origin === eventSourceOrigin) {
33
- if (e.lastEventId) {
34
- lastEventId = e.lastEventId;
35
- }
36
-
37
- eventCallback(e);
38
- }
39
- };
40
-
41
- if (eventSource) {
42
- eventSource.addEventListener(eventName, events[eventName]);
43
- }
44
- });
45
- };
46
-
47
- addEventCallbacks(events);
48
- const status = {
49
- value: "default",
50
- goTo: value => {
51
- if (value === status.value) {
52
- return;
53
- }
54
-
55
- status.value = value;
56
- status.onchange();
57
- },
58
- onchange: () => {}
59
- };
60
-
61
- let _disconnect = () => {};
62
-
63
- const attemptConnection = url => {
64
- eventSource = new EventSource(url, {
65
- withCredentials: true
66
- });
67
-
68
- _disconnect = () => {
69
- if (status.value !== STATUSES.CONNECTING && status.value !== STATUSES.CONNECTED) {
70
- console.warn(`disconnect() ignored because connection is ${status.value}`);
71
- return;
72
- }
73
-
74
- eventSource.onerror = undefined;
75
- eventSource.close();
76
- Object.keys(events).forEach(eventName => {
77
- eventSource.removeEventListener(eventName, events[eventName]);
78
- });
79
- eventSource = null;
80
- status.goTo(STATUSES.DISCONNECTED);
81
- };
82
-
83
- let retryCount = 0;
84
- let firstRetryMs = Date.now();
85
-
86
- eventSource.onerror = errorEvent => {
87
- if (errorEvent.target.readyState === EventSource.CONNECTING) {
88
- if (retryCount > retryMaxAttempt) {
89
- console.info(`could not connect after ${retryMaxAttempt} attempt`);
90
-
91
- _disconnect();
92
-
93
- return;
94
- }
95
-
96
- if (retryCount === 0) {
97
- firstRetryMs = Date.now();
98
- } else {
99
- const allRetryDuration = Date.now() - firstRetryMs;
100
-
101
- if (retryAllocatedMs && allRetryDuration > retryAllocatedMs) {
102
- console.info(`could not connect in less than ${retryAllocatedMs} ms`);
103
-
104
- _disconnect();
105
-
106
- return;
107
- }
108
- }
109
-
110
- retryCount++;
111
- status.goTo(STATUSES.CONNECTING);
112
- return;
113
- }
114
-
115
- if (errorEvent.target.readyState === EventSource.CLOSED) {
116
- _disconnect();
117
-
118
- return;
119
- }
120
- };
121
-
122
- eventSource.onopen = () => {
123
- status.goTo(STATUSES.CONNECTED);
124
- };
125
-
126
- Object.keys(events).forEach(eventName => {
127
- eventSource.addEventListener(eventName, events[eventName]);
128
- });
129
-
130
- if (!events.hasOwnProperty("welcome")) {
131
- eventSource.addEventListener("welcome", e => {
132
- if (e.origin === eventSourceOrigin && e.lastEventId) {
133
- lastEventId = e.lastEventId;
134
- }
135
- });
136
- }
137
-
138
- status.goTo(STATUSES.CONNECTING);
139
- };
140
-
141
- let connect = () => {
142
- attemptConnection(eventSourceUrl);
143
-
144
- connect = () => {
145
- attemptConnection(lastEventId ? addLastEventIdIntoUrlSearchParams(eventSourceUrl, lastEventId) : eventSourceUrl);
146
- };
147
- };
148
-
149
- const removePageUnloadListener = listenPageUnload(() => {
150
- if (status.value === STATUSES.CONNECTING || status.value === STATUSES.CONNECTED) {
151
- _disconnect();
152
- }
153
- });
154
-
155
- const destroy = () => {
156
- removePageUnloadListener();
157
-
158
- _disconnect();
159
- };
160
-
161
- return {
162
- status,
163
- connect,
164
- addEventCallbacks,
165
- disconnect: () => _disconnect(),
166
- destroy
167
- };
168
- };
169
-
170
- const addLastEventIdIntoUrlSearchParams = (url, lastEventId) => {
171
- if (url.indexOf("?") === -1) {
172
- url += "?";
173
- } else {
174
- url += "&";
175
- }
176
-
177
- return `${url}last-event-id=${encodeURIComponent(lastEventId)}`;
178
- }; // const listenPageMightFreeze = (callback) => {
179
- // const removePageHideListener = listenEvent(window, "pagehide", (pageHideEvent) => {
180
- // if (pageHideEvent.persisted === true) {
181
- // callback(pageHideEvent)
182
- // }
183
- // })
184
- // return removePageHideListener
185
- // }
186
- // const listenPageFreeze = (callback) => {
187
- // const removeFreezeListener = listenEvent(document, "freeze", (freezeEvent) => {
188
- // callback(freezeEvent)
189
- // })
190
- // return removeFreezeListener
191
- // }
192
- // const listenPageIsRestored = (callback) => {
193
- // const removeResumeListener = listenEvent(document, "resume", (resumeEvent) => {
194
- // removePageshowListener()
195
- // callback(resumeEvent)
196
- // })
197
- // const removePageshowListener = listenEvent(window, "pageshow", (pageshowEvent) => {
198
- // if (pageshowEvent.persisted === true) {
199
- // removePageshowListener()
200
- // removeResumeListener()
201
- // callback(pageshowEvent)
202
- // }
203
- // })
204
- // return () => {
205
- // removeResumeListener()
206
- // removePageshowListener()
207
- // }
208
- // }
209
-
210
-
211
- const listenPageUnload = callback => {
212
- const removePageHideListener = listenEvent(window, "pagehide", pageHideEvent => {
213
- if (pageHideEvent.persisted !== true) {
214
- callback(pageHideEvent);
215
- }
216
- });
217
- return removePageHideListener;
218
- };
219
-
220
- const listenEvent = (emitter, event, callback) => {
221
- emitter.addEventListener(event, callback);
222
- return () => {
223
- emitter.removeEventListener(event, callback);
224
- };
225
- };
226
-
227
- const isAutoreloadEnabled = () => {
228
- const value = window.localStorage.getItem("autoreload");
229
-
230
- if (value === "0") {
231
- return false;
232
- }
233
-
234
- return true;
235
- };
236
- const setAutoreloadPreference = value => {
237
- window.localStorage.setItem("autoreload", value ? "1" : "0");
238
- };
239
-
240
- const compareTwoUrlPaths = (url, otherUrl) => {
241
- if (url === otherUrl) {
242
- return true;
243
- }
244
-
245
- const urlObject = new URL(url);
246
- const otherUrlObject = new URL(otherUrl);
247
- return urlObject.origin === otherUrlObject.origin && urlObject.pathname === otherUrlObject.pathname;
248
- };
249
- const injectQuery = (url, query) => {
250
- const urlObject = new URL(url);
251
- const {
252
- searchParams
253
- } = urlObject;
254
- Object.keys(query).forEach(key => {
255
- searchParams.set(key, query[key]);
256
- });
257
- return String(urlObject);
258
- };
259
-
260
- const reloadHtmlPage = () => {
261
- window.location.reload(true);
262
- }; // This function can consider everything as hot reloadable:
263
- // - no need to check [hot-accept]and [hot-decline] attributes for instance
264
- // This is because if something should full reload, we receive "full_reload"
265
- // from server and this function is not called
266
-
267
- const reloadDOMNodesUsingUrl = urlToReload => {
268
- const mutations = [];
269
-
270
- const shouldReloadUrl = urlCandidate => {
271
- return compareTwoUrlPaths(urlCandidate, urlToReload);
272
- };
273
-
274
- const visitNodeAttributeAsUrl = (node, attributeName) => {
275
- let attribute = node[attributeName];
276
-
277
- if (!attribute) {
278
- return;
279
- }
280
-
281
- if (SVGAnimatedString && attribute instanceof SVGAnimatedString) {
282
- attribute = attribute.animVal;
283
- }
284
-
285
- if (!shouldReloadUrl(attribute)) {
286
- return;
287
- }
288
-
289
- mutations.push(() => {
290
- node[attributeName] = injectQuery(attribute, {
291
- hmr: Date.now()
292
- });
293
- });
294
- };
295
-
296
- Array.from(document.querySelectorAll(`link[rel="stylesheet"]`)).forEach(link => {
297
- visitNodeAttributeAsUrl(link, "href");
298
- });
299
- Array.from(document.querySelectorAll(`link[rel="icon"]`)).forEach(link => {
300
- visitNodeAttributeAsUrl(link, "href");
301
- });
302
- Array.from(document.querySelector("script")).forEach(script => {
303
- visitNodeAttributeAsUrl(script, "src");
304
- }); // There is no real need to update a.href because the ressource will be fetched when clicked.
305
- // But in a scenario where the ressource was already visited and is in browser cache, adding
306
- // the dynamic query param ensure the cache is invalidated
307
-
308
- Array.from(document.querySelectorAll("a")).forEach(a => {
309
- visitNodeAttributeAsUrl(a, "href");
310
- }); // About iframes:
311
- // - By default iframe itself and everything inside trigger a parent page full-reload
312
- // - Adding [hot-accept] on the iframe means parent page won't reload when iframe full/hot reload
313
- // In that case and if there is code in the iframe and parent doing post message communication:
314
- // you must put import.meta.hot.decline() for code involved in communication.
315
- // (both in parent and iframe)
316
-
317
- Array.from(document.querySelectorAll("img")).forEach(img => {
318
- visitNodeAttributeAsUrl(img, "src");
319
- const srcset = img.srcset;
320
-
321
- if (srcset) {
322
- const srcCandidates = parseSrcSet(srcset);
323
- srcCandidates.forEach(srcCandidate => {
324
- const url = new URL(srcCandidate.specifier, `${window.location.href}`);
325
-
326
- if (shouldReloadUrl(url)) {
327
- srcCandidate.specifier = injectQuery(url, {
328
- hmr: Date.now()
329
- });
330
- }
331
- });
332
- mutations.push(() => {
333
- img.srcset = stringifySrcSet(srcCandidates);
334
- });
335
- }
336
- });
337
- Array.from(document.querySelectorAll("source")).forEach(source => {
338
- visitNodeAttributeAsUrl(source, "src");
339
- }); // svg image tag
340
-
341
- Array.from(document.querySelectorAll("image")).forEach(image => {
342
- visitNodeAttributeAsUrl(image, "href");
343
- }); // svg use
344
-
345
- Array.from(document.querySelectorAll("use")).forEach(use => {
346
- visitNodeAttributeAsUrl(use, "href");
347
- });
348
- mutations.forEach(mutation => {
349
- mutation();
350
- });
351
- };
352
- const reloadJsImport = async url => {
353
- const urlWithHmr = injectQuery(url, {
354
- hmr: Date.now()
355
- });
356
- const namespace = await import(urlWithHmr);
357
- return namespace;
358
- };
359
-
360
- const reloadMessages = [];
361
- const reloadMessagesSignal = {
362
- onchange: () => {}
363
- };
364
- let pendingCallbacks = [];
365
- let running = false;
366
-
367
- const addToHotQueue = async callback => {
368
- pendingCallbacks.push(callback);
369
- dequeue();
370
- };
371
-
372
- const dequeue = async () => {
373
- if (running) {
374
- return;
375
- }
376
-
377
- const callbacks = pendingCallbacks.slice();
378
- pendingCallbacks = [];
379
- running = true;
380
-
381
- try {
382
- await callbacks.reduce(async (previous, callback) => {
383
- await previous;
384
- await callback();
385
- }, Promise.resolve());
386
- } finally {
387
- running = false;
388
-
389
- if (pendingCallbacks.length) {
390
- dequeue();
391
- }
392
- }
393
- };
394
-
395
- const applyReloadMessageEffects = async () => {
396
- const someEffectIsFullReload = reloadMessages.some(reloadMessage => reloadMessage.type === "full");
397
-
398
- if (someEffectIsFullReload) {
399
- reloadHtmlPage();
400
- return;
401
- }
402
-
403
- const onApplied = reloadMessage => {
404
- const index = reloadMessages.indexOf(reloadMessage);
405
- reloadMessages.splice(index, 1);
406
- reloadMessagesSignal.onchange();
407
- };
408
-
409
- const setReloadMessagePromise = (reloadMessage, promise) => {
410
- reloadMessage.status = "pending";
411
- promise.then(() => {
412
- onApplied(reloadMessage);
413
- }, e => {
414
- // TODO: reuse error display from html supervisor
415
- console.error(e);
416
- console.error(`[hmr] Failed to reload after ${reloadMessage.reason}.
417
- This could be due to syntax errors or importing non-existent modules (see errors above)`);
418
- reloadMessage.status = "failed";
419
- reloadMessagesSignal.onchange();
420
- });
421
- };
422
-
423
- reloadMessages.forEach(reloadMessage => {
424
- if (reloadMessage.type === "hot") {
425
- const promise = addToHotQueue(() => {
426
- return applyHotReload(reloadMessage);
427
- });
428
- setReloadMessagePromise(reloadMessage, promise);
429
- } else {
430
- setReloadMessagePromise(reloadMessage, Promise.resolve());
431
- }
432
- });
433
- reloadMessagesSignal.onchange(); // reload status is "pending"
434
- };
435
-
436
- const applyHotReload = async ({
437
- hotInstructions
438
- }) => {
439
- await hotInstructions.reduce(async (previous, {
440
- type,
441
- boundary,
442
- acceptedBy
443
- }) => {
444
- await previous;
445
- const urlToFetch = new URL(boundary, `${window.location.origin}/`).href;
446
- const urlHotMeta = urlHotMetas[urlToFetch]; // TODO: we should return when there is no url hot meta because
447
- // it means code was not executed (code splitting with dynamic import)
448
- // if (!urlHotMeta) {return }
449
-
450
- if (type === "prune") {
451
- console.groupCollapsed(`[jsenv] prune: ${boundary} (inside ${acceptedBy})`);
452
- } else if (acceptedBy === boundary) {
453
- console.groupCollapsed(`[jsenv] hot reloading: ${boundary}`);
454
- } else {
455
- console.groupCollapsed(`[jsenv] hot reloading: ${acceptedBy} inside ${boundary}`);
456
- }
457
-
458
- if (urlHotMeta && urlHotMeta.disposeCallback) {
459
- console.log(`call dispose callback`);
460
- await urlHotMeta.disposeCallback();
461
- }
462
-
463
- if (type === "prune") {
464
- delete urlHotMetas[urlToFetch];
465
- console.log(`cleanup pruned url`);
466
- console.groupEnd();
467
- return null;
468
- }
469
-
470
- if (type === "js_module") {
471
- console.log(`importing js module`);
472
- const namespace = await reloadJsImport(urlToFetch);
473
-
474
- if (urlHotMeta && urlHotMeta.acceptCallback) {
475
- await urlHotMeta.acceptCallback(namespace);
476
- }
477
-
478
- console.log(`js module import done`);
479
- console.groupEnd();
480
- return namespace;
481
- }
482
-
483
- if (type === "html") {
484
- if (!compareTwoUrlPaths(urlToFetch, window.location.href)) {
485
- // we are not in that HTML page
486
- return null;
487
- }
488
-
489
- console.log(`reloading url`);
490
- const urlToReload = new URL(acceptedBy, `${window.location.origin}/`).href;
491
- reloadDOMNodesUsingUrl(urlToReload);
492
- console.log(`url reloaded`);
493
- console.groupEnd();
494
- return null;
495
- }
496
-
497
- console.warn(`unknown update type: "${type}"`);
498
- return null;
499
- }, Promise.resolve());
500
- };
501
-
502
- const addReloadMessage = reloadMessage => {
503
- reloadMessages.push(reloadMessage);
504
-
505
- if (isAutoreloadEnabled()) {
506
- applyReloadMessageEffects();
507
- } else {
508
- reloadMessagesSignal.onchange();
509
- }
510
- };
511
-
512
- const eventsourceConnection = createEventSourceConnection(document.location.href, {
513
- retryMaxAttempt: Infinity,
514
- retryAllocatedMs: 20 * 1000
515
- });
516
- const {
517
- status,
518
- connect,
519
- addEventCallbacks,
520
- disconnect
521
- } = eventsourceConnection;
522
- eventsourceConnection.addEventCallbacks({
523
- reload: ({
524
- data
525
- }) => {
526
- const reloadMessage = JSON.parse(data);
527
- addReloadMessage(reloadMessage);
528
- }
529
- });
530
- connect();
531
- window.__jsenv_event_source_client__ = {
532
- addEventCallbacks,
533
- status,
534
- connect,
535
- disconnect,
536
- isAutoreloadEnabled,
537
- setAutoreloadPreference,
538
- urlHotMetas,
539
- reloadMessages,
540
- reloadMessagesSignal,
541
- applyReloadMessageEffects,
542
- addReloadMessage
543
- }; // const findHotMetaUrl = (originalFileRelativeUrl) => {
544
- // return Object.keys(urlHotMetas).find((compileUrl) => {
545
- // return (
546
- // parseCompiledUrl(compileUrl).fileRelativeUrl === originalFileRelativeUrl
547
- // )
548
- // })
549
- // }
@@ -1,53 +0,0 @@
1
- import { createSSERoom } from "@jsenv/server"
2
- import { createCallbackListNotifiedOnce } from "@jsenv/abort"
3
-
4
- export const createSSEService = ({ serverEventCallbackList }) => {
5
- const destroyCallbackList = createCallbackListNotifiedOnce()
6
-
7
- const cache = []
8
- const sseRoomLimit = 100
9
- const getOrCreateSSERoom = (request) => {
10
- const htmlFileRelativeUrl = request.ressource.slice(1)
11
- const cacheEntry = cache.find(
12
- (cacheEntryCandidate) =>
13
- cacheEntryCandidate.htmlFileRelativeUrl === htmlFileRelativeUrl,
14
- )
15
- if (cacheEntry) {
16
- return cacheEntry.sseRoom
17
- }
18
- const sseRoom = createSSERoom({
19
- retryDuration: 2000,
20
- historyLength: 100,
21
- welcomeEventEnabled: true,
22
- effect: () => {
23
- return serverEventCallbackList.add((event) => {
24
- sseRoom.sendEvent(event)
25
- })
26
- },
27
- })
28
- const removeSSECleanupCallback = destroyCallbackList.add(() => {
29
- removeSSECleanupCallback()
30
- sseRoom.close()
31
- })
32
- cache.push({
33
- htmlFileRelativeUrl,
34
- sseRoom,
35
- cleanup: () => {
36
- removeSSECleanupCallback()
37
- sseRoom.close()
38
- },
39
- })
40
- if (cache.length >= sseRoomLimit) {
41
- const firstCacheEntry = cache.shift()
42
- firstCacheEntry.cleanup()
43
- }
44
- return sseRoom
45
- }
46
-
47
- return {
48
- getOrCreateSSERoom,
49
- destroy: () => {
50
- destroyCallbackList.notify()
51
- },
52
- }
53
- }