@yrest/cli 0.8.0 → 0.8.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 +1 -1
- package/dist/cli/index.js +17 -5
- package/dist/cli/index.mjs +17 -5
- package/dist/index.js +17 -5
- package/dist/index.mjs +17 -5
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://github.com/aggiovato/yRest/actions)
|
|
11
11
|
[](https://www.npmjs.com/package/@yrest/cli)
|
|
12
12
|
[](https://www.typescriptlang.org/)
|
|
13
|
-
[](https://socket.dev/npm/package/@yrest/cli)
|
|
14
14
|
|
|
15
15
|
YAML-powered json-server alternative. Zero-config REST API mock server with full CRUD, relations, filters and snapshots from a `db.yml` file.
|
|
16
16
|
|
package/dist/cli/index.js
CHANGED
|
@@ -292,8 +292,11 @@ var METHOD_COLOR = {
|
|
|
292
292
|
DELETE: "#f85149",
|
|
293
293
|
fn: "#f0883e"
|
|
294
294
|
};
|
|
295
|
+
function escapeHtml(str) {
|
|
296
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
297
|
+
}
|
|
295
298
|
function badge(label, color, bg) {
|
|
296
|
-
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${label}</span>`;
|
|
299
|
+
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${escapeHtml(label)}</span>`;
|
|
297
300
|
}
|
|
298
301
|
function methodBadge(method) {
|
|
299
302
|
const color = METHOD_COLOR[method] ?? "#7d8590";
|
|
@@ -303,7 +306,7 @@ function endpointRow(method, path, desc) {
|
|
|
303
306
|
return `
|
|
304
307
|
<tr>
|
|
305
308
|
<td class="method-cell">${methodBadge(method)}</td>
|
|
306
|
-
<td class="path-cell"><code>${path}</code></td>
|
|
309
|
+
<td class="path-cell"><code>${escapeHtml(path)}</code></td>
|
|
307
310
|
<td class="desc-cell">${desc}</td>
|
|
308
311
|
</tr>`;
|
|
309
312
|
}
|
|
@@ -337,7 +340,7 @@ function resourceAccordion(name, base, isOpen) {
|
|
|
337
340
|
return `
|
|
338
341
|
<details class="resource-card" ${isOpen ? "open" : ""}>
|
|
339
342
|
<summary>
|
|
340
|
-
<span class="resource-name">/${name}</span>
|
|
343
|
+
<span class="resource-name">/${escapeHtml(name)}</span>
|
|
341
344
|
<span class="route-count">6 routes</span>
|
|
342
345
|
</summary>
|
|
343
346
|
<table>
|
|
@@ -421,7 +424,7 @@ curl -X POST ${host}/_snapshot/reset`
|
|
|
421
424
|
}
|
|
422
425
|
if (firstCustomRoute) {
|
|
423
426
|
const method = firstCustomRoute.method?.toUpperCase() ?? "GET";
|
|
424
|
-
const fullPath = `${host}${base}${firstCustomRoute.path}`;
|
|
427
|
+
const fullPath = `${host}${base}${escapeHtml(firstCustomRoute.path ?? "")}`;
|
|
425
428
|
const curlFlag = method === "GET" ? "" : `-X ${method} `;
|
|
426
429
|
examples.push(`# Custom route
|
|
427
430
|
curl ${curlFlag}${fullPath}`);
|
|
@@ -506,7 +509,8 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
506
509
|
desc = `Error injection \u2014 <code>${r.error}</code>`;
|
|
507
510
|
} else if (r.handler) {
|
|
508
511
|
const found = handlers.has(r.handler);
|
|
509
|
-
|
|
512
|
+
const handlerName = escapeHtml(r.handler);
|
|
513
|
+
desc = found ? `Handler \u2014 <code>${handlerName}()</code>` : `Handler \u2014 <code>${handlerName}()</code> <span style="color:#f85149">(not loaded)</span>`;
|
|
510
514
|
} else if (r.scenarios?.length) {
|
|
511
515
|
const hasTemplateInScenarios = r.scenarios.some((s) => s.response.body != null && hasTemplates(s.response.body)) || r.otherwise?.body != null && hasTemplates(r.otherwise.body);
|
|
512
516
|
desc = hasTemplateInScenarios ? `Scenarios \u2014 <code>{{\u2026}}</code>` : `Scenarios`;
|
|
@@ -779,6 +783,7 @@ function applyOperator(itemValue, op, filterValue) {
|
|
|
779
783
|
case "_start":
|
|
780
784
|
return strItem.toLowerCase().startsWith(filterValue.toLowerCase());
|
|
781
785
|
case "_regex": {
|
|
786
|
+
if (filterValue.length > 200) return false;
|
|
782
787
|
try {
|
|
783
788
|
return new RegExp(filterValue, "i").test(strItem);
|
|
784
789
|
} catch {
|
|
@@ -1439,8 +1444,15 @@ function loadConfigFile(configPath) {
|
|
|
1439
1444
|
|
|
1440
1445
|
// src/utils/handlers.ts
|
|
1441
1446
|
var import_node_fs5 = require("fs");
|
|
1447
|
+
var ALLOWED_EXTENSIONS = [".js", ".mjs", ".cjs"];
|
|
1442
1448
|
async function loadHandlers(filePath) {
|
|
1443
1449
|
if (!(0, import_node_fs5.existsSync)(filePath)) return /* @__PURE__ */ new Map();
|
|
1450
|
+
if (!ALLOWED_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
|
|
1451
|
+
console.error(
|
|
1452
|
+
` \x1B[31m[handlers] ${filePath} \u2014 only .js, .mjs and .cjs files are allowed\x1B[0m`
|
|
1453
|
+
);
|
|
1454
|
+
return /* @__PURE__ */ new Map();
|
|
1455
|
+
}
|
|
1444
1456
|
try {
|
|
1445
1457
|
const mod = await import(filePath);
|
|
1446
1458
|
const map = /* @__PURE__ */ new Map();
|
package/dist/cli/index.mjs
CHANGED
|
@@ -265,8 +265,11 @@ var METHOD_COLOR = {
|
|
|
265
265
|
DELETE: "#f85149",
|
|
266
266
|
fn: "#f0883e"
|
|
267
267
|
};
|
|
268
|
+
function escapeHtml(str) {
|
|
269
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
270
|
+
}
|
|
268
271
|
function badge(label, color, bg) {
|
|
269
|
-
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${label}</span>`;
|
|
272
|
+
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${escapeHtml(label)}</span>`;
|
|
270
273
|
}
|
|
271
274
|
function methodBadge(method) {
|
|
272
275
|
const color = METHOD_COLOR[method] ?? "#7d8590";
|
|
@@ -276,7 +279,7 @@ function endpointRow(method, path, desc) {
|
|
|
276
279
|
return `
|
|
277
280
|
<tr>
|
|
278
281
|
<td class="method-cell">${methodBadge(method)}</td>
|
|
279
|
-
<td class="path-cell"><code>${path}</code></td>
|
|
282
|
+
<td class="path-cell"><code>${escapeHtml(path)}</code></td>
|
|
280
283
|
<td class="desc-cell">${desc}</td>
|
|
281
284
|
</tr>`;
|
|
282
285
|
}
|
|
@@ -310,7 +313,7 @@ function resourceAccordion(name, base, isOpen) {
|
|
|
310
313
|
return `
|
|
311
314
|
<details class="resource-card" ${isOpen ? "open" : ""}>
|
|
312
315
|
<summary>
|
|
313
|
-
<span class="resource-name">/${name}</span>
|
|
316
|
+
<span class="resource-name">/${escapeHtml(name)}</span>
|
|
314
317
|
<span class="route-count">6 routes</span>
|
|
315
318
|
</summary>
|
|
316
319
|
<table>
|
|
@@ -394,7 +397,7 @@ curl -X POST ${host}/_snapshot/reset`
|
|
|
394
397
|
}
|
|
395
398
|
if (firstCustomRoute) {
|
|
396
399
|
const method = firstCustomRoute.method?.toUpperCase() ?? "GET";
|
|
397
|
-
const fullPath = `${host}${base}${firstCustomRoute.path}`;
|
|
400
|
+
const fullPath = `${host}${base}${escapeHtml(firstCustomRoute.path ?? "")}`;
|
|
398
401
|
const curlFlag = method === "GET" ? "" : `-X ${method} `;
|
|
399
402
|
examples.push(`# Custom route
|
|
400
403
|
curl ${curlFlag}${fullPath}`);
|
|
@@ -479,7 +482,8 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
479
482
|
desc = `Error injection \u2014 <code>${r.error}</code>`;
|
|
480
483
|
} else if (r.handler) {
|
|
481
484
|
const found = handlers.has(r.handler);
|
|
482
|
-
|
|
485
|
+
const handlerName = escapeHtml(r.handler);
|
|
486
|
+
desc = found ? `Handler \u2014 <code>${handlerName}()</code>` : `Handler \u2014 <code>${handlerName}()</code> <span style="color:#f85149">(not loaded)</span>`;
|
|
483
487
|
} else if (r.scenarios?.length) {
|
|
484
488
|
const hasTemplateInScenarios = r.scenarios.some((s) => s.response.body != null && hasTemplates(s.response.body)) || r.otherwise?.body != null && hasTemplates(r.otherwise.body);
|
|
485
489
|
desc = hasTemplateInScenarios ? `Scenarios \u2014 <code>{{\u2026}}</code>` : `Scenarios`;
|
|
@@ -752,6 +756,7 @@ function applyOperator(itemValue, op, filterValue) {
|
|
|
752
756
|
case "_start":
|
|
753
757
|
return strItem.toLowerCase().startsWith(filterValue.toLowerCase());
|
|
754
758
|
case "_regex": {
|
|
759
|
+
if (filterValue.length > 200) return false;
|
|
755
760
|
try {
|
|
756
761
|
return new RegExp(filterValue, "i").test(strItem);
|
|
757
762
|
} catch {
|
|
@@ -1412,8 +1417,15 @@ function loadConfigFile(configPath) {
|
|
|
1412
1417
|
|
|
1413
1418
|
// src/utils/handlers.ts
|
|
1414
1419
|
import { existsSync as existsSync3 } from "fs";
|
|
1420
|
+
var ALLOWED_EXTENSIONS = [".js", ".mjs", ".cjs"];
|
|
1415
1421
|
async function loadHandlers(filePath) {
|
|
1416
1422
|
if (!existsSync3(filePath)) return /* @__PURE__ */ new Map();
|
|
1423
|
+
if (!ALLOWED_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
|
|
1424
|
+
console.error(
|
|
1425
|
+
` \x1B[31m[handlers] ${filePath} \u2014 only .js, .mjs and .cjs files are allowed\x1B[0m`
|
|
1426
|
+
);
|
|
1427
|
+
return /* @__PURE__ */ new Map();
|
|
1428
|
+
}
|
|
1417
1429
|
try {
|
|
1418
1430
|
const mod = await import(filePath);
|
|
1419
1431
|
const map = /* @__PURE__ */ new Map();
|
package/dist/index.js
CHANGED
|
@@ -202,8 +202,15 @@ var import_node_path3 = require("path");
|
|
|
202
202
|
// src/utils/handlers.ts
|
|
203
203
|
init_cjs_shims();
|
|
204
204
|
var import_node_fs = require("fs");
|
|
205
|
+
var ALLOWED_EXTENSIONS = [".js", ".mjs", ".cjs"];
|
|
205
206
|
async function loadHandlers(filePath) {
|
|
206
207
|
if (!(0, import_node_fs.existsSync)(filePath)) return /* @__PURE__ */ new Map();
|
|
208
|
+
if (!ALLOWED_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
|
|
209
|
+
console.error(
|
|
210
|
+
` \x1B[31m[handlers] ${filePath} \u2014 only .js, .mjs and .cjs files are allowed\x1B[0m`
|
|
211
|
+
);
|
|
212
|
+
return /* @__PURE__ */ new Map();
|
|
213
|
+
}
|
|
207
214
|
try {
|
|
208
215
|
const mod = await import(filePath);
|
|
209
216
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -309,8 +316,11 @@ var METHOD_COLOR = {
|
|
|
309
316
|
DELETE: "#f85149",
|
|
310
317
|
fn: "#f0883e"
|
|
311
318
|
};
|
|
319
|
+
function escapeHtml(str) {
|
|
320
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
321
|
+
}
|
|
312
322
|
function badge(label, color, bg) {
|
|
313
|
-
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${label}</span>`;
|
|
323
|
+
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${escapeHtml(label)}</span>`;
|
|
314
324
|
}
|
|
315
325
|
function methodBadge(method) {
|
|
316
326
|
const color = METHOD_COLOR[method] ?? "#7d8590";
|
|
@@ -320,7 +330,7 @@ function endpointRow(method, path, desc) {
|
|
|
320
330
|
return `
|
|
321
331
|
<tr>
|
|
322
332
|
<td class="method-cell">${methodBadge(method)}</td>
|
|
323
|
-
<td class="path-cell"><code>${path}</code></td>
|
|
333
|
+
<td class="path-cell"><code>${escapeHtml(path)}</code></td>
|
|
324
334
|
<td class="desc-cell">${desc}</td>
|
|
325
335
|
</tr>`;
|
|
326
336
|
}
|
|
@@ -354,7 +364,7 @@ function resourceAccordion(name, base, isOpen) {
|
|
|
354
364
|
return `
|
|
355
365
|
<details class="resource-card" ${isOpen ? "open" : ""}>
|
|
356
366
|
<summary>
|
|
357
|
-
<span class="resource-name">/${name}</span>
|
|
367
|
+
<span class="resource-name">/${escapeHtml(name)}</span>
|
|
358
368
|
<span class="route-count">6 routes</span>
|
|
359
369
|
</summary>
|
|
360
370
|
<table>
|
|
@@ -438,7 +448,7 @@ curl -X POST ${host}/_snapshot/reset`
|
|
|
438
448
|
}
|
|
439
449
|
if (firstCustomRoute) {
|
|
440
450
|
const method = firstCustomRoute.method?.toUpperCase() ?? "GET";
|
|
441
|
-
const fullPath = `${host}${base}${firstCustomRoute.path}`;
|
|
451
|
+
const fullPath = `${host}${base}${escapeHtml(firstCustomRoute.path ?? "")}`;
|
|
442
452
|
const curlFlag = method === "GET" ? "" : `-X ${method} `;
|
|
443
453
|
examples.push(`# Custom route
|
|
444
454
|
curl ${curlFlag}${fullPath}`);
|
|
@@ -523,7 +533,8 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
523
533
|
desc = `Error injection \u2014 <code>${r.error}</code>`;
|
|
524
534
|
} else if (r.handler) {
|
|
525
535
|
const found = handlers.has(r.handler);
|
|
526
|
-
|
|
536
|
+
const handlerName = escapeHtml(r.handler);
|
|
537
|
+
desc = found ? `Handler \u2014 <code>${handlerName}()</code>` : `Handler \u2014 <code>${handlerName}()</code> <span style="color:#f85149">(not loaded)</span>`;
|
|
527
538
|
} else if (r.scenarios?.length) {
|
|
528
539
|
const hasTemplateInScenarios = r.scenarios.some((s) => s.response.body != null && hasTemplates(s.response.body)) || r.otherwise?.body != null && hasTemplates(r.otherwise.body);
|
|
529
540
|
desc = hasTemplateInScenarios ? `Scenarios \u2014 <code>{{\u2026}}</code>` : `Scenarios`;
|
|
@@ -801,6 +812,7 @@ function applyOperator(itemValue, op, filterValue) {
|
|
|
801
812
|
case "_start":
|
|
802
813
|
return strItem.toLowerCase().startsWith(filterValue.toLowerCase());
|
|
803
814
|
case "_regex": {
|
|
815
|
+
if (filterValue.length > 200) return false;
|
|
804
816
|
try {
|
|
805
817
|
return new RegExp(filterValue, "i").test(strItem);
|
|
806
818
|
} catch {
|
package/dist/index.mjs
CHANGED
|
@@ -168,8 +168,15 @@ import { resolve as resolve2 } from "path";
|
|
|
168
168
|
// src/utils/handlers.ts
|
|
169
169
|
init_esm_shims();
|
|
170
170
|
import { existsSync } from "fs";
|
|
171
|
+
var ALLOWED_EXTENSIONS = [".js", ".mjs", ".cjs"];
|
|
171
172
|
async function loadHandlers(filePath) {
|
|
172
173
|
if (!existsSync(filePath)) return /* @__PURE__ */ new Map();
|
|
174
|
+
if (!ALLOWED_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
|
|
175
|
+
console.error(
|
|
176
|
+
` \x1B[31m[handlers] ${filePath} \u2014 only .js, .mjs and .cjs files are allowed\x1B[0m`
|
|
177
|
+
);
|
|
178
|
+
return /* @__PURE__ */ new Map();
|
|
179
|
+
}
|
|
173
180
|
try {
|
|
174
181
|
const mod = await import(filePath);
|
|
175
182
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -275,8 +282,11 @@ var METHOD_COLOR = {
|
|
|
275
282
|
DELETE: "#f85149",
|
|
276
283
|
fn: "#f0883e"
|
|
277
284
|
};
|
|
285
|
+
function escapeHtml(str) {
|
|
286
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
287
|
+
}
|
|
278
288
|
function badge(label, color, bg) {
|
|
279
|
-
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${label}</span>`;
|
|
289
|
+
return `<span class="badge" style="background:${bg};color:${color};border:1px solid ${color}40">${escapeHtml(label)}</span>`;
|
|
280
290
|
}
|
|
281
291
|
function methodBadge(method) {
|
|
282
292
|
const color = METHOD_COLOR[method] ?? "#7d8590";
|
|
@@ -286,7 +296,7 @@ function endpointRow(method, path2, desc) {
|
|
|
286
296
|
return `
|
|
287
297
|
<tr>
|
|
288
298
|
<td class="method-cell">${methodBadge(method)}</td>
|
|
289
|
-
<td class="path-cell"><code>${path2}</code></td>
|
|
299
|
+
<td class="path-cell"><code>${escapeHtml(path2)}</code></td>
|
|
290
300
|
<td class="desc-cell">${desc}</td>
|
|
291
301
|
</tr>`;
|
|
292
302
|
}
|
|
@@ -320,7 +330,7 @@ function resourceAccordion(name, base, isOpen) {
|
|
|
320
330
|
return `
|
|
321
331
|
<details class="resource-card" ${isOpen ? "open" : ""}>
|
|
322
332
|
<summary>
|
|
323
|
-
<span class="resource-name">/${name}</span>
|
|
333
|
+
<span class="resource-name">/${escapeHtml(name)}</span>
|
|
324
334
|
<span class="route-count">6 routes</span>
|
|
325
335
|
</summary>
|
|
326
336
|
<table>
|
|
@@ -404,7 +414,7 @@ curl -X POST ${host}/_snapshot/reset`
|
|
|
404
414
|
}
|
|
405
415
|
if (firstCustomRoute) {
|
|
406
416
|
const method = firstCustomRoute.method?.toUpperCase() ?? "GET";
|
|
407
|
-
const fullPath = `${host}${base}${firstCustomRoute.path}`;
|
|
417
|
+
const fullPath = `${host}${base}${escapeHtml(firstCustomRoute.path ?? "")}`;
|
|
408
418
|
const curlFlag = method === "GET" ? "" : `-X ${method} `;
|
|
409
419
|
examples.push(`# Custom route
|
|
410
420
|
curl ${curlFlag}${fullPath}`);
|
|
@@ -489,7 +499,8 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
489
499
|
desc = `Error injection \u2014 <code>${r.error}</code>`;
|
|
490
500
|
} else if (r.handler) {
|
|
491
501
|
const found = handlers.has(r.handler);
|
|
492
|
-
|
|
502
|
+
const handlerName = escapeHtml(r.handler);
|
|
503
|
+
desc = found ? `Handler \u2014 <code>${handlerName}()</code>` : `Handler \u2014 <code>${handlerName}()</code> <span style="color:#f85149">(not loaded)</span>`;
|
|
493
504
|
} else if (r.scenarios?.length) {
|
|
494
505
|
const hasTemplateInScenarios = r.scenarios.some((s) => s.response.body != null && hasTemplates(s.response.body)) || r.otherwise?.body != null && hasTemplates(r.otherwise.body);
|
|
495
506
|
desc = hasTemplateInScenarios ? `Scenarios \u2014 <code>{{\u2026}}</code>` : `Scenarios`;
|
|
@@ -767,6 +778,7 @@ function applyOperator(itemValue, op, filterValue) {
|
|
|
767
778
|
case "_start":
|
|
768
779
|
return strItem.toLowerCase().startsWith(filterValue.toLowerCase());
|
|
769
780
|
case "_regex": {
|
|
781
|
+
if (filterValue.length > 200) return false;
|
|
770
782
|
try {
|
|
771
783
|
return new RegExp(filterValue, "i").test(strItem);
|
|
772
784
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yrest/cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "YAML-powered json-server alternative. Zero-config REST API mock server with full CRUD, relations, filters and snapshots from a db.yml file.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"yrest",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@eslint/js": "^10.0.1",
|
|
80
|
-
"@types/node": "^22.19.
|
|
80
|
+
"@types/node": "^22.19.21",
|
|
81
81
|
"eslint": "^10.4.1",
|
|
82
82
|
"eslint-config-prettier": "^10.1.8",
|
|
83
83
|
"prettier": "^3.8.3",
|
|
@@ -91,7 +91,8 @@
|
|
|
91
91
|
},
|
|
92
92
|
"socket": {
|
|
93
93
|
"allow": {
|
|
94
|
-
"filesystem": true
|
|
94
|
+
"filesystem": true,
|
|
95
|
+
"dynamic-require": true
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
}
|