mockaton 11.0.0 → 11.0.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.
package/Makefile CHANGED
@@ -6,23 +6,23 @@ watch:
6
6
 
7
7
 
8
8
  test:
9
- node --test 'src/**/*.test.js'
9
+ @MOCKATON_WATCHER_DEBOUNCE_MS=0 node --test 'src/**/*.test.js'
10
10
 
11
11
  test-docker:
12
- docker run --rm -it \
13
- -v "$$PWD":/app \
14
- -w /app \
12
+ @docker run --rm --interactive --tty \
13
+ --volume .:/app \
14
+ --workdir /app \
15
15
  node:24 \
16
16
  make test
17
17
 
18
18
  coverage:
19
- node --test --experimental-test-coverage \
19
+ @MOCKATON_WATCHER_DEBOUNCE_MS=0 node --test --experimental-test-coverage \
20
20
  --test-reporter=spec --test-reporter-destination=stdout \
21
21
  --test-reporter=lcov --test-reporter-destination=lcov.info \
22
22
  'src/**/*.test.js'
23
23
 
24
24
  pixaton:
25
- node --test --experimental-test-isolation=none \
25
+ @node --test --experimental-test-isolation=none \
26
26
  --import=./pixaton-tests/_setup.js \
27
27
  'pixaton-tests/**/*.test.js'
28
28
 
package/README.md CHANGED
@@ -77,7 +77,7 @@ get saved following Mockaton’s filename convention.
77
77
 
78
78
  ### Option 2: Fallback to Your Backend
79
79
  <details>
80
- <summary>Details</summary>
80
+ <summary>Learn more…</summary>
81
81
 
82
82
  This option could be a bit elaborate if your backend uses third-party authentication,
83
83
  because you’d have to manually inject cookies or `sessionStorage` tokens.
@@ -93,7 +93,12 @@ They will be saved in your `config.mocksDir` following the filename convention.
93
93
 
94
94
  <br/>
95
95
 
96
+ <br/>
97
+
98
+
96
99
  ## Motivation
100
+ <details>
101
+ <summary>Motivation…</summary>
97
102
 
98
103
  **No API state should be too hard to test.**
99
104
  With Mockaton, developers can achieve correctness and speed.
@@ -116,27 +121,54 @@ With Mockaton, developers can achieve correctness and speed.
116
121
  - checking out long-lived branches
117
122
  - bisecting bugs
118
123
 
124
+ </details>
125
+
126
+
127
+
128
+ ## Use Cases
129
+ <details>
130
+ <summary>Use Cases…</summary>
131
+
132
+ ### Testing Backend or Frontend
133
+ - Empty responses
134
+ - Errors such as _Bad Request_ and _Internal Server Error_
135
+ - Mocking third-party APIs
136
+ - Polled resources (for triggering their different states)
137
+ - alerts
138
+ - notifications
139
+ - slow to build resources
140
+
141
+ ### Testing Frontend
142
+ - Spinners by delaying responses
143
+ - Setting up UI tests
144
+
145
+ ### Demoing complex backend states
146
+ Sometimes, the ideal flow you need is too difficult to reproduce from the actual backend.
147
+ For this, you can **Bulk Select** mocks by comments to simulate the complete states
148
+ you want. For example, by adding `(demo-part1)`, `(demo-part2)` to the filenames.
149
+
150
+ Similarly, you can deploy a **Standalone Demo Server** by compiling the frontend app and
151
+ putting its built assets in `config.staticDir`. And simulate the flow by Bulk Selecting mocks.
152
+ The [aot-fetch-demo repo](https://github.com/ericfortis/aot-fetch-demo) has a working example.
153
+
154
+ </details>
119
155
 
120
156
  <br/>
121
157
 
122
- ## Privacy and Security
123
- - Zero dependencies (no runtime and no build packages).
124
- - Does not write to disk. Except when you select ✅ **Save Mocks** for scraping mocks from a backend.
125
- - Does not initiate network connections (no logs, no telemetry).
126
- - Does not hijack your HTTP client.
127
- - Auditable. Organized and small &mdash; under 4 KLoC (half is UI and tests).
158
+
128
159
 
129
160
  <br/>
130
161
 
131
162
  ## Basic Usage
132
- 1. Install Node.js, which comes with `npm` and `npx`
163
+
164
+ 1. Install Node.js (v22.18+ support writing mocks in TypeScript)
133
165
 
134
166
  2. Create a sample mock in the default mocks directory (`./mockaton-mocks`)
135
167
  ```sh
136
168
  mkdir -p mockaton-mocks/api
137
169
  echo "[1,2,3]" > mockaton-mocks/api/foo.GET.200.json
138
170
  ```
139
- 3. Run Mockaton (`npx` installs it if needed)
171
+ 3. Run Mockaton (`npx` comes with Node, and installs Mockaton if needed)
140
172
  ```shell
141
173
  npx mockaton --port 2345
142
174
  ```
@@ -146,6 +178,16 @@ npx mockaton --port 2345
146
178
  curl localhost:2345/api/foo
147
179
  ```
148
180
 
181
+ 5. Optionally, use a `mockaton.config.js`
182
+ ```js
183
+ import { defineConfig } from 'mockaton'
184
+
185
+ export default defineConfig({
186
+ port: 2345,
187
+ })
188
+ ```
189
+
190
+
149
191
  ### Alternative Installations
150
192
  <details>
151
193
  <summary>With NPM (package.json)…</summary>
@@ -184,6 +226,9 @@ ln -s `realpath mockaton/src/cli.js` ~/bin/mockaton # some dir in your $PATH
184
226
  ## CLI Options
185
227
  The CLI options override their counterparts in `mockaton.config.js`
186
228
 
229
+ <details>
230
+ <summary>CLI Options…</summary>
231
+
187
232
  ```txt
188
233
  -c, --config <file> (default: ./mockaton.config.js)
189
234
 
@@ -199,10 +244,17 @@ The CLI options override their counterparts in `mockaton.config.js`
199
244
  -h, --help Show this help
200
245
  -v, --version Show version
201
246
  ```
247
+ </details>
202
248
 
203
249
 
204
250
  ## mockaton.config.js (Optional)
251
+ Mockaton looks for a file `mockaton.config.js` in its current working directory.
252
+
253
+ <details>
254
+ <summary>Defaults Overview… </summary>
255
+
205
256
  As an overview, these are the defaults:
257
+
206
258
  ```js
207
259
  import {
208
260
  defineConfig,
@@ -249,8 +301,10 @@ export default defineConfig({
249
301
  })
250
302
  ```
251
303
 
304
+ </details>
305
+
252
306
  <details>
253
- <summary><b>Config Documentation</b></summary>
307
+ <summary>Config Documentation…</summary>
254
308
 
255
309
  ### `mocksDir?: string`
256
310
  Defaults to `'mockaton-mocks'`.
@@ -498,7 +552,7 @@ Defaults to `'normal'`.
498
552
 
499
553
 
500
554
  <details>
501
- <summary>Programmatic Launch (Optional)</summary>
555
+ <summary>Programmatic Launch (Optional)…</summary>
502
556
 
503
557
 
504
558
  ```js
@@ -535,32 +589,6 @@ permutations for out-of-stock, new-arrival, and discontinued.
535
589
  <br/>
536
590
 
537
591
 
538
- ## Use Cases
539
- ### Testing Backend or Frontend
540
- - Empty responses
541
- - Errors such as _Bad Request_ and _Internal Server Error_
542
- - Mocking third-party APIs
543
- - Polled resources (for triggering their different states)
544
- - alerts
545
- - notifications
546
- - slow to build resources
547
-
548
- ### Testing Frontend
549
- - Spinners by delaying responses
550
- - Setting up UI tests
551
-
552
- ### Demoing complex backend states
553
- Sometimes, the ideal flow you need is too difficult to reproduce from the actual backend.
554
- For this, you can **Bulk Select** mocks by comments to simulate the complete states
555
- you want. For example, by adding `(demo-part1)`, `(demo-part2)` to the filenames.
556
-
557
- Similarly, you can deploy a **Standalone Demo Server** by compiling the frontend app and
558
- putting its built assets in `config.staticDir`. And simulate the flow by Bulk Selecting mocks.
559
- The [aot-fetch-demo repo](https://github.com/ericfortis/aot-fetch-demo) has a working example.
560
-
561
-
562
- <br/>
563
-
564
592
 
565
593
  ## You can write JSON mocks in JavaScript or TypeScript
566
594
  For example, `api/foo.GET.200.js`
@@ -840,6 +868,16 @@ await mockaton.reset()
840
868
  </details>
841
869
 
842
870
 
871
+ <br/>
872
+
873
+ ## Privacy and Security
874
+ - Zero dependencies (no runtime and no build packages).
875
+ - Does not write to disk. Except when you select ✅ **Save Mocks** for scraping mocks from a backend.
876
+ - Does not initiate network connections (no logs, no telemetry).
877
+ - Does not hijack your HTTP client.
878
+ - Auditable. Organized and small &mdash; under 4 KLoC (half is UI and tests).
879
+
880
+
843
881
  <br/>
844
882
 
845
883
  ## Alternatives worth learning as well
@@ -861,6 +899,12 @@ hijack the HTTP client in Node.js and browsers.
861
899
  - [Fetch Mock](https://github.com/wheresrhys/fetch-mock)
862
900
  - [Mentoss](https://github.com/humanwhocodes/mentoss) Has a server side too
863
901
 
902
+ ### Server Side
903
+
904
+ - [Wire Mock](https://github.com/wiremock/wiremock)
905
+ - [Mock](https://github.com/dhuan/mock)
906
+ - [Swagger](https://swagger.io/)
907
+
864
908
  <br/>
865
909
 
866
910
  ---
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "11.0.0",
5
+ "version": "11.0.2",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
@@ -23,5 +23,8 @@
23
23
  "devDependencies": {
24
24
  "pixaton": "1.1.3",
25
25
  "puppeteer": "24.24.1"
26
+ },
27
+ "engines": {
28
+ "node": ">=22.18 <23 || >=23.6"
26
29
  }
27
30
  }
package/src/Api.js CHANGED
@@ -13,7 +13,7 @@ import * as mockBrokersCollection from './mockBrokersCollection.js'
13
13
  import { config, ConfigValidator } from './config.js'
14
14
  import { DashboardHtml, CSP } from './DashboardHtml.js'
15
15
  import { sendOK, sendJSON, sendUnprocessableContent, sendFile, sendHTML } from './utils/http-response.js'
16
- import { API, LONG_POLL_SERVER_TIMEOUT, HEADER_FOR_SYNC_VERSION } from './ApiConstants.js'
16
+ import { API, LONG_POLL_SERVER_TIMEOUT, HEADER_SYNC_VERSION } from './ApiConstants.js'
17
17
 
18
18
 
19
19
  export const apiGetRequests = new Map([
@@ -81,7 +81,8 @@ function getState(_, response) {
81
81
 
82
82
 
83
83
  function longPollClientSyncVersion(req, response) {
84
- if (uiSyncVersion.version !== Number(req.headers[HEADER_FOR_SYNC_VERSION])) {
84
+ const clientVersion = req.headers[HEADER_SYNC_VERSION]
85
+ if (clientVersion !== undefined && uiSyncVersion.version !== Number(clientVersion)) {
85
86
  // e.g., tab was hidden while new mocks were added or removed
86
87
  sendJSON(response, uiSyncVersion.version)
87
88
  return
@@ -111,9 +112,9 @@ function reinitialize(_, response) {
111
112
 
112
113
 
113
114
  async function selectCookie(req, response) {
114
- const label = await parseJSON(req)
115
+ const cookieKey = await parseJSON(req)
115
116
 
116
- const error = cookie.setCurrent(label)
117
+ const error = cookie.setCurrent(cookieKey)
117
118
  if (error)
118
119
  sendUnprocessableContent(response, error?.message || error)
119
120
  else
@@ -1,4 +1,4 @@
1
- import { API, LONG_POLL_SERVER_TIMEOUT, HEADER_FOR_SYNC_VERSION } from './ApiConstants.js'
1
+ import { API, LONG_POLL_SERVER_TIMEOUT, HEADER_SYNC_VERSION } from './ApiConstants.js'
2
2
 
3
3
 
4
4
  /** Client for controlling Mockaton via its HTTP API */
@@ -9,78 +9,49 @@ export class Commander {
9
9
  this.#addr = addr
10
10
  }
11
11
 
12
- #patch = (api, body) =>
13
- fetch(this.#addr + api, {
14
- method: 'PATCH',
15
- body: JSON.stringify(body)
16
- })
17
-
18
12
  /** @returns {JsonPromise<State>} */
19
13
  getState = () =>
20
14
  fetch(this.#addr + API.state)
21
15
 
22
- /** @returns {JsonPromise<number>} */
23
- getSyncVersion = (currSyncVer, abortSignal) =>
16
+ /**
17
+ * @param {number?} currSyncVer - On mismatch, it responds immediately. Otherwise, long polls.
18
+ * @param {AbortSignal} abortSignal
19
+ * @returns {JsonPromise<number>}
20
+ */
21
+ getSyncVersion = (currSyncVer = undefined, abortSignal = undefined) =>
24
22
  fetch(this.#addr + API.syncVersion, {
25
23
  signal: AbortSignal.any([
26
24
  abortSignal,
27
25
  AbortSignal.timeout(LONG_POLL_SERVER_TIMEOUT + 1000)
28
- ]),
29
- headers: {
30
- [HEADER_FOR_SYNC_VERSION]: currSyncVer
31
- }
26
+ ].filter(Boolean)),
27
+ headers: currSyncVer !== undefined
28
+ ? { [HEADER_SYNC_VERSION]: currSyncVer }
29
+ : {}
32
30
  })
33
31
 
34
32
 
35
- reset() {
36
- return this.#patch(API.reset)
37
- }
38
-
39
- select(file) {
40
- return this.#patch(API.select, file)
41
- }
42
-
43
- toggle500(method, urlMask) {
44
- return this.#patch(API.toggle500, [method, urlMask])
45
- }
46
-
47
- bulkSelectByComment(comment) {
48
- return this.#patch(API.bulkSelect, comment)
49
- }
50
-
51
- setRouteIsDelayed(method, urlMask, delayed) {
52
- return this.#patch(API.delay, [method, urlMask, delayed])
53
- }
54
-
55
- setStaticRouteIsDelayed(urlMask, delayed) {
56
- return this.#patch(API.delayStatic, [urlMask, delayed])
57
- }
58
-
59
- setStaticRouteStatus(urlMask, status) {
60
- return this.#patch(API.staticStatus, [urlMask, status])
61
- }
62
-
63
- setRouteIsProxied(method, urlMask, proxied) {
64
- return this.#patch(API.proxied, [method, urlMask, proxied])
33
+ #patch(api, body) {
34
+ return fetch(this.#addr + api, {
35
+ method: 'PATCH',
36
+ body: JSON.stringify(body)
37
+ })
65
38
  }
66
39
 
67
- selectCookie(cookieKey) {
68
- return this.#patch(API.cookies, cookieKey)
69
- }
40
+ reset = () => this.#patch(API.reset)
70
41
 
71
- setProxyFallback(proxyAddr) {
72
- return this.#patch(API.fallback, proxyAddr)
73
- }
42
+ selectCookie = label => this.#patch(API.cookies, label)
43
+ setGlobalDelay = delay => this.#patch(API.globalDelay, delay)
44
+ setCorsAllowed = value => this.#patch(API.cors, value)
45
+ setProxyFallback = proxyAddr => this.#patch(API.fallback, proxyAddr)
46
+ setCollectProxied = shouldCollect => this.#patch(API.collectProxied, shouldCollect)
74
47
 
75
- setCollectProxied(shouldCollect) {
76
- return this.#patch(API.collectProxied, shouldCollect)
77
- }
48
+ select = file => this.#patch(API.select, file)
49
+ bulkSelectByComment = comment => this.#patch(API.bulkSelect, comment)
78
50
 
79
- setCorsAllowed(value) {
80
- return this.#patch(API.cors, value)
81
- }
51
+ toggle500 = (method, urlMask) => this.#patch(API.toggle500, [method, urlMask])
52
+ setRouteIsProxied = (method, urlMask, proxied) => this.#patch(API.proxied, [method, urlMask, proxied])
53
+ setRouteIsDelayed = (method, urlMask, delayed) => this.#patch(API.delay, [method, urlMask, delayed])
82
54
 
83
- setGlobalDelay(delay) {
84
- return this.#patch(API.globalDelay, delay)
85
- }
55
+ setStaticRouteStatus = (urlMask, status) => this.#patch(API.staticStatus, [urlMask, status])
56
+ setStaticRouteIsDelayed = (urlMask, delayed) => this.#patch(API.delayStatic, [urlMask, delayed])
86
57
  }
@@ -1,6 +1,7 @@
1
1
  const MOUNT = '/mockaton'
2
2
  export const API = {
3
3
  dashboard: MOUNT,
4
+
4
5
  bulkSelect: MOUNT + '/bulk-select-by-comment',
5
6
  collectProxied: MOUNT + '/collect-proxied',
6
7
  cookies: MOUNT + '/cookies',
@@ -19,9 +20,9 @@ export const API = {
19
20
  toggle500: MOUNT + '/toggle500'
20
21
  }
21
22
 
22
- export const HEADER_FOR_502 = 'Mockaton502'
23
- export const HEADER_FOR_SYNC_VERSION = 'sync_version'
23
+ export const HEADER_502 = 'Mockaton502'
24
+ export const HEADER_SYNC_VERSION = 'sync_version'
24
25
 
25
26
  export const DEFAULT_MOCK_COMMENT = '(default)'
26
- export const EXT_FOR_UNKNOWN_MIME = 'unknown'
27
+ export const UNKNOWN_MIME_EXT = 'unknown'
27
28
  export const LONG_POLL_SERVER_TIMEOUT = 8_000
package/src/Dashboard.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createElement as r, createSvgElement as s, className, restoreFocus, Defer, Fragment } from './DashboardDom.js'
2
- import { HEADER_FOR_502 } from './ApiConstants.js'
2
+ import { HEADER_502 } from './ApiConstants.js'
3
3
  import { parseFilename } from './Filename.js'
4
4
  import { store } from './DashboardStore.js'
5
5
 
@@ -448,7 +448,7 @@ function StaticRow(row) {
448
448
  !groupByMethod && r('td', className(CSS.Method),
449
449
  'GET'),
450
450
 
451
- r('td', null,
451
+ r('td', { colspan: 2 },
452
452
  r('a', {
453
453
  href: row.urlMask,
454
454
  target: '_blank',
@@ -593,7 +593,7 @@ function PayloadViewerTitle(file, statusText) {
593
593
 
594
594
  function PayloadViewerTitleWhenProxied(response) {
595
595
  const mime = response.headers.get('content-type') || ''
596
- const badGateway = response.headers.get(HEADER_FOR_502)
596
+ const badGateway = response.headers.get(HEADER_502)
597
597
  return (
598
598
  r('span', null,
599
599
  badGateway
@@ -734,7 +734,7 @@ function SettingsIcon() {
734
734
  * The version increments when a mock file is added, removed, or renamed.
735
735
  */
736
736
  function initRealTimeUpdates() {
737
- let oldVersion = -1
737
+ let oldVersion = undefined
738
738
  let controller = new AbortController()
739
739
 
740
740
  longPoll()
@@ -755,11 +755,9 @@ function initRealTimeUpdates() {
755
755
  ErrorToast.close()
756
756
 
757
757
  const version = await response.json()
758
- const skipUpdate = oldVersion === -1
759
758
  if (oldVersion !== version) { // because it could be < or >
760
759
  oldVersion = version
761
- if (!skipUpdate)
762
- store.fetchState()
760
+ store.fetchState()
763
761
  }
764
762
  longPoll()
765
763
  }
package/src/Filename.js CHANGED
@@ -1,16 +1,10 @@
1
1
  const httpMethods = [ // @KeepSync with node:http.METHODS
2
- 'ACL', 'BIND', 'CHECKOUT',
3
- 'CONNECT', 'COPY', 'DELETE',
4
- 'GET', 'HEAD', 'LINK',
5
- 'LOCK', 'M-SEARCH', 'MERGE',
6
- 'MKACTIVITY', 'MKCALENDAR', 'MKCOL',
7
- 'MOVE', 'NOTIFY', 'OPTIONS',
8
- 'PATCH', 'POST', 'PROPFIND',
9
- 'PROPPATCH', 'PURGE', 'PUT',
10
- 'QUERY', 'REBIND', 'REPORT',
11
- 'SEARCH', 'SOURCE', 'SUBSCRIBE',
12
- 'TRACE', 'UNBIND', 'UNLINK',
13
- 'UNLOCK', 'UNSUBSCRIBE'
2
+ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE',
3
+ 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE',
4
+ 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS',
5
+ 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT',
6
+ 'QUERY', 'REBIND', 'REPORT', 'SEARCH', 'SOURCE', 'SUBSCRIBE',
7
+ 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE'
14
8
  ]
15
9
 
16
10
  const reComments = /\(.*?\)/g // Anything within parentheses
package/src/MockBroker.js CHANGED
@@ -4,7 +4,7 @@ import { DEFAULT_MOCK_COMMENT } from './ApiConstants.js'
4
4
 
5
5
  /**
6
6
  * MockBroker is a state for a particular route. It knows the available mock
7
- * files that can be served for the route, and the currently selected file, etc.
7
+ * files that can be served for the route, the currently selected file, etc.
8
8
  */
9
9
  export class MockBroker {
10
10
  constructor(file) {
@@ -114,7 +114,7 @@ class UrlMatcher {
114
114
  }
115
115
 
116
116
  #disregardVariables(str) { // Stars out all parts that are in square brackets
117
- return str.replace(/\[.*?]/g, '[^/]*')
117
+ return str.replace(/\[.*?]/g, '[^/]+')
118
118
  }
119
119
 
120
120
  // Appending a '/' so URLs ending with variables don't match
package/src/Mockaton.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createServer } from 'node:http'
2
2
 
3
- import { logger } from './utils/logger.js'
4
3
  import { API } from './ApiConstants.js'
4
+ import { logger } from './utils/logger.js'
5
5
  import { config, setup } from './config.js'
6
6
  import { dispatchMock } from './MockDispatcher.js'
7
7
  import { dispatchStatic } from './StaticDispatcher.js'
package/src/Watcher.js CHANGED
@@ -15,6 +15,7 @@ import * as mockBrokerCollection from './mockBrokersCollection.js'
15
15
  * and also renames, which are two events (delete + add).
16
16
  */
17
17
  export const uiSyncVersion = new class extends EventEmitter {
18
+ delay = Number(process.env.MOCKATON_WATCHER_DEBOUNCE_MS ?? 80)
18
19
  version = 0
19
20
 
20
21
  increment = this.#debounce(() => {
@@ -33,7 +34,7 @@ export const uiSyncVersion = new class extends EventEmitter {
33
34
  let timer
34
35
  return () => {
35
36
  clearTimeout(timer)
36
- timer = setTimeout(fn, 80)
37
+ timer = setTimeout(fn, this.delay)
37
38
  }
38
39
  }
39
40
  }
@@ -64,7 +65,7 @@ export function watchStaticDir() {
64
65
  const dir = config.staticDir
65
66
  if (!dir)
66
67
  return
67
-
68
+
68
69
  watch(dir, { recursive: true, persistent: false }, (_, file) => {
69
70
  if (!file)
70
71
  return
@@ -109,7 +109,7 @@ export function extractAllComments() {
109
109
  for (const c of b.extractComments())
110
110
  comments.add(c)
111
111
  })
112
- return Array.from(comments)
112
+ return Array.from(comments).sort()
113
113
  }
114
114
 
115
115
  export function setMocksMatchingComment(comment) {
@@ -50,6 +50,7 @@ export function readBody(req, parser = a => a) {
50
50
  }
51
51
 
52
52
  export const reControlAndDelChars = /[\x00-\x1f\x7f]/
53
+
53
54
  export function hasControlChars(url) {
54
55
  try {
55
56
  const decoded = decode(url)
@@ -1,7 +1,7 @@
1
1
  import fs, { readFileSync } from 'node:fs'
2
2
  import { logger } from './logger.js'
3
3
  import { mimeFor } from './mime.js'
4
- import { HEADER_FOR_502 } from '../ApiConstants.js'
4
+ import { HEADER_502 } from '../ApiConstants.js'
5
5
 
6
6
 
7
7
  export function sendOK(response) {
@@ -69,7 +69,7 @@ export function sendInternalServerError(response, error) {
69
69
  export function sendBadGateway(response, error) {
70
70
  logger.warn('Fallback Proxy Error:', error.cause.message)
71
71
  response.statusCode = 502
72
- response.setHeader(HEADER_FOR_502, 1)
72
+ response.setHeader(HEADER_502, 1)
73
73
  response.end()
74
74
  }
75
75
 
package/src/utils/mime.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { config } from '../config.js'
2
- import { EXT_FOR_UNKNOWN_MIME } from '../ApiConstants.js'
2
+ import { UNKNOWN_MIME_EXT } from '../ApiConstants.js'
3
3
 
4
4
 
5
5
  // Generated with:
@@ -119,7 +119,7 @@ export function extFor(mime) {
119
119
  function findExt(rawMime) {
120
120
  const m = parseMime(rawMime)
121
121
  const extraMimeToExt = mapMimeToExt(config.extraMimes)
122
- return extraMimeToExt[m] || mimeToExt[m] || EXT_FOR_UNKNOWN_MIME
122
+ return extraMimeToExt[m] || mimeToExt[m] || UNKNOWN_MIME_EXT
123
123
  }
124
124
 
125
125
  export function parseMime(mime) {