@yrest/cli 0.7.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 +40 -1
- package/assets/logo-color.png +0 -0
- package/assets/logo-figure.png +0 -0
- package/assets/logo-text.png +0 -0
- package/assets/logo-white.png +0 -0
- package/assets/yRest-banner.png +0 -0
- package/dist/cli/index.js +98 -41
- package/dist/cli/index.mjs +77 -20
- package/dist/index.d.mts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +78 -23
- package/dist/index.mjs +69 -17
- package/package.json +12 -4
package/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="assets/yRest-banner.png" alt="yRest" width="100%" />
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<br/>
|
|
2
6
|
|
|
3
7
|
[](https://www.npmjs.com/package/@yrest/cli)
|
|
4
8
|
[](https://www.npmjs.com/package/@yrest/cli)
|
|
@@ -6,6 +10,7 @@
|
|
|
6
10
|
[](https://github.com/aggiovato/yRest/actions)
|
|
7
11
|
[](https://www.npmjs.com/package/@yrest/cli)
|
|
8
12
|
[](https://www.typescriptlang.org/)
|
|
13
|
+
[](https://socket.dev/npm/package/@yrest/cli)
|
|
9
14
|
|
|
10
15
|
YAML-powered json-server alternative. Zero-config REST API mock server with full CRUD, relations, filters and snapshots from a `db.yml` file.
|
|
11
16
|
|
|
@@ -157,6 +162,7 @@ npx @yrest/cli serve db.yml --handlers yrest.handlers.js
|
|
|
157
162
|
| `--pageable [n]` | `false` | Wrap GET collection responses in `{ data, pagination }`. Optional limit |
|
|
158
163
|
| `--snapshot` | `false` | Save initial state snapshot and expose `/_snapshot` endpoints |
|
|
159
164
|
| `--handlers <file>` | _(none)_ | Path to a JS file exporting handler functions for custom routes |
|
|
165
|
+
| `--id-strategy` | `increment` | Id generation for new items: `increment` (auto-int) or `uuid` |
|
|
160
166
|
|
|
161
167
|
All flags can also be set in `yrest.config.yml` (see below). CLI flags always take priority over the config file.
|
|
162
168
|
|
|
@@ -178,6 +184,7 @@ host: localhost
|
|
|
178
184
|
# pageable: false # true (limit 10), or a number (custom limit)
|
|
179
185
|
# snapshot: false
|
|
180
186
|
# handlers: yrest.handlers.js
|
|
187
|
+
# idStrategy: increment # increment or uuid
|
|
181
188
|
```
|
|
182
189
|
|
|
183
190
|
**Priority order** (highest wins): CLI flags → `yrest.config.yml` → schema defaults.
|
|
@@ -595,6 +602,36 @@ _routes:
|
|
|
595
602
|
body: { data: loaded }
|
|
596
603
|
```
|
|
597
604
|
|
|
605
|
+
### Error injection
|
|
606
|
+
|
|
607
|
+
Force a custom route to always return a specific HTTP error, regardless of handlers, scenarios or the static response. Useful for simulating outages, payment failures or auth errors:
|
|
608
|
+
|
|
609
|
+
```yaml
|
|
610
|
+
_routes:
|
|
611
|
+
- method: GET
|
|
612
|
+
path: /payments
|
|
613
|
+
error: 503
|
|
614
|
+
errorBody:
|
|
615
|
+
message: Service temporarily unavailable
|
|
616
|
+
retryAfter: 30
|
|
617
|
+
|
|
618
|
+
- method: POST
|
|
619
|
+
path: /checkout
|
|
620
|
+
error: 402
|
|
621
|
+
errorBody:
|
|
622
|
+
error: Payment required
|
|
623
|
+
|
|
624
|
+
- method: GET
|
|
625
|
+
path: /slow-failure
|
|
626
|
+
delay: 400
|
|
627
|
+
error: 500
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
- `error` takes priority over `handler`, `scenarios` and `response` — the route always returns this status.
|
|
631
|
+
- `errorBody` is optional. If omitted, the default body is `{ "error": "Forced error NNN" }`.
|
|
632
|
+
- `delay` still applies before the error is returned.
|
|
633
|
+
- Shown in `/_about` with a red `error·NNN` badge.
|
|
634
|
+
|
|
598
635
|
### Handler functions
|
|
599
636
|
|
|
600
637
|
For routes that need real logic (conditional responses, stateful mocks, request inspection), reference a JavaScript function via the `handler:` field:
|
|
@@ -960,6 +997,8 @@ const server = createYrestServer({
|
|
|
960
997
|
| Request validation with JSON Schema | 🔜 |
|
|
961
998
|
| Conditional scenarios (`scenarios:`, `otherwise:`) | ✅ |
|
|
962
999
|
| Per-route delay (`delay:`) | ✅ |
|
|
1000
|
+
| Error injection (`error:` in `_routes`) | ✅ |
|
|
1001
|
+
| Configurable ID strategy (`idStrategy`) | ✅ |
|
|
963
1002
|
|
|
964
1003
|
---
|
|
965
1004
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/cli/index.js
CHANGED
|
@@ -132,8 +132,8 @@ function registerInit(program2) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// src/cli/commands/serve.ts
|
|
135
|
-
var
|
|
136
|
-
var
|
|
135
|
+
var import_node_fs6 = require("fs");
|
|
136
|
+
var import_node_path4 = require("path");
|
|
137
137
|
|
|
138
138
|
// src/storage/yrestStorage.ts
|
|
139
139
|
var import_node_fs2 = require("fs");
|
|
@@ -223,6 +223,11 @@ function createYrestStorage(filePath) {
|
|
|
223
223
|
var import_fastify = __toESM(require("fastify"));
|
|
224
224
|
var import_cors = __toESM(require("@fastify/cors"));
|
|
225
225
|
|
|
226
|
+
// src/router/templates/about.template.ts
|
|
227
|
+
var import_node_fs3 = require("fs");
|
|
228
|
+
var import_node_path3 = require("path");
|
|
229
|
+
var import_node_url = require("url");
|
|
230
|
+
|
|
226
231
|
// src/utils/interpolate.ts
|
|
227
232
|
var import_node_crypto2 = require("crypto");
|
|
228
233
|
function getPath(obj, path) {
|
|
@@ -270,6 +275,15 @@ function hasTemplates(value) {
|
|
|
270
275
|
}
|
|
271
276
|
|
|
272
277
|
// src/router/templates/about.template.ts
|
|
278
|
+
var _dir = (0, import_node_path3.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
279
|
+
var LOGO_SRC = (() => {
|
|
280
|
+
try {
|
|
281
|
+
const buf = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)(_dir, "../../assets/logo-color.png"));
|
|
282
|
+
return `data:image/png;base64,${buf.toString("base64")}`;
|
|
283
|
+
} catch {
|
|
284
|
+
return "";
|
|
285
|
+
}
|
|
286
|
+
})();
|
|
273
287
|
var METHOD_COLOR = {
|
|
274
288
|
GET: "#3fb950",
|
|
275
289
|
POST: "#58a6ff",
|
|
@@ -278,8 +292,11 @@ var METHOD_COLOR = {
|
|
|
278
292
|
DELETE: "#f85149",
|
|
279
293
|
fn: "#f0883e"
|
|
280
294
|
};
|
|
295
|
+
function escapeHtml(str) {
|
|
296
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
297
|
+
}
|
|
281
298
|
function badge(label, color, bg) {
|
|
282
|
-
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>`;
|
|
283
300
|
}
|
|
284
301
|
function methodBadge(method) {
|
|
285
302
|
const color = METHOD_COLOR[method] ?? "#7d8590";
|
|
@@ -289,7 +306,7 @@ function endpointRow(method, path, desc) {
|
|
|
289
306
|
return `
|
|
290
307
|
<tr>
|
|
291
308
|
<td class="method-cell">${methodBadge(method)}</td>
|
|
292
|
-
<td class="path-cell"><code>${path}</code></td>
|
|
309
|
+
<td class="path-cell"><code>${escapeHtml(path)}</code></td>
|
|
293
310
|
<td class="desc-cell">${desc}</td>
|
|
294
311
|
</tr>`;
|
|
295
312
|
}
|
|
@@ -323,7 +340,7 @@ function resourceAccordion(name, base, isOpen) {
|
|
|
323
340
|
return `
|
|
324
341
|
<details class="resource-card" ${isOpen ? "open" : ""}>
|
|
325
342
|
<summary>
|
|
326
|
-
<span class="resource-name">/${name}</span>
|
|
343
|
+
<span class="resource-name">/${escapeHtml(name)}</span>
|
|
327
344
|
<span class="route-count">6 routes</span>
|
|
328
345
|
</summary>
|
|
329
346
|
<table>
|
|
@@ -407,7 +424,7 @@ curl -X POST ${host}/_snapshot/reset`
|
|
|
407
424
|
}
|
|
408
425
|
if (firstCustomRoute) {
|
|
409
426
|
const method = firstCustomRoute.method?.toUpperCase() ?? "GET";
|
|
410
|
-
const fullPath = `${host}${base}${firstCustomRoute.path}`;
|
|
427
|
+
const fullPath = `${host}${base}${escapeHtml(firstCustomRoute.path ?? "")}`;
|
|
411
428
|
const curlFlag = method === "GET" ? "" : `-X ${method} `;
|
|
412
429
|
examples.push(`# Custom route
|
|
413
430
|
curl ${curlFlag}${fullPath}`);
|
|
@@ -428,6 +445,8 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
428
445
|
modes.push(badge(`pageable \xB7 limit ${options.pageable.limit}`, "#34d399", "#34d39918"));
|
|
429
446
|
if (options.snapshot) modes.push(badge("snapshot", "#c084fc", "#c084fc18"));
|
|
430
447
|
if (handlers.size > 0) modes.push(badge(`handlers \xB7 ${handlers.size}`, "#f0883e", "#f0883e18"));
|
|
448
|
+
if (options.idStrategy !== "increment")
|
|
449
|
+
modes.push(badge(`id \xB7 ${options.idStrategy}`, "#a371f7", "#a371f718"));
|
|
431
450
|
const accordions = collections.map((col, i) => resourceAccordion(col, base, i === 0)).join("");
|
|
432
451
|
const nestedRows = [];
|
|
433
452
|
for (const [child, fields] of Object.entries(relations)) {
|
|
@@ -470,6 +489,9 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
470
489
|
${customRoutes.map((r) => {
|
|
471
490
|
const fullPath = `${base}${r.path}`;
|
|
472
491
|
const tags = [];
|
|
492
|
+
if (r.error) {
|
|
493
|
+
tags.push(`<span style="color:#f85149;font-size:11px">error\xB7${r.error}</span>`);
|
|
494
|
+
}
|
|
473
495
|
if (r.delay && r.delay > 0) {
|
|
474
496
|
tags.push(`<span style="color:#fb923c;font-size:11px">delay\xB7${r.delay}ms</span>`);
|
|
475
497
|
}
|
|
@@ -483,9 +505,12 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
483
505
|
tags.push(`<span style="color:var(--text-muted);font-size:11px">otherwise</span>`);
|
|
484
506
|
}
|
|
485
507
|
let desc;
|
|
486
|
-
if (r.
|
|
508
|
+
if (r.error) {
|
|
509
|
+
desc = `Error injection \u2014 <code>${r.error}</code>`;
|
|
510
|
+
} else if (r.handler) {
|
|
487
511
|
const found = handlers.has(r.handler);
|
|
488
|
-
|
|
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>`;
|
|
489
514
|
} else if (r.scenarios?.length) {
|
|
490
515
|
const hasTemplateInScenarios = r.scenarios.some((s) => s.response.body != null && hasTemplates(s.response.body)) || r.otherwise?.body != null && hasTemplates(r.otherwise.body);
|
|
491
516
|
desc = hasTemplateInScenarios ? `Scenarios \u2014 <code>{{\u2026}}</code>` : `Scenarios`;
|
|
@@ -647,7 +672,7 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
|
|
|
647
672
|
|
|
648
673
|
<div class="banner">
|
|
649
674
|
<div class="banner-inner">
|
|
650
|
-
|
|
675
|
+
${LOGO_SRC ? `<img src="${LOGO_SRC}" alt="yRest" height="68" style="display:block;margin-bottom:0px" />` : `<h1><span class="y">y</span><span class="rest">Rest</span></h1>`}
|
|
651
676
|
<p>Zero-config REST API mock server</p>
|
|
652
677
|
<div class="banner-meta">
|
|
653
678
|
<span>URL <strong>${host}</strong></span>
|
|
@@ -730,6 +755,10 @@ function nextId(items) {
|
|
|
730
755
|
const ids = items.map((i) => i["id"]).filter((id) => typeof id === "number");
|
|
731
756
|
return ids.length > 0 ? Math.max(...ids) + 1 : 1;
|
|
732
757
|
}
|
|
758
|
+
function generateId(items, strategy) {
|
|
759
|
+
if (strategy === "uuid") return crypto.randomUUID();
|
|
760
|
+
return nextId(items);
|
|
761
|
+
}
|
|
733
762
|
function firstParam(value) {
|
|
734
763
|
if (value === void 0) return void 0;
|
|
735
764
|
return Array.isArray(value) ? value[0] : value;
|
|
@@ -754,6 +783,7 @@ function applyOperator(itemValue, op, filterValue) {
|
|
|
754
783
|
case "_start":
|
|
755
784
|
return strItem.toLowerCase().startsWith(filterValue.toLowerCase());
|
|
756
785
|
case "_regex": {
|
|
786
|
+
if (filterValue.length > 200) return false;
|
|
757
787
|
try {
|
|
758
788
|
return new RegExp(filterValue, "i").test(strItem);
|
|
759
789
|
} catch {
|
|
@@ -817,10 +847,10 @@ function findById(items, id) {
|
|
|
817
847
|
function findIndexById(items, id) {
|
|
818
848
|
return items.findIndex((i) => String(i["id"]) === id);
|
|
819
849
|
}
|
|
820
|
-
function createItem(storage, resource, body) {
|
|
850
|
+
function createItem(storage, resource, body, idStrategy = "increment") {
|
|
821
851
|
const collection = storage.getCollection(resource) ?? [];
|
|
822
852
|
const item = {
|
|
823
|
-
id: body["id"] !== void 0 ? body["id"] :
|
|
853
|
+
id: body["id"] !== void 0 ? body["id"] : generateId(collection, idStrategy),
|
|
824
854
|
...body
|
|
825
855
|
};
|
|
826
856
|
storage.setCollection(resource, [...collection, item]);
|
|
@@ -998,7 +1028,12 @@ var CollectionRouteCommand = class {
|
|
|
998
1028
|
if (!req.body || typeof req.body !== "object" || Array.isArray(req.body)) {
|
|
999
1029
|
return reply.status(400).send({ error: "Request body must be a JSON object" });
|
|
1000
1030
|
}
|
|
1001
|
-
const item = createItem(
|
|
1031
|
+
const item = createItem(
|
|
1032
|
+
this.storage,
|
|
1033
|
+
this.resource,
|
|
1034
|
+
req.body,
|
|
1035
|
+
this.options.idStrategy
|
|
1036
|
+
);
|
|
1002
1037
|
return reply.status(201).send(expandItems(item, req.query, this.resource, this.storage));
|
|
1003
1038
|
});
|
|
1004
1039
|
}
|
|
@@ -1088,6 +1123,10 @@ var CustomRouteCommand = class {
|
|
|
1088
1123
|
if (route.delay && route.delay > 0) {
|
|
1089
1124
|
await new Promise((resolve5) => setTimeout(resolve5, route.delay));
|
|
1090
1125
|
}
|
|
1126
|
+
if (route.error) {
|
|
1127
|
+
const body2 = route.errorBody ?? { error: `Forced error ${route.error}` };
|
|
1128
|
+
return reply.status(route.error).send(body2);
|
|
1129
|
+
}
|
|
1091
1130
|
for (const [key, value] of Object.entries(headers)) {
|
|
1092
1131
|
reply.header(key, value);
|
|
1093
1132
|
}
|
|
@@ -1384,22 +1423,36 @@ var yrestOptionsSchema = import_zod.z.object({
|
|
|
1384
1423
|
pageable: import_zod.z.union([import_zod.z.boolean(), import_zod.z.coerce.number().int().positive()]).default(false).transform((v) => ({
|
|
1385
1424
|
enabled: v !== false,
|
|
1386
1425
|
limit: v === false || v === true ? 10 : v
|
|
1387
|
-
}))
|
|
1426
|
+
})),
|
|
1427
|
+
/**
|
|
1428
|
+
* Strategy used to generate `id` values for new items when no `id` is provided in the body.
|
|
1429
|
+
*
|
|
1430
|
+
* - `"increment"` (default) — next integer above the current max id in the collection.
|
|
1431
|
+
* - `"uuid"` — a random UUID v4 string (`crypto.randomUUID()`).
|
|
1432
|
+
*/
|
|
1433
|
+
idStrategy: import_zod.z.enum(["increment", "uuid"]).default("increment")
|
|
1388
1434
|
});
|
|
1389
1435
|
|
|
1390
1436
|
// src/config/loadConfigFile.ts
|
|
1391
|
-
var
|
|
1437
|
+
var import_node_fs4 = require("fs");
|
|
1392
1438
|
var import_yaml2 = require("yaml");
|
|
1393
1439
|
function loadConfigFile(configPath) {
|
|
1394
|
-
if (!(0,
|
|
1395
|
-
const raw = (0,
|
|
1440
|
+
if (!(0, import_node_fs4.existsSync)(configPath)) return {};
|
|
1441
|
+
const raw = (0, import_node_fs4.readFileSync)(configPath, "utf8");
|
|
1396
1442
|
return (0, import_yaml2.parse)(raw) ?? {};
|
|
1397
1443
|
}
|
|
1398
1444
|
|
|
1399
1445
|
// src/utils/handlers.ts
|
|
1400
|
-
var
|
|
1446
|
+
var import_node_fs5 = require("fs");
|
|
1447
|
+
var ALLOWED_EXTENSIONS = [".js", ".mjs", ".cjs"];
|
|
1401
1448
|
async function loadHandlers(filePath) {
|
|
1402
|
-
if (!(0,
|
|
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
|
+
}
|
|
1403
1456
|
try {
|
|
1404
1457
|
const mod = await import(filePath);
|
|
1405
1458
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -1429,8 +1482,12 @@ function registerServe(program2) {
|
|
|
1429
1482
|
).option(
|
|
1430
1483
|
"--handlers <file>",
|
|
1431
1484
|
"Path to a JavaScript file exporting custom route handler functions"
|
|
1485
|
+
).option(
|
|
1486
|
+
"--id-strategy <strategy>",
|
|
1487
|
+
"Id generation strategy for new items: increment (default) or uuid",
|
|
1488
|
+
"increment"
|
|
1432
1489
|
).action(async (file, flags, cmd) => {
|
|
1433
|
-
const fileConfig = loadConfigFile((0,
|
|
1490
|
+
const fileConfig = loadConfigFile((0, import_node_path4.join)(process.cwd(), "yrest.config.yml"));
|
|
1434
1491
|
const cliOverrides = Object.fromEntries(
|
|
1435
1492
|
Object.entries(flags).filter(([key]) => cmd.getOptionValueSource(key) === "cli")
|
|
1436
1493
|
);
|
|
@@ -1449,7 +1506,7 @@ function registerServe(program2) {
|
|
|
1449
1506
|
console.error(`Error: cannot load "${options.file}" \u2014 ${msg}`);
|
|
1450
1507
|
process.exit(1);
|
|
1451
1508
|
}
|
|
1452
|
-
const handlers = options.handlers ? await loadHandlers((0,
|
|
1509
|
+
const handlers = options.handlers ? await loadHandlers((0, import_node_path4.resolve)(options.handlers)) : /* @__PURE__ */ new Map();
|
|
1453
1510
|
const yrestServer = createYrestServerFromStorage(storage, options, handlers);
|
|
1454
1511
|
await yrestServer.start();
|
|
1455
1512
|
const collections = Object.keys(storage.getData());
|
|
@@ -1511,9 +1568,9 @@ function registerServe(program2) {
|
|
|
1511
1568
|
${dim(modes.map((m) => `[${m}]`).join(" "))}`);
|
|
1512
1569
|
console.log("");
|
|
1513
1570
|
if (options.watch) {
|
|
1514
|
-
const absFile = (0,
|
|
1571
|
+
const absFile = (0, import_node_path4.resolve)(options.file);
|
|
1515
1572
|
let debounce;
|
|
1516
|
-
(0,
|
|
1573
|
+
(0, import_node_fs6.watchFile)(absFile, { interval: 300 }, (curr, prev) => {
|
|
1517
1574
|
if (curr.mtimeMs === prev.mtimeMs) return;
|
|
1518
1575
|
clearTimeout(debounce);
|
|
1519
1576
|
debounce = setTimeout(() => {
|
|
@@ -1533,8 +1590,8 @@ function registerServe(program2) {
|
|
|
1533
1590
|
}
|
|
1534
1591
|
|
|
1535
1592
|
// src/cli/commands/handler.ts
|
|
1536
|
-
var
|
|
1537
|
-
var
|
|
1593
|
+
var import_node_fs7 = require("fs");
|
|
1594
|
+
var import_node_path5 = require("path");
|
|
1538
1595
|
var import_yaml3 = require("yaml");
|
|
1539
1596
|
var HANDLERS_FILE_HEADER = `// yrest handlers \u2014 loaded via "handlers:" in yrest.config.yml
|
|
1540
1597
|
// Handler signature: (req: HandlerRequest) => HandlerResponse | Promise<HandlerResponse>
|
|
@@ -1561,44 +1618,44 @@ function registerHandler(program2) {
|
|
|
1561
1618
|
"--register",
|
|
1562
1619
|
"Also add a _routes entry to db.yml linking this handler to method + path"
|
|
1563
1620
|
).action((name, flags) => {
|
|
1564
|
-
const fileConfig = loadConfigFile((0,
|
|
1565
|
-
const handlersPath = (0,
|
|
1621
|
+
const fileConfig = loadConfigFile((0, import_node_path5.join)(process.cwd(), "yrest.config.yml"));
|
|
1622
|
+
const handlersPath = (0, import_node_path5.resolve)(
|
|
1566
1623
|
fileConfig.handlers ?? "yrest.handlers.js"
|
|
1567
1624
|
);
|
|
1568
|
-
const dbPath = (0,
|
|
1569
|
-
if (!(0,
|
|
1570
|
-
(0,
|
|
1625
|
+
const dbPath = (0, import_node_path5.resolve)(fileConfig.file ?? "db.yml");
|
|
1626
|
+
if (!(0, import_node_fs7.existsSync)(handlersPath)) {
|
|
1627
|
+
(0, import_node_fs7.writeFileSync)(
|
|
1571
1628
|
handlersPath,
|
|
1572
1629
|
HANDLERS_FILE_HEADER + buildStub(name, flags.method, flags.path),
|
|
1573
1630
|
"utf8"
|
|
1574
1631
|
);
|
|
1575
|
-
console.log(` Created ${(0,
|
|
1632
|
+
console.log(` Created ${(0, import_node_path5.basename)(handlersPath)}`);
|
|
1576
1633
|
} else {
|
|
1577
|
-
const existing = (0,
|
|
1634
|
+
const existing = (0, import_node_fs7.readFileSync)(handlersPath, "utf8");
|
|
1578
1635
|
if (existing.includes(`function ${name}(`)) {
|
|
1579
|
-
console.error(` Error: handler "${name}" already exists in ${(0,
|
|
1636
|
+
console.error(` Error: handler "${name}" already exists in ${(0, import_node_path5.basename)(handlersPath)}`);
|
|
1580
1637
|
process.exit(1);
|
|
1581
1638
|
}
|
|
1582
|
-
(0,
|
|
1583
|
-
console.log(` Added handler "${name}" to ${(0,
|
|
1639
|
+
(0, import_node_fs7.appendFileSync)(handlersPath, buildStub(name, flags.method, flags.path), "utf8");
|
|
1640
|
+
console.log(` Added handler "${name}" to ${(0, import_node_path5.basename)(handlersPath)}`);
|
|
1584
1641
|
}
|
|
1585
1642
|
if (flags.register) {
|
|
1586
1643
|
if (!flags.method || !flags.path) {
|
|
1587
1644
|
console.error(" Error: --register requires --method and --path");
|
|
1588
1645
|
process.exit(1);
|
|
1589
1646
|
}
|
|
1590
|
-
if (!(0,
|
|
1647
|
+
if (!(0, import_node_fs7.existsSync)(dbPath)) {
|
|
1591
1648
|
console.error(` Error: database file not found at ${dbPath}`);
|
|
1592
1649
|
process.exit(1);
|
|
1593
1650
|
}
|
|
1594
|
-
const raw = (0, import_yaml3.parse)((0,
|
|
1651
|
+
const raw = (0, import_yaml3.parse)((0, import_node_fs7.readFileSync)(dbPath, "utf8")) ?? {};
|
|
1595
1652
|
if (!Array.isArray(raw["_routes"])) raw["_routes"] = [];
|
|
1596
1653
|
const routes = raw["_routes"];
|
|
1597
1654
|
const alreadyRegistered = routes.some((r) => r["handler"] === name);
|
|
1598
1655
|
if (!alreadyRegistered) {
|
|
1599
1656
|
routes.push({ method: flags.method.toUpperCase(), path: flags.path, handler: name });
|
|
1600
|
-
(0,
|
|
1601
|
-
console.log(` Added _routes entry to ${(0,
|
|
1657
|
+
(0, import_node_fs7.writeFileSync)(dbPath, (0, import_yaml3.stringify)(raw), "utf8");
|
|
1658
|
+
console.log(` Added _routes entry to ${(0, import_node_path5.basename)(dbPath)}`);
|
|
1602
1659
|
} else {
|
|
1603
1660
|
console.log(` Handler "${name}" already in _routes \u2014 skipped`);
|
|
1604
1661
|
}
|
|
@@ -1606,10 +1663,10 @@ function registerHandler(program2) {
|
|
|
1606
1663
|
console.log(`
|
|
1607
1664
|
Next steps:`);
|
|
1608
1665
|
if (!fileConfig.handlers) {
|
|
1609
|
-
console.log(` 1. Add handlers: ${(0,
|
|
1610
|
-
console.log(` 2. Implement the "${name}" function in ${(0,
|
|
1666
|
+
console.log(` 1. Add handlers: ${(0, import_node_path5.basename)(handlersPath)} to yrest.config.yml`);
|
|
1667
|
+
console.log(` 2. Implement the "${name}" function in ${(0, import_node_path5.basename)(handlersPath)}`);
|
|
1611
1668
|
} else {
|
|
1612
|
-
console.log(` 1. Implement the "${name}" function in ${(0,
|
|
1669
|
+
console.log(` 1. Implement the "${name}" function in ${(0, import_node_path5.basename)(handlersPath)}`);
|
|
1613
1670
|
}
|
|
1614
1671
|
if (!flags.register) {
|
|
1615
1672
|
console.log(
|