mockaton 11.0.0 → 11.0.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.
package/Makefile CHANGED
@@ -6,23 +6,23 @@ watch:
6
6
 
7
7
 
8
8
  test:
9
- node --test 'src/**/*.test.js'
9
+ @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
+ @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
@@ -129,14 +129,15 @@ With Mockaton, developers can achieve correctness and speed.
129
129
  <br/>
130
130
 
131
131
  ## Basic Usage
132
- 1. Install Node.js, which comes with `npm` and `npx`
132
+
133
+ 1. Install Node.js (v22.18+ support writing mocks in TypeScript)
133
134
 
134
135
  2. Create a sample mock in the default mocks directory (`./mockaton-mocks`)
135
136
  ```sh
136
137
  mkdir -p mockaton-mocks/api
137
138
  echo "[1,2,3]" > mockaton-mocks/api/foo.GET.200.json
138
139
  ```
139
- 3. Run Mockaton (`npx` installs it if needed)
140
+ 3. Run Mockaton (`npx` comes with Node, and installs Mockaton if needed)
140
141
  ```shell
141
142
  npx mockaton --port 2345
142
143
  ```
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.1",
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,7 @@ 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
+ if (uiSyncVersion.version !== Number(req.headers[HEADER_SYNC_VERSION])) {
85
85
  // e.g., tab was hidden while new mocks were added or removed
86
86
  sendJSON(response, uiSyncVersion.version)
87
87
  return
@@ -111,9 +111,9 @@ function reinitialize(_, response) {
111
111
 
112
112
 
113
113
  async function selectCookie(req, response) {
114
- const label = await parseJSON(req)
114
+ const cookieKey = await parseJSON(req)
115
115
 
116
- const error = cookie.setCurrent(label)
116
+ const error = cookie.setCurrent(cookieKey)
117
117
  if (error)
118
118
  sendUnprocessableContent(response, error?.message || error)
119
119
  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 */
@@ -20,14 +20,14 @@ export class Commander {
20
20
  fetch(this.#addr + API.state)
21
21
 
22
22
  /** @returns {JsonPromise<number>} */
23
- getSyncVersion = (currSyncVer, abortSignal) =>
23
+ getSyncVersion = (currSyncVer, abortSignal = undefined) =>
24
24
  fetch(this.#addr + API.syncVersion, {
25
25
  signal: AbortSignal.any([
26
26
  abortSignal,
27
27
  AbortSignal.timeout(LONG_POLL_SERVER_TIMEOUT + 1000)
28
- ]),
28
+ ].filter(Boolean)),
29
29
  headers: {
30
- [HEADER_FOR_SYNC_VERSION]: currSyncVer
30
+ [HEADER_SYNC_VERSION]: currSyncVer
31
31
  }
32
32
  })
33
33
 
@@ -36,34 +36,14 @@ export class Commander {
36
36
  return this.#patch(API.reset)
37
37
  }
38
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])
39
+ setGlobalDelay(delay) {
40
+ return this.#patch(API.globalDelay, delay)
45
41
  }
46
42
 
47
43
  bulkSelectByComment(comment) {
48
44
  return this.#patch(API.bulkSelect, comment)
49
45
  }
50
46
 
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])
65
- }
66
-
67
47
  selectCookie(cookieKey) {
68
48
  return this.#patch(API.cookies, cookieKey)
69
49
  }
@@ -80,7 +60,29 @@ export class Commander {
80
60
  return this.#patch(API.cors, value)
81
61
  }
82
62
 
83
- setGlobalDelay(delay) {
84
- return this.#patch(API.globalDelay, delay)
63
+
64
+ select(file) {
65
+ return this.#patch(API.select, file)
66
+ }
67
+
68
+ toggle500(method, urlMask) {
69
+ return this.#patch(API.toggle500, [method, urlMask])
70
+ }
71
+
72
+ setRouteIsDelayed(method, urlMask, delayed) {
73
+ return this.#patch(API.delay, [method, urlMask, delayed])
74
+ }
75
+
76
+ setRouteIsProxied(method, urlMask, proxied) {
77
+ return this.#patch(API.proxied, [method, urlMask, proxied])
78
+ }
79
+
80
+
81
+ setStaticRouteIsDelayed(urlMask, delayed) {
82
+ return this.#patch(API.delayStatic, [urlMask, delayed])
83
+ }
84
+
85
+ setStaticRouteStatus(urlMask, status) {
86
+ return this.#patch(API.staticStatus, [urlMask, status])
85
87
  }
86
88
  }
@@ -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
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) {
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'
@@ -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) {