@safagayret/bemirror 1.0.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.
@@ -0,0 +1,505 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>bemirror - Fake mirror your backend, fast</title>
8
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
+ <link
11
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap"
12
+ rel="stylesheet" />
13
+ <link rel="stylesheet" href="css/style.css" />
14
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/driver.js@1.0.1/dist/driver.css" />
15
+ <script src="https://cdn.jsdelivr.net/npm/driver.js@1.0.1/dist/driver.js.iife.js"></script>
16
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.7/ace.js"></script>
17
+ </head>
18
+
19
+ <body>
20
+ <div class="blob blob-1"></div>
21
+ <div class="blob blob-2"></div>
22
+
23
+ <!-- ABOUT MODAL -->
24
+ <div id="modalAbout" class="modal-overlay" style="display: none">
25
+ <div class="modal-content glass-panel" style="max-width: 600px">
26
+ <div class="modal-header">
27
+ <h2>💡 About bemirror</h2>
28
+ <button class="btn-icon" onclick="document.getElementById('modalAbout').style.display = 'none'">
29
+ <svg viewBox="0 0 24 24">
30
+ <path d="M6 18L18 6M6 6l12 12"></path>
31
+ </svg>
32
+ </button>
33
+ </div>
34
+ <div class="modal-body">
35
+ <p>
36
+ <strong>bemirror</strong> is an advanced, Zero-Backend local API mock server tailored
37
+ for frontend developers.
38
+ </p>
39
+ <br />
40
+ <p>
41
+ <strong>🔒 Total Privacy:</strong> All your projects, mock data, and configurations are stored
42
+ entirely in local files on your machine. Pure local execution with file-based persistence.
43
+ </p>
44
+ <br />
45
+ <p>
46
+ <strong>🚀 How it Works:</strong> Use the sidebar to create Projects and Entities (e.g.,
47
+ Auth, Users). Then define your endpoints using the Postman-style UI. Instantly consume
48
+ your mock APIs using the provided "Mock URL" from your frontend application!
49
+ </p>
50
+ <br />
51
+ <p>
52
+ <strong>🧩 Import / Export:</strong> Collaborate with your teammates! Use the global
53
+ import/export buttons on the top right, or click the download icons next to specific
54
+ folders to export individual projects seamlessly.
55
+ </p>
56
+ <br />
57
+ <p>
58
+ <strong>🔧 Variables:</strong> Use variables in your endpoints with {{variableName}} syntax.
59
+ Create a variables.json file in the project root to define global variables like base URLs,
60
+ usernames, and passwords. This file should be added to .gitignore to keep sensitive data private.
61
+ </p>
62
+ </div>
63
+ <div class="modal-footer form-actions" style="margin-top: 20px">
64
+ <button class="btn-primary" onclick="document.getElementById('modalAbout').style.display = 'none'; startOnboarding();">
65
+ Start Tour
66
+ </button>
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ <!-- EXTERNAL LINKS -->
72
+ <a href="https://github.com/gayret/bemirror" target="_blank" class="github-link" title="View Source on GitHub">
73
+ <svg viewBox="0 0 24 24">
74
+ <path fill="currentColor"
75
+ d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12">
76
+ </path>
77
+ </svg>
78
+ </a>
79
+ <a href="https://buymeacoffee.com/safagayret" target="_blank" class="coffee-link" title="Buy me a coffee">
80
+ <svg width="24px" height="24px" viewBox="0 0 24 24" role="img" xmlns="http://www.w3.org/2000/svg">
81
+ <path
82
+ d="m20.216 6.415-.132-.666c-.119-.598-.388-1.163-1.001-1.379-.197-.069-.42-.098-.57-.241-.152-.143-.196-.366-.231-.572-.065-.378-.125-.756-.192-1.133-.057-.325-.102-.69-.25-.987-.195-.4-.597-.634-.996-.788a5.723 5.723 0 0 0-.626-.194c-1-.263-2.05-.36-3.077-.416a25.834 25.834 0 0 0-3.7.062c-.915.083-1.88.184-2.75.5-.318.116-.646.256-.888.501-.297.302-.393.77-.177 1.146.154.267.415.456.692.58.36.162.737.284 1.123.366 1.075.238 2.189.331 3.287.37 1.218.05 2.437.01 3.65-.118.299-.033.598-.073.896-.119.352-.054.578-.513.474-.834-.124-.383-.457-.531-.834-.473-.466.074-.96.108-1.382.146-1.177.08-2.358.082-3.536.006a22.228 22.228 0 0 1-1.157-.107c-.086-.01-.18-.025-.258-.036-.243-.036-.484-.08-.724-.13-.111-.027-.111-.185 0-.212h.005c.277-.06.557-.108.838-.147h.002c.131-.009.263-.032.394-.048a25.076 25.076 0 0 1 3.426-.12c.674.019 1.347.067 2.017.144l.228.031c.267.04.533.088.798.145.392.085.895.113 1.07.542.055.137.08.288.111.431l.319 1.484a.237.237 0 0 1-.199.284h-.003c-.037.006-.075.01-.112.015a36.704 36.704 0 0 1-4.743.295 37.059 37.059 0 0 1-4.699-.304c-.14-.017-.293-.042-.417-.06-.326-.048-.649-.108-.973-.161-.393-.065-.768-.032-1.123.161-.29.16-.527.404-.675.701-.154.316-.199.66-.267 1-.069.34-.176.707-.135 1.056.087.753.613 1.365 1.37 1.502a39.69 39.69 0 0 0 11.343.376.483.483 0 0 1 .535.53l-.071.697-1.018 9.907c-.041.41-.047.832-.125 1.237-.122.637-.553 1.028-1.182 1.171-.577.131-1.165.2-1.756.205-.656.004-1.31-.025-1.966-.022-.699.004-1.556-.06-2.095-.58-.475-.458-.54-1.174-.605-1.793l-.731-7.013-.322-3.094c-.037-.351-.286-.695-.678-.678-.336.015-.718.3-.678.679l.228 2.185.949 9.112c.147 1.344 1.174 2.068 2.446 2.272.742.12 1.503.144 2.257.156.966.016 1.942.053 2.892-.122 1.408-.258 2.465-1.198 2.616-2.657.34-3.332.683-6.663 1.024-9.995l.215-2.087a.484.484 0 0 1 .39-.426c.402-.078.787-.212 1.074-.518.455-.488.546-1.124.385-1.766zm-1.478.772c-.145.137-.363.201-.578.233-2.416.359-4.866.54-7.308.46-1.748-.06-3.477-.254-5.207-.498-.17-.024-.353-.055-.47-.18-.22-.236-.111-.71-.054-.995.052-.26.152-.609.463-.646.484-.057 1.046.148 1.526.22.577.088 1.156.159 1.737.212 2.48.226 5.002.19 7.472-.14.45-.06.899-.13 1.345-.21.399-.072.84-.206 1.08.206.166.281.188.657.162.974a.544.544 0 0 1-.169.364zm-6.159 3.9c-.862.37-1.84.788-3.109.788a5.884 5.884 0 0 1-1.569-.217l.877 9.004c.065.78.717 1.38 1.5 1.38 0 0 1.243.065 1.658.065.447 0 1.786-.065 1.786-.065.783 0 1.434-.6 1.499-1.38l.94-9.95a3.996 3.996 0 0 0-1.322-.238c-.826 0-1.491.284-2.26.613z" />
83
+ </svg>
84
+ <span>Buy me a coffee</span>
85
+ </a>
86
+
87
+
88
+
89
+ <!-- IMPORT MODAL -->
90
+ <div id="modalImport" class="modal-overlay" style="display: none">
91
+ <div class="modal-content glass-panel" style="max-width: 600px">
92
+ <div class="modal-header">
93
+ <h2>📥 Import Projects</h2>
94
+ <button class="btn-icon" onclick="document.getElementById('modalImport').style.display = 'none'">
95
+ <svg viewBox="0 0 24 24">
96
+ <path d="M6 18L18 6M6 6l12 12"></path>
97
+ </svg>
98
+ </button>
99
+ </div>
100
+ <div class="modal-body">
101
+ <p>Choose an import method:</p>
102
+
103
+ <div style="
104
+ margin-top: 15px;
105
+ border: 1px dashed var(--panel-border);
106
+ padding: 15px;
107
+ border-radius: 8px;
108
+ text-align: center;
109
+ ">
110
+ <input type="file" id="fileImportAdvanced" accept=".json" style="display: none" />
111
+ <button class="btn-primary" onclick="document.getElementById('fileImportAdvanced').click()">
112
+ Upload JSON File
113
+ </button>
114
+ <div id="fileImportStatus" style="margin-top: 10px; font-size: 14px; color: var(--text-muted)">
115
+ No file selected.
116
+ </div>
117
+ </div>
118
+
119
+ <div style="margin-top: 20px">
120
+ <p>Or paste JSON text below:</p>
121
+ <textarea id="importPasteArea" class="prod-url-input" style="
122
+ width: 100%;
123
+ height: 120px;
124
+ font-family: monospace;
125
+ resize: vertical;
126
+ margin-top: 10px;
127
+ " placeholder='{"projects": [...]}'></textarea>
128
+ </div>
129
+
130
+ <div style="margin-top: 20px; text-align: right">
131
+ <label style="margin-right: 15px; cursor: pointer">
132
+ <input type="radio" name="importStrategy" value="merge" checked /> Merge (Keep
133
+ Existing)
134
+ </label>
135
+ <label style="cursor: pointer">
136
+ <input type="radio" name="importStrategy" value="overwrite" /> Overwrite (Delete Old)
137
+ </label>
138
+ </div>
139
+ </div>
140
+ <div class="modal-footer form-actions" style="margin-top: 20px">
141
+ <button id="btnExecuteImport" class="btn-primary" style="background: var(--success); width: 100%">
142
+ Execute Import
143
+ </button>
144
+ </div>
145
+ </div>
146
+ </div>
147
+
148
+ <!-- EXPORT MODAL -->
149
+ <div id="modalExport" class="modal-overlay" style="display: none">
150
+ <div class="modal-content glass-panel" style="max-width: 500px">
151
+ <div class="modal-header">
152
+ <h2>📤 Export Projects</h2>
153
+ <button class="btn-icon" onclick="document.getElementById('modalExport').style.display = 'none'">
154
+ <svg viewBox="0 0 24 24">
155
+ <path d="M6 18L18 6M6 6l12 12"></path>
156
+ </svg>
157
+ </button>
158
+ </div>
159
+ <div class="modal-body" style="text-align: center">
160
+ <p>Your mock APIs are ready for export.</p>
161
+ <div style="display: flex; gap: 15px; justify-content: center; margin-top: 25px">
162
+ <button id="btnExportDownload" class="btn-primary" style="
163
+ min-width: 150px;
164
+ display: flex;
165
+ align-items: center;
166
+ justify-content: center;
167
+ gap: 8px;
168
+ ">
169
+ <svg viewBox="0 0 24 24" style="width: 20px; height: 20px">
170
+ <path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" stroke="currentColor"
171
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"></path>
172
+ </svg>
173
+ Download JSON
174
+ </button>
175
+ <button id="btnExportCopy" class="btn-primary" style="
176
+ background: var(--surface);
177
+ color: var(--text-primary);
178
+ border: 1px solid var(--panel-border);
179
+ min-width: 150px;
180
+ display: flex;
181
+ align-items: center;
182
+ justify-content: center;
183
+ gap: 8px;
184
+ ">
185
+ <svg viewBox="0 0 24 24" style="width: 20px; height: 20px">
186
+ <path
187
+ d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
188
+ stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none">
189
+ </path>
190
+ </svg>
191
+ Copy to Clipboard
192
+ </button>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <!-- VARIABLES MODAL -->
199
+ <div id="modalVariables" class="modal-overlay" style="display: none">
200
+ <div class="modal-content glass-panel" style="max-width: 600px">
201
+ <div class="modal-header">
202
+ <h2>🔧 Edit Variables</h2>
203
+ <button class="btn-icon" onclick="document.getElementById('modalVariables').style.display = 'none'">
204
+ <svg viewBox="0 0 24 24">
205
+ <path d="M6 18L18 6M6 6l12 12"></path>
206
+ </svg>
207
+ </button>
208
+ </div>
209
+ <div class="modal-body">
210
+ <p>Define global variables that can be used in endpoints with {{variableName}} syntax.</p>
211
+ <p class="help-text">Example: {"baseURL": "https://api.example.com", "username": "user", "password": "pass"}</p>
212
+ <div id="editorVariables" class="ace-wrapper" style="height: 300px; margin-top: 15px"></div>
213
+ </div>
214
+ <div class="modal-footer form-actions" style="margin-top: 20px">
215
+ <button id="btnSaveVariables" class="btn-primary" style="background: var(--success); width: 100%">
216
+ Save Variables
217
+ </button>
218
+ </div>
219
+ </div>
220
+ </div>
221
+
222
+ <!-- HAMBURGER MENU (Visible on Mobile) -->
223
+ <button id="btnMobileMenu" class="btn-icon mobile-menu-btn" title="Toggle Sidebar">
224
+ <svg viewBox="0 0 24 24">
225
+ <path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M4 6h16M4 12h16M4 18h16">
226
+ </path>
227
+ </svg>
228
+ </button>
229
+
230
+ <div class="app-container">
231
+ <div class="app-layout">
232
+ <aside class="sidebar glass-panel">
233
+ <div class="sidebar-header">
234
+ <div class="logo">
235
+ <svg viewBox="0 0 24 24">
236
+ <path d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path>
237
+ </svg>
238
+ <div>
239
+ <h1>be<span class="dot">.</span>mirror</h1>
240
+ <p class="slogan" style="
241
+ margin: 4px 0 0 0px;
242
+ font-size: 9px;
243
+ opacity: 0.7;
244
+ font-weight: normal;
245
+ font-family: 'Inter', sans-serif;
246
+ color: gray;
247
+ ">
248
+ Fake mirror your backend, fast
249
+ </p>
250
+ </div>
251
+ </div>
252
+ <div class="sidebar-actions">
253
+ <button id="btnAbout" class="btn-icon" title="About bemirror">
254
+ <svg viewBox="0 0 24 24">
255
+ <path d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
256
+ </svg>
257
+ </button>
258
+ <button id="btnVariables" class="btn-icon" title="Edit Variables">
259
+ <svg viewBox="0 0 24 24">
260
+ <path d="M4 6h16M4 12h16M4 18h16"></path>
261
+ </svg>
262
+ </button>
263
+ <button id="btnNewProject" class="btn-icon" title="New Project">
264
+ <svg viewBox="0 0 24 24">
265
+ <path d="M12 4v16m8-8H4"></path>
266
+ </svg>
267
+ </button>
268
+ <button id="btnImport" class="btn-icon" title="Import Data (JSON)">
269
+ <svg viewBox="0 0 24 24">
270
+ <path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"></path>
271
+ </svg>
272
+ </button>
273
+ <button id="btnExport" class="btn-icon" title="Export All Data (JSON)">
274
+ <svg viewBox="0 0 24 24">
275
+ <path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
276
+ </svg>
277
+ </button>
278
+ <!-- The old fileImport is removed as it's now inside the modal -->
279
+ </div>
280
+ </div>
281
+ <div class="sidebar-search">
282
+ <input id="treeSearch" type="search" placeholder="Search projects, entities, endpoints..." autocomplete="off" />
283
+ </div>
284
+ <div class="tree-container" id="projectTree">
285
+ <div class="loading-state">Loading Setup...</div>
286
+ </div>
287
+ </aside>
288
+
289
+ <main class="main-content glass-panel">
290
+ <div id="welcomeScreen" class="welcome-screen">
291
+ <h2>Select an endpoint to edit</h2>
292
+ <p>Organize your mock APIs using Projects and Entities from the sidebar.</p>
293
+ <button id="btnCreateFirstProject" class="btn-primary" style="margin-top: 20px; max-width: 250px">
294
+ Create your Project
295
+ </button>
296
+ </div>
297
+
298
+ <div id="editorScreen" class="editor-screen" style="display: none">
299
+ <div class="editor-header">
300
+ <h2 id="editorTitle">Edit Endpoint</h2>
301
+ <button class="btn-icon text-danger" id="btnDeleteEndpoint" title="Delete Endpoint">
302
+ <svg viewBox="0 0 24 24">
303
+ <path
304
+ d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16">
305
+ </path>
306
+ </svg>
307
+ </button>
308
+ </div>
309
+ <div id="editorBreadcrumbs" class="breadcrumbs">Project > Entity > Endpoint</div>
310
+
311
+ <!-- MOCK URL AREA -->
312
+ <div class="http-clients-area">
313
+ <div class="live-url-box" style="justify-content: space-between">
314
+ <div style="display: flex; align-items: center; gap: 12px; flex: 1">
315
+ <div class="url-badge">⚡ Mock URL</div>
316
+ <a href="#" id="liveUrlLink" target="_blank" class="live-url-link">Select an endpoint to see the mock
317
+ URL</a>
318
+ </div>
319
+ <button id="btnCopyCurl" class="btn-icon" title="Copy terminal cURL command" style="
320
+ border: 1px solid var(--panel-border);
321
+ background: rgba(255, 255, 255, 0.05);
322
+ padding: 4px 10px;
323
+ font-family: monospace;
324
+ font-size: 11px;
325
+ white-space: nowrap;
326
+ border-radius: 4px;
327
+ margin-left: 10px;
328
+ ">
329
+ Copy cURL
330
+ </button>
331
+ <button id="btnCopyFetch" class="btn-icon" title="Copy JS fetch()" style="
332
+ border: 1px solid var(--panel-border);
333
+ background: rgba(255, 255, 255, 0.05);
334
+ padding: 4px 10px;
335
+ font-family: monospace;
336
+ font-size: 11px;
337
+ white-space: nowrap;
338
+ border-radius: 4px;
339
+ margin-left: 5px;
340
+ ">
341
+ Copy fetch
342
+ </button>
343
+ </div>
344
+
345
+ <!-- PROD URL TESTER AREA -->
346
+ <div class="prod-url-box">
347
+ <div class="url-badge" style="color: var(--success)">🌍 Prod URL</div>
348
+ <input type="text" id="prodUrlInput" placeholder="https://api.example.com/production/route"
349
+ class="prod-url-input" />
350
+ <button id="btnSendProd" class="btn-send">Send Request 🚀</button>
351
+ </div>
352
+ </div>
353
+
354
+ <div id="prodResponseWrapper" class="prod-response-wrapper" style="display: none">
355
+ <div class="prod-resp-header">
356
+ <span>Production Server Response</span>
357
+ <div style="display: flex; gap: 10px; align-items: center">
358
+ <span id="prodStatus" class="prod-status">200 OK</span>
359
+ <span id="prodTime" class="prod-time">45ms</span>
360
+ <button class="btn-icon" onclick="document.getElementById('prodResponseWrapper').style.display = 'none'"
361
+ title="Close Panel">
362
+ <svg viewBox="0 0 24 24">
363
+ <path d="M6 18L18 6M6 6l12 12"></path>
364
+ </svg>
365
+ </button>
366
+ </div>
367
+ </div>
368
+ <div id="editorProdResponse" class="ace-wrapper"
369
+ style="height: 200px; border-radius: 0 0 8px 8px; border-top: none"></div>
370
+ </div>
371
+
372
+ <form id="endpointForm" style="margin-top: 20px">
373
+ <input type="hidden" id="epId" />
374
+ <input type="hidden" id="epEntityId" />
375
+ <input type="hidden" id="epProjectId" />
376
+
377
+ <div class="form-row">
378
+ <div class="form-group flex-1">
379
+ <label for="method">Method</label>
380
+ <select id="method" required>
381
+ <option value="GET">GET</option>
382
+ <option value="POST">POST</option>
383
+ <option value="PUT">PUT</option>
384
+ <option value="PATCH">PATCH</option>
385
+ <option value="DELETE">DELETE</option>
386
+ </select>
387
+ </div>
388
+ <div class="form-group flex-4">
389
+ <label for="path">Final Path Route</label>
390
+ <div class="input-prefix">
391
+ <span class="prefix">Path:</span>
392
+ <input type="text" id="path" placeholder="/users/profile" required />
393
+ </div>
394
+ </div>
395
+ </div>
396
+
397
+ <!-- Tabs -->
398
+ <!-- Tabs & Response View -->
399
+ <div class="split-editor-layout">
400
+ <!-- Left Panel (Tabs) -->
401
+ <div class="split-left">
402
+ <div class="editor-tabs-container" style="margin-top: 0">
403
+ <div class="editor-tabs">
404
+ <button type="button" class="tab-btn" data-tab="tab-params">
405
+ Params
406
+ </button>
407
+ <button type="button" class="tab-btn active" data-tab="tab-payload">
408
+ Body (Payload)
409
+ </button>
410
+ <button type="button" class="tab-btn" data-tab="tab-auth">
411
+ Authorization
412
+ </button>
413
+ <button type="button" class="tab-btn" data-tab="tab-headers">
414
+ Headers
415
+ </button>
416
+ </div>
417
+
418
+ <div class="tab-pane" id="tab-params">
419
+ <label>Expected Query Parameters</label>
420
+ <p class="help-text">
421
+ JSON format. Endpoint strict validation. Example: {"id": "5"}
422
+ </p>
423
+ <div id="editorParams" class="ace-wrapper" style="height: 300px"></div>
424
+ </div>
425
+ <div class="tab-pane active" id="tab-payload">
426
+ <label>Expected Body Payload</label>
427
+ <p class="help-text">
428
+ Mock server returns 400 Bad Request if missing top-level keys.
429
+ </p>
430
+ <div id="editorPayload" class="ace-wrapper" style="height: 300px"></div>
431
+ </div>
432
+ <div class="tab-pane" id="tab-auth">
433
+ <label>Authorization</label>
434
+ <p class="help-text">
435
+ Select authorization type and provide credentials.
436
+ </p>
437
+ <div class="form-row">
438
+ <div class="form-group flex-1">
439
+ <label>Type</label>
440
+ <select id="authType">
441
+ <option value="None">None</option>
442
+ <option value="Bearer">Bearer Token</option>
443
+ <option value="Basic">Basic Auth</option>
444
+ <option value="APIKey">API Key</option>
445
+ </select>
446
+ </div>
447
+ <div class="form-group flex-1">
448
+ <label>Value</label>
449
+ <input type="text" id="authValue" placeholder="Token or username:password" />
450
+ </div>
451
+ </div>
452
+ </div>
453
+ <div class="tab-pane" id="tab-headers">
454
+ <label>Custom Headers</label>
455
+ <p class="help-text">
456
+ Add custom headers to the response. JSON format: [{"key": "Content-Type", "value": "application/json"}]
457
+ </p>
458
+ <div id="editorHeaders" class="ace-wrapper" style="height: 300px"></div>
459
+ </div>
460
+ </div>
461
+ </div>
462
+
463
+ <!-- Right Panel (Expected Response) -->
464
+ <div class="split-right">
465
+ <h3 style="
466
+ font-size: 14px;
467
+ font-weight: 600;
468
+ color: var(--text-main);
469
+ border-bottom: 2px solid var(--accent);
470
+ padding-bottom: 10px;
471
+ margin-bottom: 16px;
472
+ ">
473
+ Expected Response 🟢
474
+ </h3>
475
+ <div class="form-row" style="margin-bottom: 10px">
476
+ <div class="form-group flex-1" style="margin-bottom: 0">
477
+ <label>Status Code</label><input type="number" id="statusCode" value="200" required />
478
+ </div>
479
+ <div class="form-group flex-1" style="margin-bottom: 0">
480
+ <label>Simulate Network Delay (ms)</label><input type="number" id="delay" value="0" required />
481
+ </div>
482
+ </div>
483
+ <label>Provide Response Body (JSON or Text)</label>
484
+ <div id="editorResponse" class="ace-wrapper" style="flex: 1; min-height: 230px"></div>
485
+ </div>
486
+ </div>
487
+ <div class="form-actions">
488
+ <button type="submit" class="btn-primary" id="saveEndpointBtn">
489
+ Save Configuration <span class="shortcut-hint">Ctrl + ↵</span>
490
+ </button>
491
+ </div>
492
+ </form>
493
+ </div>
494
+ </main>
495
+ </div>
496
+
497
+ <footer class="app-footer">
498
+ <div data-ataturk-quote-widget data-language="en" data-theme="dark"></div>
499
+ <script async src="https://ataturk-kronolojisi.org/widget/quote.js" data-language="en" data-theme="dark"></script>
500
+ </footer>
501
+
502
+ <script src="js/app.js"></script>
503
+ </body>
504
+
505
+ </html>