mockaton 10.5.0 → 10.5.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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "10.5.0",
5
+ "version": "10.5.2",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
package/src/Api.js CHANGED
@@ -4,26 +4,21 @@
4
4
  */
5
5
 
6
6
  import { join } from 'node:path'
7
+
7
8
  import { cookie } from './cookie.js'
8
9
  import { parseJSON } from './utils/http-request.js'
9
10
  import { uiSyncVersion } from './Watcher.js'
10
11
  import * as staticCollection from './staticCollection.js'
11
12
  import * as mockBrokersCollection from './mockBrokersCollection.js'
12
13
  import { config, ConfigValidator } from './config.js'
14
+ import { LinkHeader, DashboardHtml, CSP, dashboardAssets } from './DashboardHtml.js'
13
15
  import { DF, API, LONG_POLL_SERVER_TIMEOUT } from './ApiConstants.js'
14
- import { sendOK, sendJSON, sendUnprocessableContent, sendFile } from './utils/http-response.js'
16
+ import { sendOK, sendJSON, sendUnprocessableContent, sendFile, sendHTML } from './utils/http-response.js'
15
17
 
16
18
 
17
19
  export const apiGetRequests = new Map([
18
- [API.dashboard, serveDashboardAsset('Dashboard.html')],
19
- ...[
20
- '/ApiConstants.js',
21
- '/ApiCommander.js',
22
- '/Dashboard.css',
23
- '/Dashboard.js',
24
- '/Filename.js',
25
- '/Logo.svg'
26
- ].map(f => [API.dashboard + f, serveDashboardAsset(f)]),
20
+ [API.dashboard, serveDashboard],
21
+ ...dashboardAssets.map(f => [API.dashboard + f, serveStatic(f)]),
27
22
 
28
23
  [API.state, getState],
29
24
  [API.syncVersion, longPollClientSyncVersion],
@@ -49,12 +44,12 @@ export const apiPatchRequests = new Map([
49
44
 
50
45
  /** # GET */
51
46
 
52
- function serveDashboardAsset(f) {
53
- return (_, response) => {
54
- if (f.endsWith('.html'))
55
- response.setHeader('Content-Security-Policy', `default-src 'self'; img-src data: blob: 'self'`)
56
- sendFile(response, join(import.meta.dirname, f))
57
- }
47
+ function serveDashboard(_, response) {
48
+ sendHTML(response, DashboardHtml, CSP, LinkHeader)
49
+ }
50
+
51
+ function serveStatic(f) {
52
+ return (_, response) => sendFile(response, join(import.meta.dirname, f))
58
53
  }
59
54
 
60
55
  function getState(_, response) {
package/src/Dashboard.css CHANGED
@@ -149,7 +149,6 @@ header {
149
149
  background: var(--colorHeaderBackground);
150
150
 
151
151
  > img {
152
- width: 120px;
153
152
  align-self: end;
154
153
  margin-right: 22px;
155
154
  margin-bottom: 5px;
package/src/Dashboard.js CHANGED
@@ -76,7 +76,7 @@ const state = /** @type {State} */ {
76
76
 
77
77
  const mockaton = new Commander(location.origin)
78
78
  updateState()
79
- initLongPoll()
79
+ deferred(initLongPoll)
80
80
 
81
81
  async function updateState() {
82
82
  try {
@@ -93,7 +93,6 @@ async function updateState() {
93
93
 
94
94
  const r = createElement
95
95
  const s = createSvgElement
96
-
97
96
  const t = translation => translation[0]
98
97
 
99
98
  const leftSideRef = useRef()
@@ -124,7 +123,8 @@ function Header() {
124
123
  r('img', {
125
124
  alt: t`Mockaton`,
126
125
  src: 'mockaton/Logo.svg',
127
- width: 160
126
+ width: 120,
127
+ height: 22
128
128
  }),
129
129
  r('div', null,
130
130
  GlobalDelayField(),
@@ -645,6 +645,7 @@ Resizer.onUp = function () {
645
645
 
646
646
  const payloadViewerTitleRef = useRef()
647
647
  const payloadViewerRef = useRef()
648
+ const SPINNER_DELAY = 80
648
649
 
649
650
  function PayloadViewer() {
650
651
  return (
@@ -657,7 +658,7 @@ function PayloadViewer() {
657
658
  function PayloadViewerProgressBar() {
658
659
  return (
659
660
  r('div', className(CSS.ProgressBar),
660
- r('div', { style: { animationDuration: state.delay + 'ms' } })))
661
+ r('div', { style: { animationDuration: state.delay - SPINNER_DELAY + 'ms' } })))
661
662
  }
662
663
 
663
664
  function PayloadViewerTitle({ file, statusText }) {
@@ -689,7 +690,7 @@ async function previewMock(method, urlMask, href) {
689
690
  const spinnerTimer = setTimeout(() => {
690
691
  payloadViewerTitleRef.current.replaceChildren(t`Fetching…`)
691
692
  payloadViewerRef.current.replaceChildren(PayloadViewerProgressBar())
692
- }, 80)
693
+ }, SPINNER_DELAY)
693
694
 
694
695
  try {
695
696
  const response = await fetch(href, {
@@ -970,7 +971,7 @@ function dittoSplitPaths(paths) {
970
971
  return result
971
972
  }
972
973
 
973
- (function testDittoSplitPaths() {
974
+ dittoSplitPaths.test = function () {
974
975
  const input = [
975
976
  '/api/user',
976
977
  '/api/user/avatar',
@@ -992,7 +993,7 @@ function dittoSplitPaths(paths) {
992
993
  ['/v2/foo/', 'bar']
993
994
  ]
994
995
  console.assert(JSON.stringify(dittoSplitPaths(input)) === JSON.stringify(expected))
995
- }())
996
+ }
996
997
 
997
998
 
998
999
 
@@ -1,14 +1,51 @@
1
- <!DOCTYPE html>
1
+ import { API } from './ApiConstants.js'
2
+
3
+
4
+ export const DashboardHtml = `<!DOCTYPE html>
2
5
  <html lang="en-US">
3
6
  <head>
4
7
  <meta charset="UTF-8">
5
- <link rel="stylesheet" href="./mockaton/Dashboard.css">
8
+ <link rel="stylesheet" href="./mockaton/Dashboard.css" />
6
9
  <link rel="icon" href="data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m235 33.7v202c0 9.19-5.81 14-17.4 14-11.6 0-17.4-4.83-17.4-14v-151c-0.115-4.49-6.72-5.88-8.46-0.87l-48.3 155c-2.22 7.01-7.72 10.1-16 9.9-3.63-0.191-7.01-1.14-9.66-2.89-2.89-1.72-4.83-4.34-5.57-7.72-11.1-37-22.6-74.3-34.1-111-4.34-14-8.95-31.4-14-48.3-1.82-4.83-8.16-5.32-8.46 1.16v156c0 9.19-5.81 14-17.4 14-11.6 0-17.4-4.83-17.4-14v-207c0-5.74 2.62-13.2 9.39-16.3 7.5-3.14 15-4.05 21.8-3.8 3.14 0 6.03 0.686 8.95 1.46 3.14 0.797 6.03 1.98 8.7 3.63 2.65 1.38 5.32 3.14 7.5 5.57 2.22 2.22 3.87 4.83 5.07 7.72l45.8 157c4.63-15.9 32.4-117 33.3-121 4.12-13.8 7.72-26.5 10.9-38.7 1.16-2.65 2.89-5.32 5.07-7.5 2.15-2.15 4.58-4.12 7.5-5.32 2.65-1.57 5.57-2.89 8.46-3.63 3.14-0.797 9.44-0.988 12.1-0.988 11.6 1.07 29.4 9.14 29.4 27z' fill='%23808080'/%3E%3C/svg%3E">
7
10
  <meta name="viewport" content="width=device-width, initial-scale=1">
8
11
  <meta name="description" content="HTTP Mock Server">
9
12
  <title>Mockaton</title>
10
13
  </head>
11
14
  <body>
12
- <script src="./mockaton/Dashboard.js" type="module"></script>
15
+ <script type="module" src="./mockaton/Dashboard.js"></script>
13
16
  </body>
14
17
  </html>
18
+ `
19
+
20
+ export const CSP = [
21
+ `default-src 'self'`,
22
+ `img-src data: blob: 'self'`
23
+ ].join(';')
24
+
25
+
26
+ const assets = {
27
+ style: ['/Dashboard.css'],
28
+ script: ['/Dashboard.js'],
29
+ module: ['/ApiConstants.js', '/ApiCommander.js', '/Filename.js'],
30
+ image: ['/Logo.svg']
31
+ }
32
+
33
+ export const dashboardAssets = Object.values(assets).flat()
34
+
35
+
36
+ // Link Header. This is not very useful in localhost (only optimizes 2ms).
37
+ const attrMap = {
38
+ module: 'rel=modulepreload',
39
+ image: 'rel=preload; as=image',
40
+ style: 'rel=preload; as=style',
41
+ script: 'rel=preload; as=script; crossorigin',
42
+ fetch: 'rel=preload; as=fetch; crossorigin'
43
+ }
44
+
45
+ let links = []
46
+ for (const [type, files] of Object.entries(assets))
47
+ for (const f of files)
48
+ links.push(`<${API.dashboard + f}>; ${attrMap[type]}`)
49
+ links.push(`<${API.state}>; ${attrMap.fetch}`)
50
+
51
+ export const LinkHeader = links.join(',')
@@ -9,6 +9,14 @@ export function sendOK(response) {
9
9
  response.end()
10
10
  }
11
11
 
12
+ export function sendHTML(response, html, csp, link) {
13
+ logger.access(response)
14
+ response.setHeader('Content-Type', mimeFor('html'))
15
+ response.setHeader('Content-Security-Policy', csp)
16
+ response.setHeader('Link', link)
17
+ response.end(html)
18
+ }
19
+
12
20
  export function sendJSON(response, payload) {
13
21
  logger.access(response)
14
22
  response.setHeader('Content-Type', 'application/json')