mockaton 11.4.1 → 12.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/README.md CHANGED
@@ -1,30 +1,14 @@
1
- <svg width="210" viewBox="0 0 556 100" xmlns="http://www.w3.org/2000/svg">
2
- <style>
3
- @media (prefers-color-scheme: light) { :root { --color: #333 } }
4
- @media (prefers-color-scheme: dark) { :root { --color: #eee } }
5
- path {
6
- fill: #777;
7
- fill: var(--color);
8
- }
9
- </style>
10
- <path
11
- d="m13.75 1.8789c-5.9487 0.19352-10.865 4.5652-11.082 11.686v81.445c-1e-7 2.216 1.784 4 4 4h4.793c2.216 0 4-1.784 4-4v-64.982c0.02794-3.4488 3.0988-3.5551 4.2031-1.1562l16.615 59.059c1.4393 5.3711 5.1083 7.9633 8.7656 7.9473 3.6573 0.01603 7.3263-2.5762 8.7656-7.9473l16.615-59.059c1.1043-2.3989 4.1752-2.2925 4.2031 1.1562v64.982c0 2.216 1.784 4 4 4h4.793c2.216 0 4-1.784 4-4v-81.445c-0.17732-7.0807-5.1334-11.492-11.082-11.686-5.9487-0.19352-12.652 3.8309-15.609 13.619l-15.686 57.334-15.686-57.334c-2.9569-9.7882-9.6607-13.813-15.609-13.619zm239.19 0.074219c-2.216 0-4 1.784-4 4v89.057c0 2.216 1.784 4 4 4h4.793c2.216 0 3.9868-1.784 4-4l0.10644-17.94c0.0734-0.07237 12.175-13.75 12.175-13.75 5.6772 11.091 11.404 22.158 17.113 33.232 1.0168 1.9689 3.4217 2.7356 5.3906 1.7188l4.2578-2.1992c1.9689-1.0168 2.7356-3.4217 1.7188-5.3906-6.4691-12.585-12.958-25.16-19.442-37.738l17.223-19.771c1.4555-1.671 1.2803-4.189-0.39062-5.6445l-3.6133-3.1465c-0.73105-0.63679-1.6224-0.96212-2.5176-0.98633-1.151-0.03113-2.3063 0.43508-3.125 1.375l-28.896 33.174v-51.99c0-2.216-1.784-4-4-4zm-58.255 23.316c-10.699 0-19.312 8.6137-19.312 19.312v34.535c0 10.699 8.6137 19.312 19.312 19.312h19.717c10.699 0 19.311-8.6137 19.311-19.312l-0.125-7.8457c0-2.216-1.784-4-4-4h-4.6524c-2.216 0-4 1.784-4 4l3e-3 6.7888c3e-3 3.8063-1.5601 9.3694-8.4716 9.3694h-15.846c-6.9115 0-8.4766-5.5631-8.4766-12.475v-26.209c0-6.9115 1.5651-12.477 8.4766-12.477h15.846c6.6937 0 8.3697 5.2207 8.4687 11.828v2.2207c0 2.216 1.784 4 4 4h4.6524c2.216 0 4-1.784 4-4l0.125-5.7363c0-10.699-8.6117-19.312-19.311-19.312zm-72.182 0c-10.699 0-19.312 8.6137-19.312 19.312v34.535c0 10.699 8.6137 19.312 19.312 19.312h19.717c10.699 0 19.311-8.6137 19.311-19.312v-34.535c0-10.699-8.6117-19.312-19.311-19.312zm1.9356 11h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v26.209c0 6.9115-1.5631 12.475-8.4746 12.475h-15.846c-6.9115 0-8.4766-5.5631-8.4766-12.475v-26.209c0-6.9115 1.5651-12.477 8.4766-12.477z"/>
12
- <path
13
- d="m331.9 25.27c-10.699 0-19.312 8.6137-19.312 19.312v4.3682c0 2.216 1.784 4 4 4h4.7715c2.216 0 4-1.784 4-4v-0.20414c0-6.9115 1.5651-12.477 8.4766-12.477h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v7.0148h-28.059c-10.699 0-19.312 8.6117-19.312 19.311v4.0477c0 10.699 8.6137 19.313 19.312 19.312h17.812c2.216-1e-6 4-1.784 4-4v-4.7715c0-2.216-1.784-4-4-4h-13.648c-6.9115-2e-5 -12.477-1.5651-12.477-8.5649 0-6.9998 5.5651-8.5629 12.477-8.5629h23.895v25.897c0 2.216 1.784 4 4 4h4.7715c2.216-1e-6 4-1.784 4-4v-49.848c0-10.699-8.6117-19.312-19.311-19.312z"
14
- opacity="0.75"/>
15
- <path
16
- d="m392.75 1.373c-2.216 0-4 1.784-4 4v18.043h-5.3086c-2.216 0-4 1.784-4 4v4.793c0 2.216 1.784 4 4 4h5.3086v51.398c0 6.1465 3.7064 10.823 9.232 10.823h16.531c2.216 0 4-1.784 4-4v-4.793c0-2.216-1.784-4-4-4h-12.97v-49.428h9.8711c2.216 0 4-1.784 4-4v-4.793c0-2.216-1.784-4-4-4h-9.8711v-18.043c0-2.216-1.784-4-4-4zm122.96 23.896c-10.699 0-19.312 8.6137-19.312 19.312v49.812c0 2.216 1.784 4 4 4h4.7715c2.216 0 4-1.784 4-4v-45.648c0-6.9115 1.5651-12.477 8.4766-12.477h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v45.684c0 2.216 1.784 4 4 4h4.7715c2.216-1e-6 4-1.784 4-4v-49.848c0-10.699-8.6117-19.312-19.311-19.312zm-69.999 0c-10.699 0-19.312 8.6137-19.312 19.312v34.535c0 10.699 8.6137 19.312 19.312 19.312h19.717c10.699 0 19.311-8.6137 19.311-19.312v-34.535c0-10.699-8.6117-19.312-19.311-19.312zm1.9356 11h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v26.209c0 6.9115-1.5631 12.475-8.4746 12.475h-15.846c-6.9115 0-8.4766-5.5631-8.4766-12.475v-26.209c0-6.9115 1.5651-12.477 8.4766-12.477z"/>
17
- </svg>
1
+ # Mockaton
18
2
 
3
+ An HTTP mock server for simulating APIs with minimal setup &mdash; ideal
4
+ for testing difficult to reproduce backend states.
19
5
 
20
6
  ![NPM Version](https://img.shields.io/npm/v/mockaton)
21
7
  [![Test](https://github.com/ericfortis/mockaton/actions/workflows/test.yml/badge.svg)](https://github.com/ericfortis/mockaton/actions/workflows/test.yml)
22
8
  [![codecov](https://codecov.io/github/ericfortis/mockaton/graph/badge.svg?token=90NYLMMG1J)](https://codecov.io/github/ericfortis/mockaton)
23
9
 
24
- An HTTP mock server for simulating APIs with minimal setup &mdash; ideal
25
- for testing difficult to reproduce backend states.
26
10
 
27
- ## [mockaton.com ↗](https://mockaton.com)
11
+ ## [Documentation ↗](https://mockaton.com)
28
12
  ## [Changelog ↗](https://mockaton.com/changelog)
29
13
 
30
14
  ## Overview
@@ -40,6 +24,25 @@ For example, for [/api/company/123](#), the filename could be:
40
24
 
41
25
  <br/>
42
26
 
27
+ ## Dashboard
28
+
29
+ <picture>
30
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.light.gold.png">
31
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.dark.gold.png">
32
+ <img alt="Mockaton Dashboard" src="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.dark.gold.png">
33
+ </picture>
34
+
35
+ On the dashboard you can:
36
+ - Select a mock variant for a particular route
37
+ - 🕓 Delay responses
38
+ - Trigger an autogenerated `500` error
39
+ - …and cycle it off (for testing retries)
40
+
41
+ Nonetheless, there’s a [Control API ↗](https://mockaton.com/api), which is handy for
42
+ setting up tests.
43
+
44
+ <br/>
45
+
43
46
 
44
47
  ## Quick Start (Docker)
45
48
  This will spin up Mockaton with the sample directories
@@ -61,26 +64,6 @@ curl localhost:2020/api/user
61
64
  ```
62
65
 
63
66
 
64
- <br/>
65
-
66
- ## Dashboard
67
-
68
-
69
- <picture>
70
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.light.gold.png">
71
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.dark.gold.png">
72
- <img alt="Mockaton Dashboard" src="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.dark.gold.png">
73
- </picture>
74
-
75
- On the dashboard you can:
76
- - Select a mock variant for a particular route
77
- - 🕓 Delay responses
78
- - Trigger an autogenerated `500` error
79
- - …and cycle it off (for testing retries)
80
-
81
- Nonetheless, there’s a programmatic API, which is handy for
82
- setting up tests (see **Commander&nbsp;API** section below).
83
-
84
67
 
85
68
  ## License
86
69
  MIT
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.4.1",
5
+ "version": "12.0.1",
6
6
  "exports": {
7
7
  ".": {
8
8
  "import": "./index.js",
package/src/client/app.js CHANGED
@@ -1,65 +1,15 @@
1
1
  import {
2
2
  createElement as r,
3
3
  createSvgElement as s,
4
- className, restoreFocus, Defer, Fragment
4
+ className, restoreFocus, Defer, Fragment, adoptCSS
5
5
  } from './dom-utils.js'
6
6
 
7
7
  import { store } from './app-store.js'
8
8
  import { parseFilename } from './Filename.js'
9
9
  import { HEADER_502 } from './ApiConstants.js'
10
10
 
11
-
12
- const CSS = {
13
- BulkSelector: null,
14
- CookieSelector: null,
15
- DelayToggler: null,
16
- ErrorToast: null,
17
- FallbackBackend: null,
18
- Field: null,
19
- GlobalDelayField: null,
20
- GlobalDelayJitterField: null,
21
- GlobalDelayWrap: null,
22
- GroupByMethod: null,
23
- InternalServerErrorToggler: null,
24
- Logo: null,
25
- MenuTrigger: null,
26
- Method: null,
27
- MockSelector: null,
28
- NotFoundToggler: null,
29
- PayloadViewer: null,
30
- PreviewLink: null,
31
- ProgressBar: null,
32
- ProxyToggler: null,
33
- ResetButton: null,
34
- Resizer: null,
35
- SaveProxiedCheckbox: null,
36
- SettingsMenu: null,
37
- Table: null,
38
- TableHeading: null,
39
- TableRow: null,
40
-
41
- animIn: null,
42
- canProxy: null,
43
- checkboxBody: null,
44
- chosen: null,
45
- dittoDir: null,
46
- leftSide: null,
47
- nonDefault: null,
48
- nonGroupedByMethod: null,
49
- rightSide: null,
50
- status4xx: null,
51
-
52
- syntaxAttr: null,
53
- syntaxAttrVal: null,
54
- syntaxKey: null,
55
- syntaxPunc: null,
56
- syntaxStr: null,
57
- syntaxTag: null,
58
- syntaxVal: null
59
- }
60
- for (const k of Object.keys(CSS))
61
- CSS[k] = k
62
-
11
+ import CSS from './styles.css' with { type: 'css' }
12
+ adoptCSS(CSS)
63
13
 
64
14
  const FocusGroup = {
65
15
  ProxyToggler: 0,
@@ -0,0 +1,71 @@
1
+ import { test } from 'node:test'
2
+ import { deepEqual } from 'node:assert/strict'
3
+ import { extractClassNames } from './dom-utils.js'
4
+
5
+
6
+ const cssRules = [
7
+ { cssText: '.TopLevelPascal { color: red; }' },
8
+ { cssText: '.topLevelCamel { color: blue; }' },
9
+ { cssText: '.top_level_snake { color: green; }' },
10
+ { cssText: '.top-level-kebab { color: yellow; }' },
11
+ { cssText: '.Level2Parent {\n & .level2ChildCamel { color: purple; }\n}' },
12
+ { cssText: '.level2Base {\n &.level2ModifierCamel { font-weight: bold; }\n}' },
13
+ { cssText: '.Level3Parent {\n & .level3ChildCamel {\n & .level3_grand_child_snake { color: orange; }\n}\n}' },
14
+ { cssText: '.pseudoParent {\n &:hover { background: red; }\n & .pseudoNestedChild { color: pink; }\n}' },
15
+ { cssText: '.multiClass1, .multi_class_2 { padding: 10px; }' },
16
+ { cssText: '.combParent {\n & > .combChildDirect { margin: 5px; }\n}' },
17
+ { cssText: '.siblingBase {\n & + .siblingAdjacent { border: 1px solid; }\n}' },
18
+ { cssText: '@media (max-width: 768px) {\n .mediaQueryClass {\n & .mqNestedChild { display: none; }\n}\n}' },
19
+ { cssText: '.class_with_123_numbers { color: cyan; }' },
20
+ { cssText: '._privateStyleClass { opacity: 0.5; }' },
21
+ { cssText: '.stringTest { content: ".shouldNotBeExtracted"; background: url(".alsoIgnored"); }' },
22
+ { cssText: '.ComplexRoot {\n & .level2-kebab {\n &.level2ModCamel { color: red; }\n & .level3_snake {\n & .level4PascalChild { color: blue; }\n}\n}\n}' }
23
+ ]
24
+
25
+ const expected = {
26
+ TopLevelPascal: null,
27
+ topLevelCamel: null,
28
+ top_level_snake: null,
29
+ 'top-level-kebab': null,
30
+
31
+ Level2Parent: null,
32
+ level2ChildCamel: null,
33
+ level2Base: null,
34
+ level2ModifierCamel: null,
35
+
36
+ Level3Parent: null,
37
+ level3ChildCamel: null,
38
+ level3_grand_child_snake: null,
39
+
40
+ pseudoParent: null,
41
+ pseudoNestedChild: null,
42
+
43
+ multiClass1: null,
44
+ multi_class_2: null,
45
+
46
+ combParent: null,
47
+ combChildDirect: null,
48
+
49
+ siblingBase: null,
50
+ siblingAdjacent: null,
51
+
52
+ mediaQueryClass: null,
53
+ mqNestedChild: null,
54
+
55
+ class_with_123_numbers: null,
56
+ _privateStyleClass: null,
57
+
58
+ stringTest: null,
59
+
60
+ ComplexRoot: null,
61
+ 'level2-kebab': null,
62
+ level2ModCamel: null,
63
+ level3_snake: null,
64
+ level4PascalChild: null
65
+ }
66
+ for (const k of Object.keys(expected))
67
+ expected[k] = k
68
+
69
+
70
+ test('extracts', () => deepEqual(extractClassNames({ cssRules }), expected))
71
+
@@ -78,3 +78,28 @@ function selectorFor(elem) {
78
78
  return path.reverse().join('>')
79
79
  }
80
80
 
81
+
82
+
83
+ // Minimal implementation of CSS Modules in the browser
84
+ // TODO think about avoiding clashes when using multiple files. e.g.:
85
+ // - should the user pass a prefix?, or
86
+ // - should the ensure there's a unique top-level classname on each file
87
+ // TODO ignore rules in comments?
88
+
89
+ export function adoptCSS(sheet) {
90
+ document.adoptedStyleSheets.push(sheet)
91
+ Object.assign(sheet, extractClassNames(sheet))
92
+ }
93
+
94
+ export function extractClassNames({ cssRules }) {
95
+ // Class names must begin with _ or a letter, then it can have numbers and hyphens
96
+ const reClassName = /(?:^|[\s,{>])&?\s*\.([a-zA-Z_][\w-]*)/g
97
+
98
+ const cNames = {}
99
+ let match
100
+ for (const rule of cssRules)
101
+ while (match = reClassName.exec(rule.cssText))
102
+ cNames[match[1]] = match[1]
103
+ return cNames
104
+ }
105
+
@@ -14,18 +14,10 @@ export const IndexHtml = hotReloadEnabled => `
14
14
  <head>
15
15
  <meta charset="UTF-8">
16
16
  <base href="${API.dashboard}/">
17
-
18
- <link rel="stylesheet" href="styles.css">
17
+
19
18
  <script type="module" src="app.js"></script>
20
-
21
19
  <link rel="preload" href="${API.state}" as="fetch" crossorigin>
22
20
 
23
- <link rel="modulepreload" href="ApiConstants.js">
24
- <link rel="modulepreload" href="ApiCommander.js">
25
- <link rel="modulepreload" href="Filename.js">
26
- <link rel="modulepreload" href="app-store.js">
27
- <link rel="modulepreload" href="dom-utils.js">
28
-
29
21
  <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">
30
22
  <meta name="viewport" content="width=device-width, initial-scale=1">
31
23
  <meta name="description" content="HTTP Mock Server">
@@ -5,6 +5,7 @@
5
5
 
6
6
  @media (prefers-color-scheme: light) {
7
7
  :root {
8
+ color-scheme: light;
8
9
  --color4xxBackground: #ffedd1;
9
10
  --colorAccent: #0b61ec;
10
11
  --colorBackground: #fff;
@@ -27,6 +28,7 @@
27
28
  }
28
29
  @media (prefers-color-scheme: dark) {
29
30
  :root {
31
+ color-scheme: dark;
30
32
  --color4xxBackground: #68554a;
31
33
  --colorAccent: #2495ff;
32
34
  --colorBackground: #181818;
@@ -52,9 +54,6 @@ html,
52
54
  body {
53
55
  overflow: hidden;
54
56
  height: 100%;
55
- padding: 0;
56
- margin: 0;
57
- background: var(--colorHeaderBackground);
58
57
  font-size: 12px;
59
58
  }
60
59
  body {
@@ -72,7 +71,6 @@ body {
72
71
  margin: 0;
73
72
  font-family: inherit;
74
73
  font-size: 100%;
75
- outline: 0;
76
74
  scrollbar-width: thin;
77
75
  }
78
76
 
@@ -88,6 +86,7 @@ a,
88
86
  select,
89
87
  button,
90
88
  input[type=checkbox] {
89
+ outline: 0;
91
90
  cursor: pointer;
92
91
  }
93
92
 
@@ -100,6 +99,11 @@ input[type=checkbox]:active {
100
99
 
101
100
  a {
102
101
  text-decoration: none;
102
+ color: var(--colorAccent);
103
+ }
104
+
105
+ input[type="number"]:not(:focus) {
106
+ -moz-appearance: textfield;
103
107
  }
104
108
 
105
109
  select {
@@ -128,7 +132,7 @@ select {
128
132
 
129
133
  header {
130
134
  display: flex;
131
- width: 100vw;
135
+ flex: 0 0 100%;
132
136
  padding: 16px;
133
137
  border-bottom: 1px solid var(--colorSecondaryActionBorder);
134
138
  background: var(--colorHeaderBackground);
@@ -143,6 +147,10 @@ header {
143
147
  pointer-events: none;
144
148
  fill: var(--colorText);
145
149
  }
150
+
151
+ @media (max-width: 830px) {
152
+ display: none;
153
+ }
146
154
  }
147
155
 
148
156
  > div {
@@ -151,16 +159,11 @@ header {
151
159
  flex-wrap: wrap;
152
160
  align-items: flex-end;
153
161
  gap: 16px 8px;
154
- }
155
162
 
156
- @media (max-width: 830px) {
157
- .Logo {
158
- display: none;
159
- }
160
- }
161
- @media (max-width: 690px) {
162
- > div .MenuTrigger {
163
- margin-left: unset;
163
+ @media (max-width: 690px) {
164
+ .MenuTrigger {
165
+ margin-left: unset;
166
+ }
164
167
  }
165
168
  }
166
169
 
@@ -194,11 +197,6 @@ header {
194
197
  border-radius: var(--radius);
195
198
  }
196
199
 
197
- select:enabled:hover {
198
- border-color: var(--colorSecondaryActionBorder);
199
- background: var(--colorHover);
200
- }
201
-
202
200
  &.GlobalDelayField {
203
201
  position: relative;
204
202
  width: 76px;
@@ -263,8 +261,12 @@ header {
263
261
  input:enabled + .checkboxBody {
264
262
  cursor: pointer;
265
263
  }
264
+ input:disabled {
265
+ cursor: not-allowed;
266
+ }
266
267
  input:disabled + .checkboxBody {
267
268
  opacity: 0.8;
269
+ cursor: not-allowed;
268
270
  }
269
271
  }
270
272
  }
@@ -329,10 +331,6 @@ header {
329
331
  gap: 12px;
330
332
  text-align: left;
331
333
 
332
- a {
333
- color: var(--colorAccent);
334
- }
335
-
336
334
  .GroupByMethod {
337
335
  display: flex;
338
336
  align-items: center;
@@ -356,10 +354,9 @@ main {
356
354
  }
357
355
 
358
356
  .leftSide {
359
- min-width: 100%;
360
- min-height: 50%;
361
- max-height: 50%;
362
- border: 0;
357
+ width: 100% !important;
358
+ height: 50%;
359
+ border-right: 0;
363
360
  }
364
361
  }
365
362
 
@@ -430,7 +427,6 @@ main {
430
427
  }
431
428
  }
432
429
  }
433
-
434
430
  @keyframes _kfRowIn {
435
431
  to {
436
432
  opacity: 1;
@@ -459,7 +455,6 @@ main {
459
455
  padding: 6px 8px;
460
456
  margin-left: 4px;
461
457
  border-radius: var(--radius);
462
- color: var(--colorAccent);
463
458
  word-break: break-word;
464
459
 
465
460
 
@@ -651,9 +646,7 @@ main {
651
646
 
652
647
 
653
648
  .PayloadViewer {
654
- display: flex;
655
649
  height: 100%;
656
- flex-direction: column;
657
650
  padding-top: 16px;
658
651
 
659
652
  > h2 {
@@ -750,7 +743,6 @@ main {
750
743
  background: rgba(0, 0, 0, 0.5);
751
744
  }
752
745
  }
753
-
754
746
  @keyframes _kfToastIn {
755
747
  to {
756
748
  opacity: 1;
@@ -10,7 +10,7 @@ async function longPollDevChanges() {
10
10
 
11
11
  const file = await response.json() || ''
12
12
  if (file.endsWith('.css')) {
13
- hotReloadCSS(file)
13
+ await hotReloadCSS(file)
14
14
  longPollDevChanges()
15
15
  }
16
16
  else if (file)
@@ -24,10 +24,7 @@ async function longPollDevChanges() {
24
24
  }
25
25
  }
26
26
 
27
- function hotReloadCSS(file) {
28
- const link = document.querySelector(`link[href*="${file}"]`)
29
- if (link) {
30
- const [url] = link.href.split('?')
31
- link.href = url + '?' + Date.now()
32
- }
27
+ async function hotReloadCSS(file) {
28
+ const mod = await import(`./${file}?${Date.now()}`, { with: { type: 'css' } })
29
+ document.adoptedStyleSheets = [mod.default]
33
30
  }