mockaton 8.11.5 → 8.11.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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "A deterministic server-side for developing and testing frontend clients",
4
4
  "type": "module",
5
- "version": "8.11.5",
5
+ "version": "8.11.6",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
@@ -30,3 +30,5 @@ export const DEFAULT_MOCK_COMMENT = '(default)'
30
30
  export const EXT_FOR_UNKNOWN_MIME = 'unknown'
31
31
 
32
32
  export const LONG_POLL_SERVER_TIMEOUT = 8_000
33
+
34
+ export const HEADER_FOR_502 = 'mockaton502'
package/src/Dashboard.css CHANGED
@@ -103,6 +103,10 @@ select {
103
103
  }
104
104
  }
105
105
 
106
+ .red {
107
+ color: var(--colorRed);
108
+ }
109
+
106
110
  .Header {
107
111
  position: fixed;
108
112
  z-index: 100;
package/src/Dashboard.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DEFAULT_500_COMMENT } from './ApiConstants.js'
1
+ import { DEFAULT_500_COMMENT, HEADER_FOR_502 } from './ApiConstants.js'
2
2
  import { parseFilename } from './Filename.js'
3
3
  import { Commander } from './Commander.js'
4
4
 
@@ -20,6 +20,7 @@ const Strings = {
20
20
  delay_ms: 'Delay (ms)',
21
21
  empty_response_body: '/* Empty Response Body */',
22
22
  fallback_server: 'Fallback Backend',
23
+ fallback_server_error: '⛔ Fallback Backend Error',
23
24
  fallback_server_placeholder: 'Type Server Address',
24
25
  got: 'Got',
25
26
  internal_server_error: 'Internal Server Error',
@@ -51,6 +52,7 @@ const CSS = {
51
52
  SaveProxiedCheckbox: 'SaveProxiedCheckbox',
52
53
  StaticFilesList: 'StaticFilesList',
53
54
 
55
+ red: 'red',
54
56
  empty: 'empty',
55
57
  chosen: 'chosen',
56
58
  status4xx: 'status4xx',
@@ -425,10 +427,12 @@ function PayloadViewerTitle({ file, status, statusText }) {
425
427
  r('abbr', { title: statusText }, status),
426
428
  '.' + ext))
427
429
  }
428
- function PayloadViewerTitleWhenProxied({ mime, status, statusText }) {
430
+ function PayloadViewerTitleWhenProxied({ mime, status, statusText, gatewayIsBad }) {
429
431
  return (
430
432
  r('span', null,
431
- Strings.got + ' ',
433
+ gatewayIsBad
434
+ ? r('span', { className: CSS.red }, Strings.fallback_server_error + ' ')
435
+ : r('span', null, Strings.got + ' '),
432
436
  r('abbr', { title: statusText }, status),
433
437
  ' ' + mime))
434
438
  }
@@ -452,7 +456,8 @@ async function updatePayloadViewer(method, urlMask, response) {
452
456
  payloadViewerTitleRef.current.replaceChildren(PayloadViewerTitleWhenProxied({
453
457
  status: response.status,
454
458
  statusText: response.statusText,
455
- mime
459
+ mime,
460
+ gatewayIsBad: response.headers.get(HEADER_FOR_502)
456
461
  }))
457
462
  else
458
463
  payloadViewerTitleRef.current.replaceChildren(PayloadViewerTitle({
package/src/ProxyRelay.js CHANGED
@@ -3,25 +3,36 @@ import { randomUUID } from 'node:crypto'
3
3
 
4
4
  import { config } from './config.js'
5
5
  import { extFor } from './utils/mime.js'
6
- import { readBody } from './utils/http-request.js'
7
6
  import { write, isFile } from './utils/fs.js'
8
7
  import { makeMockFilename } from './Filename.js'
8
+ import { readBody, BodyReaderError } from './utils/http-request.js'
9
+ import { sendUnprocessableContent, sendBadGateway } from './utils/http-response.js'
9
10
 
10
11
 
11
12
  export async function proxy(req, response, delay) {
12
- const proxyResponse = await fetch(config.proxyFallback + req.url, {
13
- method: req.method,
14
- headers: req.headers,
15
- body: req.method === 'GET' || req.method === 'HEAD'
16
- ? undefined
17
- : await readBody(req)
18
- })
13
+ let proxyResponse
14
+ try {
15
+ proxyResponse = await fetch(config.proxyFallback + req.url, {
16
+ method: req.method,
17
+ headers: req.headers,
18
+ body: req.method === 'GET' || req.method === 'HEAD'
19
+ ? undefined
20
+ : await readBody(req)
21
+ })
22
+ }
23
+ catch (error) { // TESTME
24
+ if (error instanceof BodyReaderError)
25
+ sendUnprocessableContent(response, error.name)
26
+ else
27
+ sendBadGateway(response, error)
28
+ return
29
+ }
19
30
 
20
31
  const headers = Object.fromEntries(proxyResponse.headers)
21
32
  headers['set-cookie'] = proxyResponse.headers.getSetCookie() // parses multiple into an array
22
33
  response.writeHead(proxyResponse.status, headers)
23
34
  const body = await proxyResponse.text()
24
- setTimeout(() => response.end(body), delay) // TESTME (Note that when the proxy fails e.g. wrong addr it doesn't delay)
35
+ setTimeout(() => response.end(body), delay) // TESTME
25
36
 
26
37
  if (config.collectProxied) {
27
38
  const ext = extFor(proxyResponse.headers.get('content-type'))
@@ -1,5 +1,6 @@
1
1
  import { readFileSync } from 'node:fs'
2
2
  import { mimeFor } from './mime.js'
3
+ import { HEADER_FOR_502 } from '../ApiConstants.js'
3
4
 
4
5
 
5
6
  export function sendOK(response) {
@@ -42,3 +43,10 @@ export function sendInternalServerError(response, error) {
42
43
  response.statusCode = 500
43
44
  response.end()
44
45
  }
46
+
47
+ export function sendBadGateway(response, error) {
48
+ console.error('Fallback Proxy Error:', error.cause.message)
49
+ response.statusCode = 502
50
+ response.setHeader(HEADER_FOR_502, 1)
51
+ response.end()
52
+ }