@jsenv/core 27.3.4 → 27.5.1

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 (88) 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 +524 -147
  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 +7709 -7324
  8. package/package.json +15 -15
  9. package/{README.md → readme.md} +18 -7
  10. package/src/build/build.js +16 -18
  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 +43 -9
  15. package/src/omega/kitchen.js +42 -25
  16. package/src/omega/omega_server.js +96 -74
  17. package/src/omega/server/file_service.js +256 -28
  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 -8
  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_overlay.js +401 -0
  30. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +138 -23
  31. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
  32. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +55 -23
  33. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +97 -117
  34. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +66 -58
  35. package/src/plugins/plugin_controller.js +102 -67
  36. package/src/plugins/plugins.js +10 -10
  37. package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +125 -33
  38. package/src/plugins/server_events/client/server_events_client.js +17 -0
  39. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +48 -0
  40. package/src/plugins/server_events/server_events_dispatcher.js +69 -0
  41. package/src/{dev/plugins → plugins}/toolbar/client/animation/toolbar_animation.js +0 -0
  42. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/eventsource.css +0 -0
  43. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/toolbar_eventsource.js +0 -0
  44. package/src/{dev/plugins → plugins}/toolbar/client/execution/execution.css +0 -0
  45. package/src/{dev/plugins → plugins}/toolbar/client/execution/toolbar_execution.js +0 -0
  46. package/src/{dev/plugins → plugins}/toolbar/client/focus/focus.css +0 -0
  47. package/src/{dev/plugins → plugins}/toolbar/client/focus/toolbar_focus.js +0 -0
  48. package/src/{dev/plugins → plugins}/toolbar/client/jsenv_logo.svg +0 -0
  49. package/src/{dev/plugins → plugins}/toolbar/client/notification/toolbar_notification.js +0 -0
  50. package/src/{dev/plugins → plugins}/toolbar/client/responsive/overflow_menu.css +0 -0
  51. package/src/{dev/plugins → plugins}/toolbar/client/responsive/toolbar_responsive.js +0 -0
  52. package/src/{dev/plugins → plugins}/toolbar/client/settings/settings.css +0 -0
  53. package/src/{dev/plugins → plugins}/toolbar/client/settings/toolbar_settings.js +0 -0
  54. package/src/{dev/plugins → plugins}/toolbar/client/theme/jsenv_theme.css +0 -0
  55. package/src/{dev/plugins → plugins}/toolbar/client/theme/light_theme.css +0 -0
  56. package/src/{dev/plugins → plugins}/toolbar/client/theme/toolbar_theme.js +0 -0
  57. package/src/{dev/plugins → plugins}/toolbar/client/toolbar.html +0 -0
  58. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_injector.js +0 -0
  59. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.css +0 -0
  60. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.js +0 -0
  61. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.css +0 -0
  62. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.js +0 -0
  63. package/src/{dev/plugins → plugins}/toolbar/client/util/animation.js +0 -0
  64. package/src/{dev/plugins → plugins}/toolbar/client/util/dom.js +0 -0
  65. package/src/{dev/plugins → plugins}/toolbar/client/util/fetch_using_xhr.js +0 -0
  66. package/src/{dev/plugins → plugins}/toolbar/client/util/fetching.js +0 -0
  67. package/src/{dev/plugins → plugins}/toolbar/client/util/iframe_to_parent_href.js +0 -0
  68. package/src/{dev/plugins → plugins}/toolbar/client/util/jsenv_logger.js +0 -0
  69. package/src/{dev/plugins → plugins}/toolbar/client/util/preferences.js +0 -0
  70. package/src/{dev/plugins → plugins}/toolbar/client/util/responsive.js +0 -0
  71. package/src/{dev/plugins → plugins}/toolbar/client/util/util.js +0 -0
  72. package/src/{dev/plugins → plugins}/toolbar/client/variant/variant.js +0 -0
  73. package/src/{dev/plugins → plugins}/toolbar/jsenv_plugin_toolbar.js +0 -0
  74. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +4 -3
  75. package/src/plugins/transpilation/babel/new_stylesheet/client/new_stylesheet.js +25 -55
  76. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +44 -24
  77. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +6 -1
  78. package/src/plugins/url_analysis/html/html_urls.js +8 -8
  79. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +3 -1
  80. package/src/test/execute_plan.js +36 -54
  81. package/src/test/execute_test_plan.js +2 -2
  82. package/src/test/logs_file_execution.js +60 -27
  83. package/src/test/logs_file_execution.test.mjs +41 -0
  84. package/dist/js/event_source_client.js +0 -528
  85. package/src/helpers/event_source/sse_service.js +0 -53
  86. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
  87. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -203
  88. package/src/plugins/html_supervisor/client/error_in_document.js +0 -198
@@ -1,4 +1,5 @@
1
1
  import { createDetailedMessage } from "@jsenv/log"
2
+ import { stringifyUrlSite } from "@jsenv/urls"
2
3
 
3
4
  export const createResolveUrlError = ({
4
5
  pluginController,
@@ -15,7 +16,7 @@ export const createResolveUrlError = ({
15
16
  reason,
16
17
  ...details,
17
18
  "specifier": `"${reference.specifier}"`,
18
- "specifier trace": reference.trace,
19
+ "specifier trace": reference.trace.message,
19
20
  ...detailsFromPluginController(pluginController),
20
21
  }),
21
22
  )
@@ -46,19 +47,24 @@ export const createFetchUrlContentError = ({
46
47
  reason,
47
48
  ...details
48
49
  }) => {
49
- const fetchContentError = new Error(
50
+ const fetchError = new Error(
50
51
  createDetailedMessage(`Failed to fetch url content`, {
51
52
  reason,
52
53
  ...details,
53
54
  "url": urlInfo.url,
54
- "url reference trace": reference.trace,
55
+ "url reference trace": reference.trace.message,
55
56
  ...detailsFromPluginController(pluginController),
56
57
  }),
57
58
  )
58
- fetchContentError.name = "FETCH_URL_CONTENT_ERROR"
59
- fetchContentError.code = code
60
- fetchContentError.reason = reason
61
- return fetchContentError
59
+ fetchError.name = "FETCH_URL_CONTENT_ERROR"
60
+ fetchError.code = code
61
+ fetchError.reason = reason
62
+ fetchError.url = urlInfo.url
63
+ fetchError.traceUrl = reference.trace.url
64
+ fetchError.traceLine = reference.trace.line
65
+ fetchError.traceColumn = reference.trace.column
66
+ fetchError.traceMessage = reference.trace.message
67
+ return fetchError
62
68
  }
63
69
 
64
70
  if (error.code === "EPERM") {
@@ -103,7 +109,7 @@ export const createTransformUrlContentError = ({
103
109
  reason,
104
110
  ...details,
105
111
  "url": urlInfo.url,
106
- "url reference trace": reference.trace,
112
+ "url reference trace": reference.trace.message,
107
113
  ...detailsFromPluginController(pluginController),
108
114
  },
109
115
  ),
@@ -111,6 +117,34 @@ export const createTransformUrlContentError = ({
111
117
  transformError.name = "TRANSFORM_URL_CONTENT_ERROR"
112
118
  transformError.code = code
113
119
  transformError.reason = reason
120
+ transformError.stack = error.stack
121
+ transformError.url = urlInfo.url
122
+ transformError.traceUrl = reference.trace.url
123
+ transformError.traceLine = reference.trace.line
124
+ transformError.traceColumn = reference.trace.column
125
+ transformError.traceMessage = reference.trace.message
126
+ if (code === "PARSE_ERROR") {
127
+ transformError.reason = error.message
128
+ if (urlInfo.isInline) {
129
+ transformError.traceLine = reference.trace.line + error.line - 1
130
+ transformError.traceColumn = reference.trace.column + error.column
131
+ transformError.traceMessage = stringifyUrlSite({
132
+ url: urlInfo.inlineUrlSite.url,
133
+ line: transformError.traceLine,
134
+ column: transformError.traceColumn,
135
+ content: urlInfo.inlineUrlSite.content,
136
+ })
137
+ } else {
138
+ transformError.traceLine = error.line
139
+ transformError.traceColumn = error.column
140
+ transformError.traceMessage = stringifyUrlSite({
141
+ url: urlInfo.url,
142
+ line: error.line - 1,
143
+ column: error.column,
144
+ content: urlInfo.content,
145
+ })
146
+ }
147
+ }
114
148
  return transformError
115
149
  }
116
150
  return createFailedToTransformError({
@@ -130,7 +164,7 @@ export const createFinalizeUrlContentError = ({
130
164
  "reason": `An error occured during "finalizeUrlContent"`,
131
165
  ...detailsFromValueThrown(error),
132
166
  "url": urlInfo.url,
133
- "url reference trace": reference.trace,
167
+ "url reference trace": reference.trace.message,
134
168
  ...detailsFromPluginController(pluginController),
135
169
  }),
136
170
  )
@@ -7,7 +7,7 @@ import {
7
7
  setUrlFilename,
8
8
  } from "@jsenv/urls"
9
9
  import { writeFileSync, ensureWindowsDriveLetter } from "@jsenv/filesystem"
10
- import { createDetailedMessage } from "@jsenv/log"
10
+ import { createLogger, createDetailedMessage } from "@jsenv/log"
11
11
  import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js"
12
12
 
13
13
  import { createPluginController } from "../plugins/plugin_controller.js"
@@ -25,12 +25,13 @@ import { isWebWorkerEntryPointReference } from "./web_workers.js"
25
25
 
26
26
  export const createKitchen = ({
27
27
  signal,
28
- logger,
28
+ logLevel,
29
+
29
30
  rootDirectoryUrl,
31
+ scenario,
32
+ runtimeCompat,
30
33
  urlGraph,
31
-
32
34
  plugins,
33
- scenario,
34
35
  sourcemaps = {
35
36
  dev: "inline", // "programmatic" and "file" also allowed
36
37
  test: "inline",
@@ -44,9 +45,9 @@ export const createKitchen = ({
44
45
  build: true,
45
46
  }[scenario],
46
47
  sourcemapsRelativeSources,
47
- runtimeCompat,
48
48
  writeGeneratedFiles,
49
49
  }) => {
50
+ const logger = createLogger({ logLevel })
50
51
  const pluginController = createPluginController({
51
52
  plugins,
52
53
  scenario,
@@ -56,13 +57,13 @@ export const createKitchen = ({
56
57
  signal,
57
58
  logger,
58
59
  rootDirectoryUrl,
59
- sourcemaps,
60
60
  urlGraph,
61
61
  scenario,
62
62
  runtimeCompat,
63
63
  isSupportedOnFutureClients: (feature) => {
64
64
  return RUNTIME_COMPAT.isSupported(runtimeCompat, feature)
65
65
  },
66
+ sourcemaps,
66
67
  }
67
68
  pluginController.callHooks("init", kitchenContext)
68
69
  const createReference = ({
@@ -221,7 +222,10 @@ export const createKitchen = ({
221
222
  sourcemapsRelativeSources,
222
223
  injectSourcemapPlaceholder: ({ urlInfo, specifier }) => {
223
224
  const sourcemapReference = createReference({
224
- trace: `sourcemap comment placeholder for ${urlInfo.url}`,
225
+ trace: {
226
+ message: `sourcemap comment placeholder`,
227
+ url: urlInfo.url,
228
+ },
225
229
  type: "sourcemap_comment",
226
230
  subtype: urlInfo.contentType === "text/javascript" ? "js" : "css",
227
231
  parentUrl: urlInfo.url,
@@ -238,15 +242,14 @@ export const createKitchen = ({
238
242
  specifierLine,
239
243
  specifierColumn,
240
244
  }) => {
245
+ const sourcemapUrlSite = adjustUrlSite(urlInfo, {
246
+ urlGraph,
247
+ url: urlInfo.url,
248
+ line: specifierLine,
249
+ column: specifierColumn,
250
+ })
241
251
  const sourcemapReference = createReference({
242
- trace: stringifyUrlSite(
243
- adjustUrlSite(urlInfo, {
244
- urlGraph,
245
- url: urlInfo.url,
246
- line: specifierLine,
247
- column: specifierColumn,
248
- }),
249
- ),
252
+ trace: traceFromUrlSite(sourcemapUrlSite),
250
253
  type,
251
254
  parentUrl: urlInfo.url,
252
255
  specifier,
@@ -273,7 +276,7 @@ export const createKitchen = ({
273
276
  `no plugin has handled url during "fetchUrlContent" hook -> url will be ignored`,
274
277
  {
275
278
  "url": urlInfo.url,
276
- "url reference trace": reference.trace,
279
+ "url reference trace": reference.trace.message,
277
280
  },
278
281
  ),
279
282
  )
@@ -408,7 +411,7 @@ export const createKitchen = ({
408
411
  },
409
412
  found: ({ trace, ...rest }) => {
410
413
  if (trace === undefined) {
411
- trace = stringifyUrlSite(
414
+ trace = traceFromUrlSite(
412
415
  adjustUrlSite(urlInfo, {
413
416
  urlGraph,
414
417
  url: urlInfo.url,
@@ -423,7 +426,12 @@ export const createKitchen = ({
423
426
  ...rest,
424
427
  })
425
428
  },
426
- foundInline: ({ isOriginalPosition, line, column, ...rest }) => {
429
+ foundInline: ({
430
+ isOriginalPosition,
431
+ specifierLine,
432
+ specifierColumn,
433
+ ...rest
434
+ }) => {
427
435
  const parentUrl = isOriginalPosition
428
436
  ? urlInfo.url
429
437
  : urlInfo.generatedUrl
@@ -431,15 +439,15 @@ export const createKitchen = ({
431
439
  ? urlInfo.originalContent
432
440
  : urlInfo.content
433
441
  return addReference({
434
- trace: stringifyUrlSite({
442
+ trace: traceFromUrlSite({
435
443
  url: parentUrl,
436
444
  content: parentContent,
437
- line,
438
- column,
445
+ line: specifierLine,
446
+ column: specifierColumn,
439
447
  }),
440
448
  isOriginalPosition,
441
- line,
442
- column,
449
+ specifierLine,
450
+ specifierColumn,
443
451
  isInline: true,
444
452
  ...rest,
445
453
  })
@@ -487,7 +495,7 @@ export const createKitchen = ({
487
495
  ? urlInfo.originalContent
488
496
  : urlInfo.content
489
497
  return referenceUtils.update(reference, {
490
- trace: stringifyUrlSite({
498
+ trace: traceFromUrlSite({
491
499
  url: parentUrl,
492
500
  content: parentContent,
493
501
  line: specifierLine,
@@ -505,7 +513,7 @@ export const createKitchen = ({
505
513
  inject: ({ trace, ...rest }) => {
506
514
  if (trace === undefined) {
507
515
  const { url, line, column } = getCallerPosition()
508
- trace = stringifyUrlSite({
516
+ trace = traceFromUrlSite({
509
517
  url,
510
518
  line,
511
519
  column,
@@ -722,6 +730,15 @@ const memoizeCook = (cook) => {
722
730
  }
723
731
  }
724
732
 
733
+ const traceFromUrlSite = (urlSite) => {
734
+ return {
735
+ message: stringifyUrlSite(urlSite),
736
+ url: urlSite.url,
737
+ line: urlSite.line,
738
+ column: urlSite.column,
739
+ }
740
+ }
741
+
725
742
  const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
726
743
  if (reference.shouldHandle) {
727
744
  urlInfo.shouldHandle = true
@@ -1,13 +1,10 @@
1
1
  import {
2
2
  jsenvAccessControlAllowedHeaders,
3
3
  startServer,
4
- composeServices,
5
- pluginServerTiming,
6
- pluginRequestWaitingCheck,
7
- pluginCORS,
4
+ jsenvServiceCORS,
5
+ jsenvServiceErrorHandler,
8
6
  } from "@jsenv/server"
9
7
  import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js"
10
- import { createCallbackListNotifiedOnce } from "@jsenv/abort"
11
8
 
12
9
  import { createFileService } from "./server/file_service.js"
13
10
 
@@ -19,28 +16,31 @@ export const startOmegaServer = async ({
19
16
  http2 = protocol === "https",
20
17
  privateKey,
21
18
  certificate,
22
- listenAnyIp,
23
- ip,
19
+ acceptAnyIp,
20
+ host,
24
21
  port = 0,
25
22
  keepProcessAlive = false,
26
23
  onStop = () => {},
27
- serverPlugins,
28
- services,
24
+ services = [],
29
25
 
30
26
  rootDirectoryUrl,
31
27
  scenario,
32
- urlGraph,
33
- kitchen,
28
+ runtimeCompat,
29
+
30
+ plugins,
31
+ urlAnalysis,
32
+ htmlSupervisor,
33
+ nodeEsmResolution,
34
+ fileSystemMagicResolution,
35
+ transpilation,
36
+ clientAutoreload,
37
+ clientFiles,
38
+ cooldownBetweenFileEvents,
39
+ explorer,
40
+ sourcemaps,
41
+ writeGeneratedFiles,
34
42
  }) => {
35
- const serverStopCallbackList = createCallbackListNotifiedOnce()
36
- const coreServices = {
37
- "service:file": createFileService({
38
- rootDirectoryUrl,
39
- urlGraph,
40
- kitchen,
41
- scenario,
42
- }),
43
- }
43
+ const serverStopCallbacks = []
44
44
  const server = await startServer({
45
45
  signal,
46
46
  stopOnExit: false,
@@ -54,12 +54,12 @@ export const startOmegaServer = async ({
54
54
  http2,
55
55
  certificate,
56
56
  privateKey,
57
- listenAnyIp,
58
- ip,
57
+ acceptAnyIp,
58
+ host,
59
59
  port,
60
- plugins: {
61
- ...serverPlugins,
62
- ...pluginCORS({
60
+ requestWaitingMs: 60_1000,
61
+ services: [
62
+ jsenvServiceCORS({
63
63
  accessControlAllowRequestOrigin: true,
64
64
  accessControlAllowRequestMethod: true,
65
65
  accessControlAllowRequestHeaders: true,
@@ -68,61 +68,83 @@ export const startOmegaServer = async ({
68
68
  "x-jsenv-execution-id",
69
69
  ],
70
70
  accessControlAllowCredentials: true,
71
+ timingAllowOrigin: true,
71
72
  }),
72
- ...pluginServerTiming(),
73
- ...pluginRequestWaitingCheck({
74
- requestWaitingMs: 60 * 1000,
75
- }),
76
- },
77
- sendErrorDetails: true,
78
- errorToResponse: (error, { request }) => {
79
- const getResponseForError = () => {
80
- if (error && error.asResponse) {
81
- return error.asResponse()
82
- }
83
- if (error && error.statusText === "Unexpected directory operation") {
73
+ ...services,
74
+ {
75
+ name: "jsenv:omega_file_service",
76
+ handleRequest: createFileService({
77
+ signal,
78
+ logLevel,
79
+ serverStopCallbacks,
80
+
81
+ rootDirectoryUrl,
82
+ scenario,
83
+ runtimeCompat,
84
+
85
+ plugins,
86
+ urlAnalysis,
87
+ htmlSupervisor,
88
+ nodeEsmResolution,
89
+ fileSystemMagicResolution,
90
+ transpilation,
91
+ clientAutoreload,
92
+ clientFiles,
93
+ cooldownBetweenFileEvents,
94
+ explorer,
95
+ sourcemaps,
96
+ writeGeneratedFiles,
97
+ }),
98
+ },
99
+ {
100
+ name: "jsenv:omega_error_handler",
101
+ handleError: (error) => {
102
+ const getResponseForError = () => {
103
+ if (error && error.asResponse) {
104
+ return error.asResponse()
105
+ }
106
+ if (
107
+ error &&
108
+ error.statusText === "Unexpected directory operation"
109
+ ) {
110
+ return {
111
+ status: 403,
112
+ }
113
+ }
114
+ return convertFileSystemErrorToResponseProperties(error)
115
+ }
116
+ const response = getResponseForError()
117
+ if (!response) {
118
+ return null
119
+ }
120
+ const body = JSON.stringify({
121
+ status: response.status,
122
+ statusText: response.statusText,
123
+ headers: response.headers,
124
+ body: response.body,
125
+ })
84
126
  return {
85
- status: 403,
127
+ status: 200,
128
+ headers: {
129
+ "content-type": "application/json",
130
+ "content-length": Buffer.byteLength(body),
131
+ },
132
+ body,
86
133
  }
87
- }
88
- return convertFileSystemErrorToResponseProperties(error)
89
- }
90
- const response = getResponseForError()
91
- if (!response) {
92
- return null
93
- }
94
- const isInspectRequest = new URL(
95
- request.ressource,
96
- request.origin,
97
- ).searchParams.has("__inspect__")
98
- if (!isInspectRequest) {
99
- return response
100
- }
101
- const body = JSON.stringify({
102
- status: response.status,
103
- statusText: response.statusText,
104
- headers: response.headers,
105
- body: response.body,
106
- })
107
- return {
108
- status: 200,
109
- headers: {
110
- "content-type": "application/json",
111
- "content-length": Buffer.byteLength(body),
112
134
  },
113
- body,
114
- }
115
- },
116
- requestToResponse: composeServices({
117
- ...services,
118
- ...coreServices,
119
- }),
135
+ },
136
+ // default error handling
137
+ jsenvServiceErrorHandler({
138
+ sendErrorDetails: true,
139
+ }),
140
+ ],
120
141
  onStop: (reason) => {
121
142
  onStop()
122
- serverStopCallbackList.notify(reason)
143
+ serverStopCallbacks.forEach((serverStopCallback) => {
144
+ serverStopCallback(reason)
145
+ })
146
+ serverStopCallbacks.length = 0
123
147
  },
124
148
  })
125
- return {
126
- ...server,
127
- }
149
+ return server
128
150
  }