@jsenv/core 27.4.0 → 27.5.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 (84) 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 +221 -73
  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 +7483 -7281
  8. package/package.json +11 -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 +30 -94
  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_in_document.js → error_overlay.js} +73 -17
  30. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +127 -54
  31. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
  32. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +19 -12
  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 -8
  37. package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +102 -31
  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/test/execute_plan.js +36 -54
  80. package/src/test/execute_test_plan.js +2 -2
  81. package/dist/js/event_source_client.js +0 -549
  82. package/src/helpers/event_source/sse_service.js +0 -53
  83. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
  84. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -192
@@ -1,18 +1,11 @@
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 {
11
- createCallbackListNotifiedOnce,
12
- createCallbackList,
13
- } from "@jsenv/abort"
14
8
 
15
- import { createSSEService } from "@jsenv/core/src/helpers/event_source/sse_service.js"
16
9
  import { createFileService } from "./server/file_service.js"
17
10
 
18
11
  export const startOmegaServer = async ({
@@ -23,76 +16,31 @@ export const startOmegaServer = async ({
23
16
  http2 = protocol === "https",
24
17
  privateKey,
25
18
  certificate,
26
- listenAnyIp,
27
- ip,
19
+ acceptAnyIp,
20
+ host,
28
21
  port = 0,
29
22
  keepProcessAlive = false,
30
23
  onStop = () => {},
31
- serverPlugins,
32
- services,
24
+ services = [],
33
25
 
34
26
  rootDirectoryUrl,
35
27
  scenario,
36
- urlGraph,
37
- kitchen,
38
- }) => {
39
- const serverStopCallbackList = createCallbackListNotifiedOnce()
28
+ runtimeCompat,
40
29
 
41
- const serverEventCallbackList = createCallbackList()
42
- const sseService = createSSEService({ serverEventCallbackList })
43
- const sendServerEvent = ({ type, data }) => {
44
- serverEventCallbackList.notify({
45
- type,
46
- data: JSON.stringify(data),
47
- })
48
- }
49
-
50
- kitchen.pluginController.addHook("registerServerEvents")
51
- kitchen.pluginController.callHooks(
52
- "registerServerEvents",
53
- { sendServerEvent },
54
- {
55
- rootDirectoryUrl,
56
- urlGraph,
57
- scenario,
58
- },
59
- () => {},
60
- )
61
-
62
- const sendServerErrorEvent = (event) => {
63
- // setTimeout display first the error
64
- // dispatched on window by browser
65
- // then display the jsenv error
66
- setTimeout(() => {
67
- sendServerEvent(event)
68
- }, 10)
69
- }
70
-
71
- const coreServices = {
72
- "service:server_events": (request) => {
73
- const { accept } = request.headers
74
- if (accept && accept.includes("text/event-stream")) {
75
- const room = sseService.getOrCreateSSERoom(request)
76
- return room.join(request)
77
- }
78
- return null
79
- },
80
- "service:file": createFileService({
81
- rootDirectoryUrl,
82
- urlGraph,
83
- kitchen,
84
- scenario,
85
- onFileNotFound: (data) => {
86
- sendServerErrorEvent({ type: "file_not_found", data })
87
- },
88
- onParseError: (data) => {
89
- sendServerErrorEvent({ type: "parse_error", data })
90
- },
91
- onUnexpectedError: (data) => {
92
- sendServerErrorEvent({ type: "unexpected_error", data })
93
- },
94
- }),
95
- }
30
+ plugins,
31
+ urlAnalysis,
32
+ htmlSupervisor,
33
+ nodeEsmResolution,
34
+ fileSystemMagicResolution,
35
+ transpilation,
36
+ clientAutoreload,
37
+ clientFiles,
38
+ cooldownBetweenFileEvents,
39
+ explorer,
40
+ sourcemaps,
41
+ writeGeneratedFiles,
42
+ }) => {
43
+ const serverStopCallbacks = []
96
44
  const server = await startServer({
97
45
  signal,
98
46
  stopOnExit: false,
@@ -106,12 +54,12 @@ export const startOmegaServer = async ({
106
54
  http2,
107
55
  certificate,
108
56
  privateKey,
109
- listenAnyIp,
110
- ip,
57
+ acceptAnyIp,
58
+ host,
111
59
  port,
112
- plugins: {
113
- ...serverPlugins,
114
- ...pluginCORS({
60
+ requestWaitingMs: 60_1000,
61
+ services: [
62
+ jsenvServiceCORS({
115
63
  accessControlAllowRequestOrigin: true,
116
64
  accessControlAllowRequestMethod: true,
117
65
  accessControlAllowRequestHeaders: true,
@@ -120,62 +68,83 @@ export const startOmegaServer = async ({
120
68
  "x-jsenv-execution-id",
121
69
  ],
122
70
  accessControlAllowCredentials: true,
71
+ timingAllowOrigin: true,
123
72
  }),
124
- ...pluginServerTiming(),
125
- ...pluginRequestWaitingCheck({
126
- requestWaitingMs: 60 * 1000,
127
- }),
128
- },
129
- sendErrorDetails: true,
130
- errorToResponse: (error, { request }) => {
131
- const getResponseForError = () => {
132
- if (error && error.asResponse) {
133
- return error.asResponse()
134
- }
135
- 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
+ })
136
126
  return {
137
- status: 403,
127
+ status: 200,
128
+ headers: {
129
+ "content-type": "application/json",
130
+ "content-length": Buffer.byteLength(body),
131
+ },
132
+ body,
138
133
  }
139
- }
140
- return convertFileSystemErrorToResponseProperties(error)
141
- }
142
- const response = getResponseForError()
143
- if (!response) {
144
- return null
145
- }
146
- const isInspectRequest = new URL(
147
- request.ressource,
148
- request.origin,
149
- ).searchParams.has("__inspect__")
150
- if (!isInspectRequest) {
151
- return response
152
- }
153
- const body = JSON.stringify({
154
- status: response.status,
155
- statusText: response.statusText,
156
- headers: response.headers,
157
- body: response.body,
158
- })
159
- return {
160
- status: 200,
161
- headers: {
162
- "content-type": "application/json",
163
- "content-length": Buffer.byteLength(body),
164
134
  },
165
- body,
166
- }
167
- },
168
- requestToResponse: composeServices({
169
- ...services,
170
- ...coreServices,
171
- }),
135
+ },
136
+ // default error handling
137
+ jsenvServiceErrorHandler({
138
+ sendErrorDetails: true,
139
+ }),
140
+ ],
172
141
  onStop: (reason) => {
173
142
  onStop()
174
- sseService.destroy()
175
- serverStopCallbackList.notify(reason)
143
+ serverStopCallbacks.forEach((serverStopCallback) => {
144
+ serverStopCallback(reason)
145
+ })
146
+ serverStopCallbacks.length = 0
176
147
  },
177
148
  })
178
- return {
179
- ...server,
180
- }
149
+ return server
181
150
  }
@@ -3,46 +3,242 @@ import {
3
3
  serveDirectory,
4
4
  composeTwoResponses,
5
5
  } from "@jsenv/server"
6
+ import { registerDirectoryLifecycle } from "@jsenv/filesystem"
6
7
  import { urlIsInsideOf, moveUrl } from "@jsenv/urls"
8
+ import { URL_META } from "@jsenv/url-meta"
7
9
 
10
+ import { getCorePlugins } from "@jsenv/core/src/plugins/plugins.js"
11
+ import { createUrlGraph } from "@jsenv/core/src/omega/url_graph.js"
12
+ import { createKitchen } from "@jsenv/core/src/omega/kitchen.js"
13
+ import { createServerEventsDispatcher } from "@jsenv/core/src/plugins/server_events/server_events_dispatcher.js"
14
+ import { jsenvPluginServerEventsClientInjection } from "@jsenv/core/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js"
8
15
  import { parseUserAgentHeader } from "./user_agent.js"
9
16
 
10
17
  export const createFileService = ({
18
+ signal,
19
+ logLevel,
20
+ serverStopCallbacks,
21
+
11
22
  rootDirectoryUrl,
12
- urlGraph,
13
- kitchen,
14
23
  scenario,
15
- onParseError,
16
- onFileNotFound,
17
- onUnexpectedError,
24
+ runtimeCompat,
25
+
26
+ plugins,
27
+ urlAnalysis,
28
+ htmlSupervisor,
29
+ nodeEsmResolution,
30
+ fileSystemMagicResolution,
31
+ transpilation,
32
+ clientAutoreload,
33
+ clientFiles,
34
+ cooldownBetweenFileEvents,
35
+ explorer,
36
+ sourcemaps,
37
+ writeGeneratedFiles,
18
38
  }) => {
19
- kitchen.pluginController.addHook("serve")
20
- kitchen.pluginController.addHook("augmentResponse")
21
- const serveContext = {
22
- rootDirectoryUrl,
23
- urlGraph,
24
- scenario,
39
+ const jsenvDirectoryUrl = new URL(".jsenv/", rootDirectoryUrl).href
40
+ const onErrorWhileServingFileCallbacks = []
41
+ const onErrorWhileServingFile = (data) => {
42
+ onErrorWhileServingFileCallbacks.forEach(
43
+ (onErrorWhileServingFileCallback) => {
44
+ onErrorWhileServingFileCallback(data)
45
+ },
46
+ )
47
+ }
48
+
49
+ const clientFileChangeCallbackList = []
50
+ const clientFilesPruneCallbackList = []
51
+ const clientFileChangeCallback = ({ relativeUrl, event }) => {
52
+ const url = new URL(relativeUrl, rootDirectoryUrl).href
53
+ clientFileChangeCallbackList.forEach((callback) => {
54
+ callback({ url, event })
55
+ })
25
56
  }
26
- const augmentResponseContext = {
27
- rootDirectoryUrl,
28
- urlGraph,
29
- scenario,
57
+ const clientFilePatterns = {
58
+ ...clientFiles,
59
+ ".jsenv/": false,
60
+ }
61
+
62
+ if (scenario === "dev") {
63
+ const stopWatchingClientFiles = registerDirectoryLifecycle(
64
+ rootDirectoryUrl,
65
+ {
66
+ watchPatterns: clientFilePatterns,
67
+ cooldownBetweenFileEvents,
68
+ keepProcessAlive: false,
69
+ recursive: true,
70
+ added: ({ relativeUrl }) => {
71
+ clientFileChangeCallback({ event: "added", relativeUrl })
72
+ },
73
+ updated: ({ relativeUrl }) => {
74
+ clientFileChangeCallback({ event: "modified", relativeUrl })
75
+ },
76
+ removed: ({ relativeUrl }) => {
77
+ clientFileChangeCallback({ event: "removed", relativeUrl })
78
+ },
79
+ },
80
+ )
81
+ serverStopCallbacks.push(stopWatchingClientFiles)
30
82
  }
31
83
 
32
- const getResponse = async (request) => {
84
+ const contextCache = new Map()
85
+ const getOrCreateContext = (request) => {
86
+ const { runtimeName, runtimeVersion } = parseUserAgentHeader(
87
+ request.headers["user-agent"],
88
+ )
89
+ const runtimeId = `${runtimeName}@${runtimeVersion}`
90
+ const existingContext = contextCache.get(runtimeId)
91
+ if (existingContext) {
92
+ return existingContext
93
+ }
94
+ const watchAssociations = URL_META.resolveAssociations(
95
+ { watch: clientFilePatterns },
96
+ rootDirectoryUrl,
97
+ )
98
+ const urlGraph = createUrlGraph({
99
+ clientFileChangeCallbackList,
100
+ clientFilesPruneCallbackList,
101
+ onCreateUrlInfo: (urlInfo) => {
102
+ const { watch } = URL_META.applyAssociations({
103
+ url: urlInfo.url,
104
+ associations: watchAssociations,
105
+ })
106
+ urlInfo.isValid = () => watch
107
+ },
108
+ includeOriginalUrls: scenario === "dev",
109
+ })
110
+ const kitchen = createKitchen({
111
+ signal,
112
+ logLevel,
113
+ rootDirectoryUrl,
114
+ scenario,
115
+ runtimeCompat,
116
+ urlGraph,
117
+ plugins: [
118
+ ...plugins,
119
+ ...getCorePlugins({
120
+ rootDirectoryUrl,
121
+ scenario,
122
+ runtimeCompat,
123
+
124
+ urlAnalysis,
125
+ htmlSupervisor,
126
+ nodeEsmResolution,
127
+ fileSystemMagicResolution,
128
+ transpilation,
129
+
130
+ clientAutoreload,
131
+ clientFileChangeCallbackList,
132
+ clientFilesPruneCallbackList,
133
+ explorer,
134
+ }),
135
+ ],
136
+ sourcemaps,
137
+ writeGeneratedFiles,
138
+ })
139
+ serverStopCallbacks.push(() => {
140
+ kitchen.pluginController.callHooks("destroy", kitchen.kitchenContext)
141
+ })
142
+ server_events: {
143
+ const allServerEvents = {}
144
+ kitchen.pluginController.plugins.forEach((plugin) => {
145
+ const { serverEvents } = plugin
146
+ if (serverEvents) {
147
+ Object.keys(serverEvents).forEach((serverEventName) => {
148
+ // we could throw on serverEvent name conflict
149
+ // we could throw if serverEvents[serverEventName] is not a function
150
+ allServerEvents[serverEventName] = serverEvents[serverEventName]
151
+ })
152
+ }
153
+ })
154
+ const serverEventNames = Object.keys(allServerEvents)
155
+ if (serverEventNames.length > 0) {
156
+ const serverEventsDispatcher = createServerEventsDispatcher()
157
+ serverStopCallbacks.push(() => {
158
+ serverEventsDispatcher.destroy()
159
+ })
160
+ Object.keys(allServerEvents).forEach((serverEventName) => {
161
+ allServerEvents[serverEventName]({
162
+ rootDirectoryUrl,
163
+ urlGraph,
164
+ scenario,
165
+ sendServerEvent: (data) => {
166
+ serverEventsDispatcher.dispatch({
167
+ type: serverEventName,
168
+ data,
169
+ })
170
+ },
171
+ })
172
+ })
173
+ onErrorWhileServingFileCallbacks.push((data) => {
174
+ serverEventsDispatcher.dispatchToRoomsMatching(
175
+ {
176
+ type: "error_while_serving_file",
177
+ data,
178
+ },
179
+ (room) => {
180
+ // send only to page depending on this file
181
+ const errorFileUrl = data.url
182
+ const roomEntryPointUrl = new URL(
183
+ room.request.ressource.slice(1),
184
+ rootDirectoryUrl,
185
+ ).href
186
+ const isErrorRelatedToEntryPoint = Boolean(
187
+ urlGraph.findDependent(errorFileUrl, (dependentUrlInfo) => {
188
+ return dependentUrlInfo.url === roomEntryPointUrl
189
+ }),
190
+ )
191
+ return isErrorRelatedToEntryPoint
192
+ },
193
+ )
194
+ })
195
+ // "unshift" because serve must come first to catch event source client request
196
+ kitchen.pluginController.unshiftPlugin({
197
+ name: "jsenv:provide_server_events",
198
+ serve: (request) => {
199
+ const { accept } = request.headers
200
+ if (accept && accept.includes("text/event-stream")) {
201
+ const room = serverEventsDispatcher.addRoom(request)
202
+ return room.join(request)
203
+ }
204
+ return null
205
+ },
206
+ })
207
+ // "push" so that event source client connection can be put as early as possible in html
208
+ kitchen.pluginController.pushPlugin(
209
+ jsenvPluginServerEventsClientInjection(),
210
+ )
211
+ }
212
+ }
213
+
214
+ const context = {
215
+ rootDirectoryUrl,
216
+ scenario,
217
+ runtimeName,
218
+ runtimeVersion,
219
+ urlGraph,
220
+ kitchen,
221
+ }
222
+ contextCache.set(runtimeId, context)
223
+ return context
224
+ }
225
+
226
+ return async (request) => {
33
227
  // serve file inside ".jsenv" directory
34
228
  const requestFileUrl = new URL(request.ressource.slice(1), rootDirectoryUrl)
35
229
  .href
36
- if (urlIsInsideOf(requestFileUrl, kitchen.jsenvDirectoryUrl)) {
230
+ if (urlIsInsideOf(requestFileUrl, jsenvDirectoryUrl)) {
37
231
  return fetchFileSystem(requestFileUrl, {
38
232
  headers: request.headers,
39
233
  })
40
234
  }
235
+ const { runtimeName, runtimeVersion, urlGraph, kitchen } =
236
+ getOrCreateContext(request)
41
237
  const responseFromPlugin =
42
238
  await kitchen.pluginController.callAsyncHooksUntil(
43
239
  "serve",
44
240
  request,
45
- serveContext,
241
+ kitchen.kitchenContext,
46
242
  )
47
243
  if (responseFromPlugin) {
48
244
  return responseFromPlugin
@@ -67,8 +263,12 @@ export const createFileService = ({
67
263
  if (
68
264
  ifNoneMatch &&
69
265
  urlInfo.contentEtag === ifNoneMatch &&
70
- // - isValid is true by default
71
- // - isValid can be overriden by plugins such as cjs_to_esm
266
+ // urlInfo.isValid
267
+ // - is false by default because there must be some logic capable
268
+ // to invalidate the url (otherwise server would return 304 forever)
269
+ // - is set to a function returning true if the file is watched
270
+ // in start_dev_server.js
271
+ // - is set to a custom function by cjs_to_esm in compiled_file_cache.js
72
272
  urlInfo.isValid()
73
273
  ) {
74
274
  return {
@@ -95,9 +295,6 @@ export const createFileService = ({
95
295
  urlInfo.dependsOnPackageJson = false
96
296
  urlInfo.timing = {}
97
297
  }
98
- const { runtimeName, runtimeVersion } = parseUserAgentHeader(
99
- request.headers["user-agent"],
100
- )
101
298
  await kitchen.cook(urlInfo, {
102
299
  request,
103
300
  reference,
@@ -129,7 +326,7 @@ export const createFileService = ({
129
326
  kitchen.pluginController.callHooks(
130
327
  "augmentResponse",
131
328
  { reference, urlInfo },
132
- augmentResponseContext,
329
+ kitchen.kitchenContext,
133
330
  (returnValue) => {
134
331
  response = composeTwoResponses(response, returnValue)
135
332
  },
@@ -138,13 +335,15 @@ export const createFileService = ({
138
335
  } catch (e) {
139
336
  const code = e.code
140
337
  if (code === "PARSE_ERROR") {
141
- onParseError({
142
- reason: e.reason,
143
- message: e.message,
338
+ onErrorWhileServingFile({
339
+ requestedRessource: request.ressource,
340
+ code: "PARSE_ERROR",
341
+ message: e.reason,
144
342
  url: e.url,
145
- line: e.line,
146
- column: e.column,
147
- contentFrame: e.contentFrame,
343
+ traceUrl: e.traceUrl,
344
+ traceLine: e.traceLine,
345
+ traceColumn: e.traceColumn,
346
+ traceMessage: e.traceMessage,
148
347
  })
149
348
  return {
150
349
  url: reference.url,
@@ -176,13 +375,18 @@ export const createFileService = ({
176
375
  }
177
376
  }
178
377
  if (code === "NOT_FOUND") {
179
- onFileNotFound({
180
- reason: e.reason,
181
- message: e.message,
378
+ onErrorWhileServingFile({
379
+ requestedRessource: request.ressource,
380
+ isFaviconAutoRequest:
381
+ request.ressource === "/favicon.ico" &&
382
+ reference.type === "http_request",
383
+ code: "NOT_FOUND",
384
+ message: e.reason,
182
385
  url: e.url,
183
- line: e.line,
184
- column: e.column,
185
- contentFrame: e.contentFrame,
386
+ traceUrl: e.traceUrl,
387
+ traceLine: e.traceLine,
388
+ traceColumn: e.traceColumn,
389
+ traceMessage: e.traceMessage,
186
390
  })
187
391
  return {
188
392
  url: reference.url,
@@ -191,14 +395,15 @@ export const createFileService = ({
191
395
  statusMessage: e.message,
192
396
  }
193
397
  }
194
- onUnexpectedError({
195
- reason: e.reason,
196
- message: e.message,
398
+ onErrorWhileServingFile({
399
+ requestedRessource: request.ressource,
400
+ code: "UNEXPECTED",
197
401
  stack: e.stack,
198
402
  url: e.url,
199
- line: e.line,
200
- column: e.column,
201
- contentFrame: e.contentFrame,
403
+ traceUrl: e.traceUrl,
404
+ traceLine: e.traceLine,
405
+ traceColumn: e.traceColumn,
406
+ traceMessage: e.traceMessage,
202
407
  })
203
408
  return {
204
409
  url: reference.url,
@@ -208,10 +413,6 @@ export const createFileService = ({
208
413
  }
209
414
  }
210
415
  }
211
- return async (request) => {
212
- let response = await getResponse(request)
213
- return response
214
- }
215
416
  }
216
417
 
217
418
  const inferParentFromRequest = (request, rootDirectoryUrl) => {