mockaton 13.2.0 → 13.3.0
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 +5 -3
- package/src/client/ApiCommander.js +0 -1
- package/src/client/app-payload-viewer.js +1 -1
- package/src/client/app-store.js +39 -14
- package/src/client/app.css +76 -2
- package/src/client/app.js +24 -3
- package/src/client/graphics.js +6 -0
- package/src/server/Api.js +1 -2
- package/src/server/MockDispatcher.js +2 -5
- package/src/server/Mockaton.js +1 -2
- package/src/server/Mockaton.test.js +11 -37
- package/src/server/mockBrokersCollection.js +2 -2
- package/src/server/utils/HttpServerResponse.js +2 -2
- package/src/server/utils/fs.js +0 -1
- package/www/src/assets/openapi.json +661 -0
package/package.json
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "HTTP Mock Server",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "13.
|
|
5
|
+
"version": "13.3.0",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"import": "./index.js",
|
|
9
9
|
"types": "./index.d.ts"
|
|
10
|
-
}
|
|
10
|
+
},
|
|
11
|
+
"./openapi.json": "./www/src/assets/openapi.json"
|
|
11
12
|
},
|
|
12
13
|
"files": [
|
|
13
14
|
"src",
|
|
14
15
|
"index.js",
|
|
15
|
-
"index.d.ts"
|
|
16
|
+
"index.d.ts",
|
|
17
|
+
"www/src/assets/openapi.json"
|
|
16
18
|
],
|
|
17
19
|
"license": "MIT",
|
|
18
20
|
"homepage": "https://mockaton.com",
|
|
@@ -42,7 +42,6 @@ export class Commander {
|
|
|
42
42
|
/** @returns {JsonPromise<ClientMockBroker>} */
|
|
43
43
|
toggleStatus = (method, urlMask, status) => this.#patch(API.toggleStatus, [method, urlMask, status])
|
|
44
44
|
|
|
45
|
-
// TODO change Status or Toggle404?
|
|
46
45
|
|
|
47
46
|
/** @returns {JsonPromise<ClientMockBroker>} */
|
|
48
47
|
setRouteIsProxied = (method, urlMask, proxied) => this.#patch(API.proxied, [method, urlMask, proxied])
|
|
@@ -132,7 +132,7 @@ async function updatePayloadViewer(proxied, file, response) {
|
|
|
132
132
|
else if (['text/xml', 'application/xml'].includes(mime))
|
|
133
133
|
codeRef.elem.replaceChildren(SyntaxXML(await bodyAsText()))
|
|
134
134
|
|
|
135
|
-
else if (mime.startsWith('text/'))
|
|
135
|
+
else if (mime.startsWith('text/') || mime === 'application/yaml')
|
|
136
136
|
codeRef.elem.textContent = await bodyAsText()
|
|
137
137
|
|
|
138
138
|
else
|
package/src/client/app-store.js
CHANGED
|
@@ -33,6 +33,16 @@ export const store = {
|
|
|
33
33
|
store.render()
|
|
34
34
|
},
|
|
35
35
|
|
|
36
|
+
collapsedFolders: new Set(JSON.parse(globalThis.localStorage?.getItem('collapsedFolders') || '[]')),
|
|
37
|
+
setFolderCollapsed(folder, collapsed) {
|
|
38
|
+
if (collapsed)
|
|
39
|
+
store.collapsedFolders.add(folder)
|
|
40
|
+
else
|
|
41
|
+
store.collapsedFolders.delete(folder)
|
|
42
|
+
|
|
43
|
+
globalThis.localStorage?.setItem('collapsedFolders', JSON.stringify([...store.collapsedFolders]))
|
|
44
|
+
},
|
|
45
|
+
|
|
36
46
|
chosenLink: { method: '', urlMask: '' },
|
|
37
47
|
setChosenLink(method, urlMask) {
|
|
38
48
|
store.chosenLink = { method, urlMask }
|
|
@@ -112,27 +122,40 @@ export const store = {
|
|
|
112
122
|
},
|
|
113
123
|
|
|
114
124
|
|
|
125
|
+
_dittoCache: new Map(),
|
|
126
|
+
|
|
115
127
|
brokerFor(method, urlMask) {
|
|
116
128
|
return store.brokersByMethod[method]?.[urlMask]
|
|
117
129
|
},
|
|
118
130
|
|
|
131
|
+
brokerAsRow(method, urlMask) {
|
|
132
|
+
const b = store.brokerFor(method, urlMask)
|
|
133
|
+
const r = new BrokerRowModel(b, store.canProxy)
|
|
134
|
+
r.setUrlMaskDittoed(store._dittoCache.get(r.key))
|
|
135
|
+
return r
|
|
136
|
+
},
|
|
137
|
+
|
|
119
138
|
_setBroker(broker) {
|
|
120
139
|
const { method, urlMask } = parseFilename(broker.file)
|
|
121
140
|
store.brokersByMethod[method] ??= {}
|
|
122
141
|
store.brokersByMethod[method][urlMask] = broker
|
|
123
142
|
},
|
|
124
143
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
folderGroupsByMethod(method) {
|
|
145
|
+
const groups = []
|
|
146
|
+
let g = null
|
|
147
|
+
for (const row of store._brokersAsRowsByMethod(method)) {
|
|
148
|
+
const folder = row.urlMask.substring(0, row.urlMask.lastIndexOf('/') + 1)
|
|
149
|
+
if (!g || g.folder !== folder) {
|
|
150
|
+
g = { folder, children: [] }
|
|
151
|
+
groups.push(g)
|
|
152
|
+
}
|
|
153
|
+
g.children.push(row)
|
|
154
|
+
}
|
|
155
|
+
return groups
|
|
133
156
|
},
|
|
134
157
|
|
|
135
|
-
|
|
158
|
+
_brokersAsRowsByMethod(method) {
|
|
136
159
|
const rows = store._brokersAsArray(method)
|
|
137
160
|
.map(b => new BrokerRowModel(b, store.canProxy))
|
|
138
161
|
.sort((a, b) => a.urlMask.localeCompare(b.urlMask))
|
|
@@ -145,12 +168,14 @@ export const store = {
|
|
|
145
168
|
return rows
|
|
146
169
|
},
|
|
147
170
|
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
171
|
+
_brokersAsArray(byMethod = '*') {
|
|
172
|
+
const arr = []
|
|
173
|
+
for (const [method, brokers] of Object.entries(store.brokersByMethod))
|
|
174
|
+
if (byMethod === '*' || byMethod === method)
|
|
175
|
+
arr.push(...Object.values(brokers))
|
|
176
|
+
return arr
|
|
153
177
|
},
|
|
178
|
+
|
|
154
179
|
|
|
155
180
|
previewLink(method, urlMask) {
|
|
156
181
|
store.setChosenLink(method, urlMask)
|
package/src/client/app.css
CHANGED
|
@@ -423,7 +423,7 @@ main {
|
|
|
423
423
|
padding-bottom: 4px;
|
|
424
424
|
padding-left: 1px;
|
|
425
425
|
border-top: 24px solid transparent;
|
|
426
|
-
margin-left:
|
|
426
|
+
margin-left: 94px;
|
|
427
427
|
font-weight: bold;
|
|
428
428
|
text-align: left;
|
|
429
429
|
|
|
@@ -438,7 +438,7 @@ main {
|
|
|
438
438
|
|
|
439
439
|
.TableRow {
|
|
440
440
|
display: flex;
|
|
441
|
-
|
|
441
|
+
margin-left: 24px;
|
|
442
442
|
|
|
443
443
|
&.animIn {
|
|
444
444
|
opacity: 0;
|
|
@@ -446,7 +446,79 @@ main {
|
|
|
446
446
|
animation: _kfRowIn 180ms ease-in-out forwards;
|
|
447
447
|
}
|
|
448
448
|
}
|
|
449
|
+
|
|
450
|
+
.FolderGroup {
|
|
451
|
+
position: relative;
|
|
452
|
+
|
|
453
|
+
> summary {
|
|
454
|
+
left: 0;
|
|
455
|
+
display: flex;
|
|
456
|
+
overflow: hidden;
|
|
457
|
+
align-items: center;
|
|
458
|
+
padding: 5px 0;
|
|
459
|
+
font-size: 12px;
|
|
460
|
+
list-style: none;
|
|
461
|
+
cursor: pointer;
|
|
462
|
+
user-select: none;
|
|
463
|
+
color: var(--colorLabel);
|
|
464
|
+
white-space: nowrap;
|
|
465
|
+
text-overflow: ellipsis;
|
|
466
|
+
border-radius: var(--radius);
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
&:active {
|
|
470
|
+
cursor: grabbing;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
&::-webkit-details-marker {
|
|
474
|
+
display: none;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
&:hover {
|
|
478
|
+
color: var(--colorText);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.FolderName {
|
|
482
|
+
margin-left: 125px;
|
|
483
|
+
&.groupedByMethod {
|
|
484
|
+
margin-left: 79px;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.FolderChevron {
|
|
489
|
+
display: flex;
|
|
490
|
+
width: 16px;
|
|
491
|
+
height: 16px;
|
|
492
|
+
flex-shrink: 0;
|
|
493
|
+
align-items: center;
|
|
494
|
+
justify-content: center;
|
|
495
|
+
opacity: .7;
|
|
496
|
+
transition: transform cubic-bezier(.2, .7, .8, 1.4) 400ms;
|
|
497
|
+
transform: rotate(-90deg);
|
|
498
|
+
|
|
499
|
+
svg {
|
|
500
|
+
width: 100%;
|
|
501
|
+
height: 100%;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
&[open] > summary {
|
|
507
|
+
position: absolute;
|
|
508
|
+
top: 0;
|
|
509
|
+
left: 0;
|
|
510
|
+
width: 16px;
|
|
511
|
+
|
|
512
|
+
.FolderChevron {
|
|
513
|
+
transform: rotate(0deg);
|
|
514
|
+
}
|
|
515
|
+
.FolderName {
|
|
516
|
+
display: none;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
449
520
|
}
|
|
521
|
+
|
|
450
522
|
@keyframes _kfRowIn {
|
|
451
523
|
to {
|
|
452
524
|
opacity: 1;
|
|
@@ -458,6 +530,7 @@ main {
|
|
|
458
530
|
overflow: hidden;
|
|
459
531
|
min-width: 38px;
|
|
460
532
|
padding: 4px 0;
|
|
533
|
+
margin-top: 3px;
|
|
461
534
|
margin-right: 8px;
|
|
462
535
|
color: var(--colorLabel);
|
|
463
536
|
font-size: 11px;
|
|
@@ -523,6 +596,7 @@ main {
|
|
|
523
596
|
|
|
524
597
|
.Toggler {
|
|
525
598
|
display: flex;
|
|
599
|
+
margin-top: 3px;
|
|
526
600
|
|
|
527
601
|
input {
|
|
528
602
|
/* For click drag target */
|
package/src/client/app.js
CHANGED
|
@@ -3,8 +3,8 @@ import { createElement as r, t, classNames, restoreFocus, Fragment, defineClassN
|
|
|
3
3
|
import { store } from './app-store.js'
|
|
4
4
|
import { API } from './ApiConstants.js'
|
|
5
5
|
import { Header } from './app-header.js'
|
|
6
|
-
import { TimerIcon, CloudIcon } from './graphics.js'
|
|
7
6
|
import { PayloadViewer, previewMock } from './app-payload-viewer.js'
|
|
7
|
+
import { TimerIcon, CloudIcon, ChevronDownIcon } from './graphics.js'
|
|
8
8
|
|
|
9
9
|
import CSS from './app.css' with { type: 'css' }
|
|
10
10
|
document.adoptedStyleSheets.push(CSS)
|
|
@@ -100,9 +100,30 @@ function MockList() {
|
|
|
100
100
|
r('div', {
|
|
101
101
|
className: classNames(CSS.TableHeading, store.canProxy && CSS.canProxy)
|
|
102
102
|
}, method),
|
|
103
|
-
store.
|
|
103
|
+
FolderGroups(store.folderGroupsByMethod(method))))
|
|
104
104
|
|
|
105
|
-
return store.
|
|
105
|
+
return FolderGroups(store.folderGroupsByMethod('*'))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function FolderGroups(groups) {
|
|
109
|
+
return groups.map(({ folder, children }) => {
|
|
110
|
+
if (children.length === 1)
|
|
111
|
+
return Row(children[0], 0)
|
|
112
|
+
|
|
113
|
+
return r('details', {
|
|
114
|
+
className: CSS.FolderGroup,
|
|
115
|
+
open: !store.collapsedFolders.has(folder),
|
|
116
|
+
onToggle() {
|
|
117
|
+
// TODO alt+click exclusive open
|
|
118
|
+
store.setFolderCollapsed(folder, !this.open)
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
r('summary', null,
|
|
122
|
+
r('span', { className: CSS.FolderChevron }, ChevronDownIcon()),
|
|
123
|
+
r('span', { className: classNames(CSS.FolderName, store.groupByMethod && CSS.groupedByMethod) },
|
|
124
|
+
folder + '…')),
|
|
125
|
+
children.map(Row))
|
|
126
|
+
})
|
|
106
127
|
}
|
|
107
128
|
|
|
108
129
|
/**
|
package/src/client/graphics.js
CHANGED
|
@@ -27,3 +27,9 @@ export function HelpIcon() {
|
|
|
27
27
|
s('svg', { viewBox: '0 0 24 24' },
|
|
28
28
|
s('path', { d: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m1 17h-2v-2h2zm2.07-7.75-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25' })))
|
|
29
29
|
}
|
|
30
|
+
|
|
31
|
+
export function ChevronDownIcon() {
|
|
32
|
+
return (
|
|
33
|
+
s('svg', { viewBox: '0 0 24 24', stroke: 'currentColor', fill: 'none', 'stroke-width': '2' },
|
|
34
|
+
s('path', { d: 'M6 9l6 6 6-6' })))
|
|
35
|
+
}
|
package/src/server/Api.js
CHANGED
|
@@ -113,7 +113,6 @@ async function setGlobalDelay(req, response) {
|
|
|
113
113
|
response.unprocessable(`Expected non-negative integer for "delay"`)
|
|
114
114
|
else {
|
|
115
115
|
config.delay = delay
|
|
116
|
-
uiSyncVersion.increment()
|
|
117
116
|
response.ok()
|
|
118
117
|
uiSyncVersion.increment()
|
|
119
118
|
}
|
|
@@ -219,7 +218,7 @@ async function setRouteIsDelayed(req, response) {
|
|
|
219
218
|
else {
|
|
220
219
|
broker.setDelayed(delayed)
|
|
221
220
|
response.json(broker)
|
|
222
|
-
uiSyncVersion.increment()
|
|
221
|
+
uiSyncVersion.increment()
|
|
223
222
|
}
|
|
224
223
|
}
|
|
225
224
|
|
|
@@ -53,11 +53,8 @@ export async function dispatchMock(req, response) {
|
|
|
53
53
|
response.setHeader('Content-Type', mime)
|
|
54
54
|
response.setHeader('Content-Length', length(body))
|
|
55
55
|
|
|
56
|
-
setTimeout(() =>
|
|
57
|
-
|
|
58
|
-
? null
|
|
59
|
-
: body
|
|
60
|
-
), Number(broker.delayed && calcDelay()))
|
|
56
|
+
setTimeout(() => response.end(isHead ? null : body),
|
|
57
|
+
Number(broker.delayed && calcDelay()))
|
|
61
58
|
|
|
62
59
|
logger.accessMock(req.url, broker.file)
|
|
63
60
|
}
|
package/src/server/Mockaton.js
CHANGED
|
@@ -5,9 +5,8 @@ import pkgJSON from '../../package.json' with { type: 'json' }
|
|
|
5
5
|
|
|
6
6
|
import { logger } from './utils/logger.js'
|
|
7
7
|
import { ServerResponse } from './utils/HttpServerResponse.js'
|
|
8
|
-
import { IncomingMessage } from './utils/HttpIncomingMessage.js'
|
|
8
|
+
import { IncomingMessage, BodyReaderError, hasControlChars } from './utils/HttpIncomingMessage.js'
|
|
9
9
|
import { setCorsHeaders, isPreflight } from './utils/http-cors.js'
|
|
10
|
-
import { BodyReaderError, hasControlChars } from './utils/HttpIncomingMessage.js'
|
|
11
10
|
|
|
12
11
|
import { API } from '../client/ApiConstants.js'
|
|
13
12
|
|
|
@@ -61,29 +61,10 @@ function request(path, options = {}) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
class
|
|
65
|
-
dir = ''
|
|
66
|
-
urlMask = ''
|
|
67
|
-
method = ''
|
|
68
|
-
|
|
64
|
+
class Fixture {
|
|
69
65
|
constructor(file, body = '') {
|
|
70
66
|
this.file = file
|
|
71
67
|
this.body = body || `Body for ${file}`
|
|
72
|
-
}
|
|
73
|
-
write() { return api.writeMock(this.file, this.body) }
|
|
74
|
-
delete() { return api.deleteMock(this.file) }
|
|
75
|
-
|
|
76
|
-
request(options = {}) {
|
|
77
|
-
options.method ??= this.method
|
|
78
|
-
return request(this.urlMask, options)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class Fixture extends BaseFixture {
|
|
84
|
-
constructor(file, body = '') {
|
|
85
|
-
super(file, body)
|
|
86
|
-
this.dir = mocksDir
|
|
87
68
|
const t = parseFilename(file)
|
|
88
69
|
this.urlMask = t.urlMask
|
|
89
70
|
this.method = t.method
|
|
@@ -93,14 +74,12 @@ class Fixture extends BaseFixture {
|
|
|
93
74
|
async fetchBroker() {
|
|
94
75
|
return (await fetchState()).brokersByMethod?.[this.method]?.[this.urlMask]
|
|
95
76
|
}
|
|
96
|
-
}
|
|
77
|
+
write() { return api.writeMock(this.file, this.body) }
|
|
78
|
+
delete() { return api.deleteMock(this.file) }
|
|
97
79
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.dir = mocksDir
|
|
102
|
-
this.urlMask = '/' + file
|
|
103
|
-
this.method = 'GET'
|
|
80
|
+
request(options = {}) {
|
|
81
|
+
options.method ??= this.method
|
|
82
|
+
return request(this.urlMask, options)
|
|
104
83
|
}
|
|
105
84
|
}
|
|
106
85
|
|
|
@@ -614,8 +593,8 @@ describe('Dynamic Function Mocks', () => {
|
|
|
614
593
|
|
|
615
594
|
|
|
616
595
|
describe('Static Files', () => {
|
|
617
|
-
const fxsIndex = new
|
|
618
|
-
const fxsAsset = new
|
|
596
|
+
const fxsIndex = new Fixture('index.html', '<h1>Index</h1>')
|
|
597
|
+
const fxsAsset = new Fixture('asset-script.js', 'const a = 1')
|
|
619
598
|
before(async () => {
|
|
620
599
|
await api.reset()
|
|
621
600
|
await fxsIndex.write()
|
|
@@ -724,7 +703,7 @@ describe('Auto Status', () => {
|
|
|
724
703
|
})
|
|
725
704
|
|
|
726
705
|
test('toggling ON 404 for static routes', async () => {
|
|
727
|
-
const fx = new
|
|
706
|
+
const fx = new Fixture('static-404.txt')
|
|
728
707
|
await fx.write()
|
|
729
708
|
equal((await fx.request()).status, 200)
|
|
730
709
|
|
|
@@ -1040,10 +1019,6 @@ describe('Watch mocks API toggler', () => {
|
|
|
1040
1019
|
describe('Registering Mocks', () => {
|
|
1041
1020
|
// simulates user interacting with the file-system directly
|
|
1042
1021
|
class FixtureExternal extends Fixture {
|
|
1043
|
-
constructor(props) {
|
|
1044
|
-
super(props)
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
1022
|
async writeExternally() {
|
|
1048
1023
|
const nextVerPromise = resolveOnNextSyncVersion()
|
|
1049
1024
|
await sleep(0) // next macro task
|
|
@@ -1063,7 +1038,6 @@ describe('Registering Mocks', () => {
|
|
|
1063
1038
|
return new Promise(resolve => setTimeout(resolve, ms))
|
|
1064
1039
|
}
|
|
1065
1040
|
|
|
1066
|
-
|
|
1067
1041
|
const fxA = new FixtureExternal('register(default).GET.200.json')
|
|
1068
1042
|
const fxB = new FixtureExternal('register(alt).GET.200.json')
|
|
1069
1043
|
|
|
@@ -1138,9 +1112,9 @@ describe('Registering Mocks', () => {
|
|
|
1138
1112
|
})
|
|
1139
1113
|
|
|
1140
1114
|
test('responds when dir is renamed', async () => {
|
|
1141
|
-
const
|
|
1115
|
+
const prom = resolveOnNextSyncVersion(version + 2)
|
|
1142
1116
|
await renameInMocksDir('reg0', 'reg1')
|
|
1143
|
-
equal(await
|
|
1117
|
+
equal(await prom, version + 3)
|
|
1144
1118
|
|
|
1145
1119
|
const s = await fetchState()
|
|
1146
1120
|
equal(s.brokersByMethod.GET['/reg1/runtime0'].file, 'reg1/runtime0.GET.200.txt')
|
|
@@ -61,8 +61,8 @@ export function registerMock(file, isFromWatcher = false) {
|
|
|
61
61
|
|
|
62
62
|
export function unregisterMock(file) {
|
|
63
63
|
const broker = brokerByFilename(file)
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
64
|
+
const methodHasNoMoreMocks = broker?.unregister(file) // TODO or it was a directory of many mocks
|
|
65
|
+
if (methodHasNoMoreMocks) {
|
|
66
66
|
const { method, urlMask } = parseFilename(file)
|
|
67
67
|
delete collection[method][urlMask]
|
|
68
68
|
if (!Object.keys(collection[method]).length)
|
|
@@ -19,14 +19,14 @@ export class ServerResponse extends http.ServerResponse {
|
|
|
19
19
|
|
|
20
20
|
html(html, csp) {
|
|
21
21
|
logger.access(this)
|
|
22
|
-
this.setHeader('Content-Type', mimeFor('html'))
|
|
22
|
+
this.setHeader('Content-Type', mimeFor('.html'))
|
|
23
23
|
this.setHeader('Content-Security-Policy', csp)
|
|
24
24
|
this.end(html)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
json(payload) {
|
|
28
28
|
logger.access(this)
|
|
29
|
-
this.setHeader('Content-Type', mimeFor('json'))
|
|
29
|
+
this.setHeader('Content-Type', mimeFor('.json'))
|
|
30
30
|
this.end(JSON.stringify(payload))
|
|
31
31
|
}
|
|
32
32
|
|
package/src/server/utils/fs.js
CHANGED
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.1.2",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "Mockaton Control API",
|
|
5
|
+
"version": "1.0.0"
|
|
6
|
+
},
|
|
7
|
+
"servers": [
|
|
8
|
+
{
|
|
9
|
+
"url": "http://localhost:2020"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"paths": {
|
|
13
|
+
"/mockaton/reset": {
|
|
14
|
+
"patch": {
|
|
15
|
+
"summary": "Re-initialize Mockaton",
|
|
16
|
+
"description": "The selected mocks, cookies, and delays go back to default, but `proxyFallback`, `collectProxied`, and `corsAllowed` are not affected.",
|
|
17
|
+
"x-js-client-example": "await mockaton.reset()",
|
|
18
|
+
"responses": {
|
|
19
|
+
"200": {
|
|
20
|
+
"description": "OK"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"/mockaton/bulk-select-by-comment": {
|
|
26
|
+
"patch": {
|
|
27
|
+
"summary": "Select all mocks that have a particular comment",
|
|
28
|
+
"x-js-client-example": "await mockaton.bulkSelectByComment('(demo-a)')",
|
|
29
|
+
"requestBody": {
|
|
30
|
+
"required": true,
|
|
31
|
+
"content": {
|
|
32
|
+
"application/json": {
|
|
33
|
+
"schema": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Parentheses are optional, so you can pass a partial match. For example, passing `'demo-'` (without the final `a`) works too. On routes with many partial matches, their first mock in alphabetical order wins.",
|
|
36
|
+
"example": "(demo-a)"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"responses": {
|
|
42
|
+
"200": {
|
|
43
|
+
"$ref": "#/components/responses/Broker"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"/mockaton/select": {
|
|
49
|
+
"patch": {
|
|
50
|
+
"summary": "Select a mock file for a route",
|
|
51
|
+
"x-js-client-example": "await mockaton.select('api/user/avatar.GET.json')",
|
|
52
|
+
"requestBody": {
|
|
53
|
+
"required": true,
|
|
54
|
+
"content": {
|
|
55
|
+
"application/json": {
|
|
56
|
+
"schema": {
|
|
57
|
+
"$ref": "#/components/schemas/Filename"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"responses": {
|
|
63
|
+
"200": {
|
|
64
|
+
"$ref": "#/components/responses/Broker"
|
|
65
|
+
},
|
|
66
|
+
"422": {
|
|
67
|
+
"description": "Mock file doesn’t exist",
|
|
68
|
+
"content": {
|
|
69
|
+
"application/json": {
|
|
70
|
+
"schema": {
|
|
71
|
+
"type": "string"
|
|
72
|
+
},
|
|
73
|
+
"example": "Mock file does not exist"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"/mockaton/toggle-status": {
|
|
81
|
+
"patch": {
|
|
82
|
+
"summary": "Toggle a specific status for a route",
|
|
83
|
+
"description": "Selects the first found mock with the given status, which could be the autogenerated one. Or, selects the default file.",
|
|
84
|
+
"x-js-client-example": "await mockaton.toggleStatus('GET', '/api/user/friends', 500)",
|
|
85
|
+
"requestBody": {
|
|
86
|
+
"required": true,
|
|
87
|
+
"content": {
|
|
88
|
+
"application/json": {
|
|
89
|
+
"schema": {
|
|
90
|
+
"type": "array",
|
|
91
|
+
"minItems": 3,
|
|
92
|
+
"maxItems": 3,
|
|
93
|
+
"prefixItems": [
|
|
94
|
+
{
|
|
95
|
+
"$ref": "#/components/schemas/Method"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"$ref": "#/components/schemas/UrlMask"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"type": "number",
|
|
102
|
+
"description": "HTTP Status to toggle",
|
|
103
|
+
"example": 500
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"additionalItems": false
|
|
107
|
+
},
|
|
108
|
+
"example": [
|
|
109
|
+
"GET",
|
|
110
|
+
"/api/user",
|
|
111
|
+
500
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"responses": {
|
|
117
|
+
"200": {
|
|
118
|
+
"$ref": "#/components/responses/Broker"
|
|
119
|
+
},
|
|
120
|
+
"422": {
|
|
121
|
+
"description": "Route does not exist"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"/mockaton/proxied": {
|
|
127
|
+
"patch": {
|
|
128
|
+
"summary": "Set whether a route is proxied",
|
|
129
|
+
"description": "Applicable only when there’s a proxy fallback server URL already set. See `PATCH /mockaton/fallback`",
|
|
130
|
+
"x-js-client-example": "await mockaton.setRouteIsProxied('GET', '/api/user/friends', true)",
|
|
131
|
+
"requestBody": {
|
|
132
|
+
"required": true,
|
|
133
|
+
"content": {
|
|
134
|
+
"application/json": {
|
|
135
|
+
"schema": {
|
|
136
|
+
"type": "array",
|
|
137
|
+
"minItems": 3,
|
|
138
|
+
"maxItems": 3,
|
|
139
|
+
"prefixItems": [
|
|
140
|
+
{
|
|
141
|
+
"$ref": "#/components/schemas/Method"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"$ref": "#/components/schemas/UrlMask"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"type": "boolean",
|
|
148
|
+
"description": "proxied",
|
|
149
|
+
"example": true
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"additionalItems": false
|
|
153
|
+
},
|
|
154
|
+
"example": [
|
|
155
|
+
"GET",
|
|
156
|
+
"/api/user",
|
|
157
|
+
true
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"responses": {
|
|
163
|
+
"200": {
|
|
164
|
+
"$ref": "#/components/responses/Broker"
|
|
165
|
+
},
|
|
166
|
+
"422": {
|
|
167
|
+
"description": "Invalid request. Possible reasons:\n- Route does not exist\n- Expected boolean for `proxied`\n- No `proxyFallback` configured\n"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"/mockaton/delay": {
|
|
173
|
+
"patch": {
|
|
174
|
+
"summary": "Set whether a route is delayed",
|
|
175
|
+
"x-js-client-example": "await mockaton.setRouteIsDelayed('GET', '/api/user/friends', true)",
|
|
176
|
+
"requestBody": {
|
|
177
|
+
"required": true,
|
|
178
|
+
"content": {
|
|
179
|
+
"application/json": {
|
|
180
|
+
"schema": {
|
|
181
|
+
"type": "array",
|
|
182
|
+
"minItems": 3,
|
|
183
|
+
"maxItems": 3,
|
|
184
|
+
"prefixItems": [
|
|
185
|
+
{
|
|
186
|
+
"$ref": "#/components/schemas/Method"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"$ref": "#/components/schemas/UrlMask"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"type": "boolean",
|
|
193
|
+
"description": "delayed",
|
|
194
|
+
"example": true
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"additionalItems": false
|
|
198
|
+
},
|
|
199
|
+
"example": [
|
|
200
|
+
"GET",
|
|
201
|
+
"/api/user",
|
|
202
|
+
true
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"responses": {
|
|
208
|
+
"200": {
|
|
209
|
+
"$ref": "#/components/responses/Broker"
|
|
210
|
+
},
|
|
211
|
+
"422": {
|
|
212
|
+
"description": "Invalid request. Possible reasons:\n- Route does not exist\n- Expected boolean for `delayed`\n"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
"/mockaton/global-delay": {
|
|
218
|
+
"patch": {
|
|
219
|
+
"summary": "Set global delay for all responses",
|
|
220
|
+
"x-js-client-example": "await mockaton.setGlobalDelay(1500)",
|
|
221
|
+
"requestBody": {
|
|
222
|
+
"required": true,
|
|
223
|
+
"content": {
|
|
224
|
+
"application/json": {
|
|
225
|
+
"schema": {
|
|
226
|
+
"type": "integer",
|
|
227
|
+
"description": "Delay in milliseconds",
|
|
228
|
+
"example": 1500
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"responses": {
|
|
234
|
+
"200": {
|
|
235
|
+
"description": "OK"
|
|
236
|
+
},
|
|
237
|
+
"422": {
|
|
238
|
+
"description": "Expected non-negative integer"
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
"/mockaton/global-delay-jitter": {
|
|
244
|
+
"patch": {
|
|
245
|
+
"summary": "Set global delay jitter for all responses",
|
|
246
|
+
"x-js-client-example": "await mockaton.setGlobalDelayJitter(0.5)",
|
|
247
|
+
"requestBody": {
|
|
248
|
+
"required": true,
|
|
249
|
+
"content": {
|
|
250
|
+
"application/json": {
|
|
251
|
+
"schema": {
|
|
252
|
+
"type": "number",
|
|
253
|
+
"description": "0 to 3 float percent",
|
|
254
|
+
"example": 0.5
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
"responses": {
|
|
260
|
+
"200": {
|
|
261
|
+
"description": "OK"
|
|
262
|
+
},
|
|
263
|
+
"422": {
|
|
264
|
+
"description": "Expected 0 to 3 float"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"/mockaton/cors": {
|
|
270
|
+
"patch": {
|
|
271
|
+
"summary": "Enable or disable CORS",
|
|
272
|
+
"x-js-client-example": "await mockaton.setCorsAllowed(false)",
|
|
273
|
+
"requestBody": {
|
|
274
|
+
"required": true,
|
|
275
|
+
"content": {
|
|
276
|
+
"application/json": {
|
|
277
|
+
"schema": {
|
|
278
|
+
"type": "boolean",
|
|
279
|
+
"description": "Is enabled?"
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
"responses": {
|
|
285
|
+
"200": {
|
|
286
|
+
"description": "OK"
|
|
287
|
+
},
|
|
288
|
+
"422": {
|
|
289
|
+
"description": "Expected boolean"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"/mockaton/fallback": {
|
|
295
|
+
"patch": {
|
|
296
|
+
"summary": "Set proxy fallback address",
|
|
297
|
+
"x-js-client-example": "await mockaton.setProxyFallback('http://example.test')",
|
|
298
|
+
"requestBody": {
|
|
299
|
+
"required": true,
|
|
300
|
+
"content": {
|
|
301
|
+
"application/json": {
|
|
302
|
+
"schema": {
|
|
303
|
+
"type": "string",
|
|
304
|
+
"description": "URL",
|
|
305
|
+
"example": "https://example.test"
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
"responses": {
|
|
311
|
+
"200": {
|
|
312
|
+
"description": "OK"
|
|
313
|
+
},
|
|
314
|
+
"422": {
|
|
315
|
+
"description": "Invalid Proxy Fallback URL"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
"/mockaton/collect-proxied": {
|
|
321
|
+
"patch": {
|
|
322
|
+
"summary": "Enable or disable collection of proxied responses",
|
|
323
|
+
"description": "Applicable only when there’s a proxy fallback server URL already set. See `PATCH /mockaton/fallback`",
|
|
324
|
+
"x-js-client-example": "await mockaton.setCollectProxied(true)",
|
|
325
|
+
"requestBody": {
|
|
326
|
+
"required": true,
|
|
327
|
+
"content": {
|
|
328
|
+
"application/json": {
|
|
329
|
+
"schema": {
|
|
330
|
+
"type": "boolean",
|
|
331
|
+
"description": "Should Collect?",
|
|
332
|
+
"example": true
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
"responses": {
|
|
338
|
+
"200": {
|
|
339
|
+
"description": "OK"
|
|
340
|
+
},
|
|
341
|
+
"422": {
|
|
342
|
+
"description": "Expected boolean"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
"/mockaton/cookies": {
|
|
348
|
+
"patch": {
|
|
349
|
+
"summary": "Select a cookie label",
|
|
350
|
+
"x-js-client-example": "await mockaton.selectCookie('Normal User')",
|
|
351
|
+
"requestBody": {
|
|
352
|
+
"required": true,
|
|
353
|
+
"content": {
|
|
354
|
+
"application/json": {
|
|
355
|
+
"schema": {
|
|
356
|
+
"type": "string",
|
|
357
|
+
"description": "Cookie key",
|
|
358
|
+
"example": "Normal User"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
"responses": {
|
|
364
|
+
"200": {
|
|
365
|
+
"description": "Available cookie labels",
|
|
366
|
+
"content": {
|
|
367
|
+
"application/json": {
|
|
368
|
+
"schema": {
|
|
369
|
+
"$ref": "#/components/schemas/CookieSelectionList"
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
"422": {
|
|
375
|
+
"description": "Cookie key not found"
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
"/mockaton/watch-mocks": {
|
|
381
|
+
"patch": {
|
|
382
|
+
"summary": "Enable or disable mock file watching",
|
|
383
|
+
"description": "Controls file watchers for mocksDir.",
|
|
384
|
+
"x-js-client-example": "await mockaton.setWatchMocks(true)",
|
|
385
|
+
"requestBody": {
|
|
386
|
+
"required": true,
|
|
387
|
+
"content": {
|
|
388
|
+
"application/json": {
|
|
389
|
+
"schema": {
|
|
390
|
+
"type": "boolean",
|
|
391
|
+
"description": "true to start watchers, false to stop them"
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
"responses": {
|
|
397
|
+
"200": {
|
|
398
|
+
"description": "OK"
|
|
399
|
+
},
|
|
400
|
+
"422": {
|
|
401
|
+
"description": "Invalid input - expected boolean"
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
"/mockaton/write-mock": {
|
|
407
|
+
"patch": {
|
|
408
|
+
"summary": "Write a mock file",
|
|
409
|
+
"description": "Writes a mock file to the mocks directory. Guarded by `readOnly` and `mocksDir`.",
|
|
410
|
+
"x-js-client-example": "await mockaton.writeMock('api/user/friends.GET.200.json', '{ \"friends\": [] }')",
|
|
411
|
+
"requestBody": {
|
|
412
|
+
"required": true,
|
|
413
|
+
"content": {
|
|
414
|
+
"application/json": {
|
|
415
|
+
"schema": {
|
|
416
|
+
"type": "array",
|
|
417
|
+
"minItems": 2,
|
|
418
|
+
"maxItems": 2,
|
|
419
|
+
"prefixItems": [
|
|
420
|
+
{
|
|
421
|
+
"$ref": "#/components/schemas/Filename"
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
"type": "string",
|
|
425
|
+
"description": "File content"
|
|
426
|
+
}
|
|
427
|
+
],
|
|
428
|
+
"additionalItems": false
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
"responses": {
|
|
434
|
+
"200": {
|
|
435
|
+
"description": "OK"
|
|
436
|
+
},
|
|
437
|
+
"403": {
|
|
438
|
+
"description": "Forbidden (read-only mode or outside mocksDir)"
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
"/mockaton/delete-mock": {
|
|
444
|
+
"patch": {
|
|
445
|
+
"summary": "Delete a mock file",
|
|
446
|
+
"description": "Deletes a mock file from the mocks directory. Guarded by `readOnly` and `mocksDir`.",
|
|
447
|
+
"x-js-client-example": "await mockaton.deleteMock('api/user/friends.GET.200.json')",
|
|
448
|
+
"requestBody": {
|
|
449
|
+
"required": true,
|
|
450
|
+
"content": {
|
|
451
|
+
"application/json": {
|
|
452
|
+
"schema": {
|
|
453
|
+
"$ref": "#/components/schemas/Filename"
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
"responses": {
|
|
459
|
+
"200": {
|
|
460
|
+
"description": "OK"
|
|
461
|
+
},
|
|
462
|
+
"403": {
|
|
463
|
+
"description": "Forbidden (read-only mode or outside mocksDir)"
|
|
464
|
+
},
|
|
465
|
+
"422": {
|
|
466
|
+
"description": "Mock file does not exist"
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
"/mockaton/state": {
|
|
472
|
+
"get": {
|
|
473
|
+
"summary": "Get complete Mockaton state",
|
|
474
|
+
"x-js-client-example": "await mockaton.getState()",
|
|
475
|
+
"responses": {
|
|
476
|
+
"200": {
|
|
477
|
+
"description": "Mockaton state",
|
|
478
|
+
"content": {
|
|
479
|
+
"application/json": {
|
|
480
|
+
"schema": {
|
|
481
|
+
"$ref": "#/components/schemas/State"
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
"/mockaton/sync-version": {
|
|
490
|
+
"get": {
|
|
491
|
+
"summary": "Get sync version for long‑polling updates",
|
|
492
|
+
"description": "A counter that’s incremented when a new mock is added, removed, or renamed. Also, when the internal state changes, e.g., when changing the mock file for a route.",
|
|
493
|
+
"x-js-client-example": "await mockaton.getSyncVersion()",
|
|
494
|
+
"parameters": [
|
|
495
|
+
{
|
|
496
|
+
"name": "sync_version",
|
|
497
|
+
"in": "header",
|
|
498
|
+
"required": false,
|
|
499
|
+
"example": -1,
|
|
500
|
+
"schema": {
|
|
501
|
+
"type": "number"
|
|
502
|
+
},
|
|
503
|
+
"description": "When not present, or when the version mismatches it responds right away. Otherwise, it long polls. Times out in 8s."
|
|
504
|
+
}
|
|
505
|
+
],
|
|
506
|
+
"responses": {
|
|
507
|
+
"200": {
|
|
508
|
+
"description": "Sync version value",
|
|
509
|
+
"content": {
|
|
510
|
+
"application/json": {
|
|
511
|
+
"schema": {
|
|
512
|
+
"type": "number",
|
|
513
|
+
"description": "Incremental integer"
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
"components": {
|
|
523
|
+
"responses": {
|
|
524
|
+
"Broker": {
|
|
525
|
+
"description": "Updated broker state",
|
|
526
|
+
"content": {
|
|
527
|
+
"application/json": {
|
|
528
|
+
"schema": {
|
|
529
|
+
"$ref": "#/components/schemas/ClientMockBroker"
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
"schemas": {
|
|
536
|
+
"Method": {
|
|
537
|
+
"type": "string",
|
|
538
|
+
"description": "HTTP Method of the mock",
|
|
539
|
+
"example": "GET"
|
|
540
|
+
},
|
|
541
|
+
"UrlMask": {
|
|
542
|
+
"type": "string",
|
|
543
|
+
"example": "/api/user/friends"
|
|
544
|
+
},
|
|
545
|
+
"Filename": {
|
|
546
|
+
"type": "string",
|
|
547
|
+
"description": "Mock filename. The convention is UrlMask.Method.StatusCode.Extension",
|
|
548
|
+
"example": "api/user/friends.GET.200.json"
|
|
549
|
+
},
|
|
550
|
+
"ClientMockBroker": {
|
|
551
|
+
"type": "object",
|
|
552
|
+
"properties": {
|
|
553
|
+
"mocks": {
|
|
554
|
+
"type": "array",
|
|
555
|
+
"items": {
|
|
556
|
+
"$ref": "#/components/schemas/Filename"
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
"file": {
|
|
560
|
+
"$ref": "#/components/schemas/Filename"
|
|
561
|
+
},
|
|
562
|
+
"status": {
|
|
563
|
+
"type": "number"
|
|
564
|
+
},
|
|
565
|
+
"autoStatus": {
|
|
566
|
+
"type": "number"
|
|
567
|
+
},
|
|
568
|
+
"isStatic": {
|
|
569
|
+
"type": "boolean"
|
|
570
|
+
},
|
|
571
|
+
"delayed": {
|
|
572
|
+
"type": "boolean"
|
|
573
|
+
},
|
|
574
|
+
"proxied": {
|
|
575
|
+
"type": "boolean"
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
"required": [
|
|
579
|
+
"mocks",
|
|
580
|
+
"file",
|
|
581
|
+
"status",
|
|
582
|
+
"autoStatus",
|
|
583
|
+
"isStatic",
|
|
584
|
+
"delayed",
|
|
585
|
+
"proxied"
|
|
586
|
+
]
|
|
587
|
+
},
|
|
588
|
+
"State": {
|
|
589
|
+
"type": "object",
|
|
590
|
+
"properties": {
|
|
591
|
+
"brokersByMethod": {
|
|
592
|
+
"type": "object",
|
|
593
|
+
"additionalProperties": {
|
|
594
|
+
"type": "object",
|
|
595
|
+
"additionalProperties": {
|
|
596
|
+
"$ref": "#/components/schemas/ClientMockBroker"
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
"cookies": {
|
|
601
|
+
"$ref": "#/components/schemas/CookieSelectionList"
|
|
602
|
+
},
|
|
603
|
+
"comments": {
|
|
604
|
+
"type": "array",
|
|
605
|
+
"items": {
|
|
606
|
+
"type": "string"
|
|
607
|
+
}
|
|
608
|
+
},
|
|
609
|
+
"delay": {
|
|
610
|
+
"type": "number"
|
|
611
|
+
},
|
|
612
|
+
"delayJitter": {
|
|
613
|
+
"type": "number"
|
|
614
|
+
},
|
|
615
|
+
"collectProxied": {
|
|
616
|
+
"type": "boolean"
|
|
617
|
+
},
|
|
618
|
+
"proxyFallback": {
|
|
619
|
+
"type": "string"
|
|
620
|
+
},
|
|
621
|
+
"readOnly": {
|
|
622
|
+
"type": "boolean"
|
|
623
|
+
},
|
|
624
|
+
"corsAllowed": {
|
|
625
|
+
"type": "boolean"
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
"required": [
|
|
629
|
+
"brokersByMethod",
|
|
630
|
+
"cookies",
|
|
631
|
+
"comments",
|
|
632
|
+
"delay",
|
|
633
|
+
"delayJitter",
|
|
634
|
+
"collectProxied",
|
|
635
|
+
"proxyFallback",
|
|
636
|
+
"readOnly",
|
|
637
|
+
"corsAllowed"
|
|
638
|
+
]
|
|
639
|
+
},
|
|
640
|
+
"CookieSelectionList": {
|
|
641
|
+
"type": "array",
|
|
642
|
+
"items": {
|
|
643
|
+
"type": "array",
|
|
644
|
+
"minItems": 2,
|
|
645
|
+
"maxItems": 2,
|
|
646
|
+
"prefixItems": [
|
|
647
|
+
{
|
|
648
|
+
"type": "string",
|
|
649
|
+
"description": "Label"
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
"type": "boolean",
|
|
653
|
+
"description": "Selected"
|
|
654
|
+
}
|
|
655
|
+
],
|
|
656
|
+
"additionalItems": false
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|