mockaton 11.2.5 → 11.2.6

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.
@@ -2,19 +2,26 @@ import { join } from 'node:path'
2
2
  import { watch } from 'node:fs'
3
3
  import { EventEmitter } from 'node:events'
4
4
 
5
+ import {
6
+ HEADER_SYNC_VERSION,
7
+ LONG_POLL_SERVER_TIMEOUT
8
+ } from './ApiConstants.js'
9
+
5
10
  import { config } from './config.js'
11
+ import { sendJSON } from './utils/http-response.js'
6
12
  import { isFile, isDirectory } from './utils/fs.js'
13
+
7
14
  import * as staticCollection from './staticCollection.js'
8
15
  import * as mockBrokerCollection from './mockBrokersCollection.js'
9
16
 
10
17
 
11
18
  /**
12
- * ARR = Add, Remove, or Rename Mock Event
19
+ * ARR Event = Add, Remove, or Rename Mock
13
20
  *
14
21
  * The emitter is debounced so it handles e.g. bulk deletes,
15
22
  * and also renames, which are two events (delete + add).
16
23
  */
17
- export const uiSyncVersion = new class extends EventEmitter {
24
+ const uiSyncVersion = new class extends EventEmitter {
18
25
  delay = Number(process.env.MOCKATON_WATCHER_DEBOUNCE_MS ?? 80)
19
26
  version = 0
20
27
 
@@ -39,6 +46,7 @@ export const uiSyncVersion = new class extends EventEmitter {
39
46
  }
40
47
  }
41
48
 
49
+
42
50
  export function watchMocksDir() {
43
51
  const dir = config.mocksDir
44
52
  watch(dir, { recursive: true, persistent: false }, (_, file) => {
@@ -61,6 +69,7 @@ export function watchMocksDir() {
61
69
  })
62
70
  }
63
71
 
72
+
64
73
  export function watchStaticDir() {
65
74
  const dir = config.staticDir
66
75
  if (!dir)
@@ -86,4 +95,23 @@ export function watchStaticDir() {
86
95
  })
87
96
  }
88
97
 
89
- // TODO ThinkAbout watching for config changes
98
+
99
+ /** Realtime notify ARR Events */
100
+ export function longPollClientSyncVersion(req, response) {
101
+ const clientVersion = req.headers[HEADER_SYNC_VERSION]
102
+ if (clientVersion !== undefined && uiSyncVersion.version !== Number(clientVersion)) {
103
+ // e.g., tab was hidden while new mocks were added or removed
104
+ sendJSON(response, uiSyncVersion.version)
105
+ return
106
+ }
107
+ function onARR() {
108
+ uiSyncVersion.unsubscribe(onARR)
109
+ sendJSON(response, uiSyncVersion.version)
110
+ }
111
+ response.setTimeout(LONG_POLL_SERVER_TIMEOUT, onARR)
112
+ req.on('error', () => {
113
+ uiSyncVersion.unsubscribe(onARR)
114
+ response.destroy()
115
+ })
116
+ uiSyncVersion.subscribe(onARR)
117
+ }
@@ -1,17 +1,50 @@
1
- import { watch } from 'node:fs'
1
+ import { join } from 'node:path'
2
2
  import { EventEmitter } from 'node:events'
3
+ import { watch, readdirSync } from 'node:fs'
4
+ import { sendJSON, sendNotFound } from './utils/http-response.js'
5
+ import { LONG_POLL_SERVER_TIMEOUT } from './ApiConstants.js'
3
6
 
4
7
 
5
- export const devClientWatcher = new class extends EventEmitter {
8
+ const DEV = process.env.NODE_ENV === 'development'
9
+
10
+ export const CLIENT_DIR = join(import.meta.dirname, '../client')
11
+ export const DASHBOARD_ASSETS = readdirSync(CLIENT_DIR)
12
+
13
+
14
+ const devClientWatcher = new class extends EventEmitter {
6
15
  emit(file) { super.emit('RELOAD', file) }
7
16
  subscribe(listener) { this.once('RELOAD', listener) }
8
17
  unsubscribe(listener) { this.removeListener('RELOAD', listener) }
9
18
  }
10
19
 
11
- // DashboardHtml.js is not watched.
12
- // It would need dynamic import + cache busting
20
+
21
+ // Although `client/indexHtml.js` is watched, it returns a stale version.
22
+ // i.e., it would need to be a dynamic import + cache busting.
13
23
  export function watchDevSPA() {
14
- watch('src/client', (_, file) => {
24
+ watch(CLIENT_DIR, (_, file) => {
15
25
  devClientWatcher.emit(file)
16
26
  })
17
27
  }
28
+
29
+
30
+ /** Realtime notify Dev UI changes */
31
+ export function longPollDevClientHotReload(req, response) {
32
+ if (!DEV) {
33
+ sendNotFound(response)
34
+ return
35
+ }
36
+
37
+ function onDevChange(file) {
38
+ devClientWatcher.unsubscribe(onDevChange)
39
+ sendJSON(response, file)
40
+ }
41
+ response.setTimeout(LONG_POLL_SERVER_TIMEOUT, () => {
42
+ devClientWatcher.unsubscribe(onDevChange)
43
+ sendJSON(response, '')
44
+ })
45
+ req.on('error', () => {
46
+ devClientWatcher.unsubscribe(onDevChange)
47
+ response.destroy()
48
+ })
49
+ devClientWatcher.subscribe(onDevChange)
50
+ }
package/src/server/cli.js CHANGED
@@ -5,6 +5,7 @@ import { parseArgs } from 'node:util'
5
5
 
6
6
  import { isFile } from './utils/fs.js'
7
7
  import { Mockaton } from '../../index.js'
8
+
8
9
  import pkgJSON from '../../package.json' with { type: 'json' }
9
10
 
10
11
 
@@ -3,11 +3,12 @@ import { resolve } from 'node:path'
3
3
  import { logger } from './utils/logger.js'
4
4
  import { isDirectory } from './utils/fs.js'
5
5
  import { openInBrowser } from './utils/openInBrowser.js'
6
- import { jsToJsonPlugin } from './MockDispatcher.js'
7
6
  import { optional, is, validate } from './utils/validate.js'
8
7
  import { SUPPORTED_METHODS } from './utils/http-request.js'
9
8
  import { validateCorsAllowedMethods, validateCorsAllowedOrigins } from './utils/http-cors.js'
10
9
 
10
+ import { jsToJsonPlugin } from './MockDispatcher.js'
11
+
11
12
 
12
13
  /** @type {{
13
14
  * [K in keyof Config]-?: [
@@ -1,9 +1,10 @@
1
1
  import { basename } from 'node:path'
2
2
 
3
3
  import { logger } from './utils/logger.js'
4
+ import { listFilesRecursively } from './utils/fs.js'
5
+
4
6
  import { cookie } from './cookie.js'
5
7
  import { MockBroker } from './MockBroker.js'
6
- import { listFilesRecursively } from './utils/fs.js'
7
8
  import { config, isFileAllowed } from './config.js'
8
9
  import { parseFilename, validateFilename } from './Filename.js'
9
10
 
@@ -1,5 +1,6 @@
1
1
  import { join, dirname, sep, posix } from 'node:path'
2
2
  import { lstatSync, readdirSync, writeFileSync, mkdirSync } from 'node:fs'
3
+
3
4
  import { logger } from './logger.js'
4
5
 
5
6
 
@@ -47,6 +47,12 @@ export function sendBadRequest(response) {
47
47
  response.end()
48
48
  }
49
49
 
50
+ export function sendNotFound(response) {
51
+ response.statusCode = 404
52
+ logger.access(response)
53
+ response.end()
54
+ }
55
+
50
56
  export function sendMockNotFound(response) {
51
57
  response.statusCode = 404
52
58
  logger.accessMock(response.req.url, '404')