mockaton 11.3.1 → 11.4.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,4 +1,21 @@
1
- <img src="src/client/logo.svg" alt="Mockaton Logo" width="210" style="margin-top: 30px"/>
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>
18
+
2
19
 
3
20
  ![NPM Version](https://img.shields.io/npm/v/mockaton)
4
21
  [![Test](https://github.com/ericfortis/mockaton/actions/workflows/test.yml/badge.svg)](https://github.com/ericfortis/mockaton/actions/workflows/test.yml)
@@ -50,9 +67,9 @@ curl localhost:2020/api/user
50
67
 
51
68
 
52
69
  <picture>
53
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp761x740.light.gold.png">
54
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp761x740.dark.gold.png">
55
- <img alt="Mockaton Dashboard" src="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp761x740.dark.gold.png">
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">
56
73
  </picture>
57
74
 
58
75
  On the dashboard you can:
package/index.d.ts CHANGED
@@ -99,6 +99,7 @@ export interface State {
99
99
  comments: string[]
100
100
 
101
101
  delay: number
102
+ delayJitter: number
102
103
 
103
104
  collectProxied: boolean
104
105
  proxyFallback: string
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.3.1",
5
+ "version": "11.4.1",
6
6
  "exports": {
7
7
  ".": {
8
8
  "import": "./index.js",
@@ -23,6 +23,9 @@ export class Commander {
23
23
 
24
24
  /** @returns {Promise<Response>} */
25
25
  setGlobalDelay = delay => this.#patch(API.globalDelay, delay)
26
+
27
+ /** @returns {Promise<Response>} */
28
+ setGlobalDelayJitter = jitterPct => this.#patch(API.globalDelayJitter, jitterPct)
26
29
 
27
30
  /** @returns {Promise<Response>} */
28
31
  setCorsAllowed = value => this.#patch(API.cors, value)
@@ -12,6 +12,7 @@ export const API = {
12
12
  delayStatic: MOUNT + '/delay-static',
13
13
  fallback: MOUNT + '/fallback',
14
14
  globalDelay: MOUNT + '/global-delay',
15
+ globalDelayJitter: MOUNT + '/global-delay-jitter',
15
16
  proxied: MOUNT + '/proxied',
16
17
  reset: MOUNT + '/reset',
17
18
  select: MOUNT + '/select',
@@ -16,6 +16,7 @@ export const store = {
16
16
  cookies: [],
17
17
  comments: [],
18
18
  delay: 0,
19
+ delayJitter: 0,
19
20
 
20
21
  collectProxied: false,
21
22
  proxyFallback: '',
@@ -84,6 +85,15 @@ export const store = {
84
85
  }
85
86
  catch (error) { store.onError(error) }
86
87
  },
88
+
89
+ async setGlobalDelayJitter(value) {
90
+ try {
91
+ const response = await api.setGlobalDelayJitter(value)
92
+ if (!response.ok) throw response
93
+ store.delayJitter = value
94
+ }
95
+ catch (error) { store.onError(error) }
96
+ },
87
97
 
88
98
  async selectCookie(name) {
89
99
  try {
package/src/client/app.js CHANGED
@@ -17,6 +17,8 @@ const CSS = {
17
17
  FallbackBackend: null,
18
18
  Field: null,
19
19
  GlobalDelayField: null,
20
+ GlobalDelayJitterField: null,
21
+ GlobalDelayWrap: null,
20
22
  GroupByMethod: null,
21
23
  InternalServerErrorToggler: null,
22
24
  Logo: null,
@@ -111,21 +113,20 @@ function Header() {
111
113
  className: CSS.Logo,
112
114
  href: 'https://mockaton.com'
113
115
  },
114
- r('object', {
115
- data: 'logo.svg',
116
- type: 'image/svg+xml',
117
- width: 120,
118
- height: 22
119
- })),
116
+ Logo()),
120
117
  r('div', null,
121
- GlobalDelayField(),
118
+ r('div', className(CSS.GlobalDelayWrap),
119
+ GlobalDelayField(),
120
+ GlobalDelayJitterField()),
122
121
  BulkSelector(),
123
122
  CookieSelector(),
124
123
  ProxyFallbackField(),
125
124
  ResetButton(),
126
- SettingsMenuTrigger())))
125
+ SettingsMenuTrigger()
126
+ )))
127
127
  }
128
128
 
129
+
129
130
  function GlobalDelayField() {
130
131
  function onChange() {
131
132
  store.setGlobalDelay(this.valueAsNumber)
@@ -142,6 +143,7 @@ function GlobalDelayField() {
142
143
  r('label', className(CSS.Field, CSS.GlobalDelayField),
143
144
  r('span', null, t`Delay (ms)`),
144
145
  r('input', {
146
+ name: 'delay',
145
147
  type: 'number',
146
148
  min: 0,
147
149
  step: 100,
@@ -152,6 +154,38 @@ function GlobalDelayField() {
152
154
  })))
153
155
  }
154
156
 
157
+ function GlobalDelayJitterField() {
158
+ function onChange() {
159
+ this.value = this.valueAsNumber.toFixed(0)
160
+ this.value = Math.max(0, this.valueAsNumber)
161
+ this.value = Math.min(300, this.valueAsNumber)
162
+ store.setGlobalDelayJitter(this.valueAsNumber / 100)
163
+ }
164
+ function onWheel(event) {
165
+ if (event.deltaY > 0)
166
+ this.stepUp()
167
+ else
168
+ this.stepDown()
169
+ clearTimeout(onWheel.timer)
170
+ onWheel.timer = setTimeout(onChange.bind(this), 300)
171
+ }
172
+ return (
173
+ r('label', className(CSS.Field, CSS.GlobalDelayJitterField),
174
+ r('span', null, t`Max Jitter %`),
175
+ r('input', {
176
+ name: 'delay-jitter',
177
+ type: 'number',
178
+ min: 0,
179
+ max: 300,
180
+ step: 10,
181
+ autocomplete: 'none',
182
+ value: (store.delayJitter * 100).toFixed(0),
183
+ onChange,
184
+ onWheel: [onWheel, { passive: true }]
185
+ })))
186
+ }
187
+
188
+
155
189
  function BulkSelector() {
156
190
  const { comments } = store
157
191
  const firstOption = t`Pick Comment…`
@@ -208,6 +242,7 @@ function ProxyFallbackField() {
208
242
  r('label', null,
209
243
  r('span', null, t`Fallback`),
210
244
  r('input', {
245
+ name: 'fallback',
211
246
  type: 'url',
212
247
  autocomplete: 'none',
213
248
  placeholder: t`Type backend address`,
@@ -221,6 +256,7 @@ function SaveProxiedCheckbox(ref) {
221
256
  return (
222
257
  r('label', className(CSS.SaveProxiedCheckbox),
223
258
  r('input', {
259
+ name: 'save-proxied',
224
260
  ref,
225
261
  type: 'checkbox',
226
262
  disabled: !store.canProxy,
@@ -268,6 +304,7 @@ function SettingsMenu(id) {
268
304
  r('div', null,
269
305
  r('label', className(CSS.GroupByMethod),
270
306
  r('input', {
307
+ name: 'group-by-method',
271
308
  ref: firstInputRef,
272
309
  type: 'checkbox',
273
310
  checked: store.groupByMethod,
@@ -721,7 +758,15 @@ ErrorToast.close = () => {
721
758
  }
722
759
 
723
760
 
724
- /** # Icons */
761
+ /** # Graphics */
762
+
763
+ function Logo() {
764
+ return (
765
+ s('svg', { viewBox: '0 0 556 100' },
766
+ s('path', { 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' }),
767
+ s('path', { opacity: 0.75, 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' }),
768
+ s('path', { 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' })))
769
+ }
725
770
 
726
771
  function TimerIcon() {
727
772
  return (
@@ -923,7 +968,3 @@ function SyntaxXML(xml) {
923
968
  frag.normalize()
924
969
  return frag
925
970
  }
926
-
927
-
928
- /*
929
- */
@@ -25,7 +25,6 @@ export const IndexHtml = hotReloadEnabled => `
25
25
  <link rel="modulepreload" href="Filename.js">
26
26
  <link rel="modulepreload" href="app-store.js">
27
27
  <link rel="modulepreload" href="dom-utils.js">
28
- <link rel="preload" href="logo.svg" as="image">
29
28
 
30
29
  <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">
31
30
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -137,9 +137,11 @@ header {
137
137
  align-self: end;
138
138
  margin-right: 22px;
139
139
  margin-bottom: 3px;
140
-
141
- object {
140
+
141
+ svg {
142
+ width: 120px;
142
143
  pointer-events: none;
144
+ fill: var(--colorText);
143
145
  }
144
146
  }
145
147
 
@@ -151,25 +153,21 @@ header {
151
153
  gap: 16px 8px;
152
154
  }
153
155
 
154
- @media (max-width: 760px) {
155
- > img {
156
- width: 100px;
157
- align-self: center;
158
- }
159
-
160
- > div {
161
- width: 400px;
162
- .MenuTrigger {
163
- margin-left: unset;
164
- }
156
+ @media (max-width: 830px) {
157
+ .Logo {
158
+ display: none;
165
159
  }
166
160
  }
167
- @media (max-width: 424px) {
168
- > img {
169
- display: none;
161
+ @media (max-width: 690px) {
162
+ > div .MenuTrigger {
163
+ margin-left: unset;
170
164
  }
171
165
  }
172
166
 
167
+ .GlobalDelayWrap {
168
+ display: flex;
169
+ }
170
+
173
171
  .Field {
174
172
  width: 116px;
175
173
 
@@ -202,10 +200,13 @@ header {
202
200
  }
203
201
 
204
202
  &.GlobalDelayField {
203
+ position: relative;
205
204
  width: 76px;
206
205
 
207
- input[type=number] {
206
+ input {
208
207
  padding-right: 6px;
208
+ border-bottom-right-radius: 0;
209
+ border-top-right-radius: 0;
209
210
  }
210
211
 
211
212
  svg {
@@ -215,6 +216,25 @@ header {
215
216
  stroke-width: 3px;
216
217
  border-radius: 50%;
217
218
  }
219
+
220
+ &:focus-within {
221
+ z-index: 100;
222
+ }
223
+ }
224
+
225
+ &.GlobalDelayJitterField {
226
+ width: 80px;
227
+ span {
228
+ margin-left: 4px;
229
+ }
230
+ input {
231
+ border-left: 2px solid transparent;
232
+ border-bottom-left-radius: 0;
233
+ border-top-left-radius: 0;
234
+ }
235
+ &:focus-within {
236
+ z-index: 100;
237
+ }
218
238
  }
219
239
 
220
240
  &.CookieSelector {
@@ -223,7 +243,7 @@ header {
223
243
 
224
244
  &.FallbackBackend {
225
245
  position: relative;
226
- width: 160px;
246
+ width: 150px;
227
247
 
228
248
  .SaveProxiedCheckbox {
229
249
  position: absolute;
package/src/server/Api.js CHANGED
@@ -39,6 +39,7 @@ export const apiPatchReqs = new Map([
39
39
  [API.reset, reinitialize],
40
40
  [API.cookies, selectCookie],
41
41
  [API.globalDelay, setGlobalDelay],
42
+ [API.globalDelayJitter, setGlobalDelayJitter],
42
43
 
43
44
  [API.fallback, setProxyFallback],
44
45
  [API.collectProxied, setCollectProxied],
@@ -117,6 +118,17 @@ async function setGlobalDelay(req, response) {
117
118
  }
118
119
  }
119
120
 
121
+ async function setGlobalDelayJitter(req, response) {
122
+ const jitter = await req.json()
123
+
124
+ if (!ConfigValidator.delayJitter(jitter))
125
+ response.unprocessable(`Expected 0 to 3 float for "delayJitter"`)
126
+ else {
127
+ config.delayJitter = jitter
128
+ response.ok()
129
+ }
130
+ }
131
+
120
132
 
121
133
  async function selectCookie(req, response) {
122
134
  const cookieKey = await req.json()
@@ -12,6 +12,7 @@ export const API = {
12
12
  delayStatic: MOUNT + '/delay-static',
13
13
  fallback: MOUNT + '/fallback',
14
14
  globalDelay: MOUNT + '/global-delay',
15
+ globalDelayJitter: MOUNT + '/global-delay-jitter',
15
16
  proxied: MOUNT + '/proxied',
16
17
  reset: MOUNT + '/reset',
17
18
  select: MOUNT + '/select',
@@ -309,7 +309,7 @@ describe('Cookie', () => {
309
309
 
310
310
  describe('Delay', () => {
311
311
  describe('Set Global Delay', () => {
312
- test('422 for invalid global delay value', async () => {
312
+ test('422 for invalid value', async () => {
313
313
  const r = await api.setGlobalDelay('not-a-number')
314
314
  equal(r.status, 422)
315
315
  equal(await r.text(), 'Expected non-negative integer for "delay"')
@@ -321,6 +321,19 @@ describe('Delay', () => {
321
321
  })
322
322
  })
323
323
 
324
+ describe('Set Global Delay Jitter', () => {
325
+ test('422 for invalid value', async () => {
326
+ const r = await api.setGlobalDelayJitter('not-a-number')
327
+ equal(r.status, 422)
328
+ equal(await r.text(), 'Expected 0 to 3 float for "delayJitter"')
329
+ })
330
+ test('200 for valid value', async () => {
331
+ const r = await api.setGlobalDelayJitter(0.1)
332
+ equal(r.status, 200)
333
+ equal((await fetchState()).delayJitter, 0.1)
334
+ })
335
+ })
336
+
324
337
  test('updates route delay', async () => {
325
338
  const fx = new Fixture('route-delay.GET.200.json')
326
339
  await fx.sync()
@@ -1,18 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg width="556" height="100" version="1.1" viewBox="0 0 556 100" xmlns="http://www.w3.org/2000/svg">
3
- <style>
4
- @media (prefers-color-scheme: light) { :root { --color: #333 } }
5
- @media (prefers-color-scheme: dark) { :root { --color: #eee } }
6
- path {
7
- fill: #777;
8
- fill: var(--color);
9
- }
10
- </style>
11
- <path
12
- 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"/>
13
- <path
14
- 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"
15
- opacity="0.75"/>
16
- <path
17
- 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"/>
18
- </svg>