@yrest/cli 0.5.3 → 0.7.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/dist/index.js CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,20 +30,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
30
- // src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
33
- createServer: () => createServer,
34
- createYamlStorage: () => createYamlStorage,
35
- serverOptionsSchema: () => serverOptionsSchema
33
+ // node_modules/tsup/assets/cjs_shims.js
34
+ var init_cjs_shims = __esm({
35
+ "node_modules/tsup/assets/cjs_shims.js"() {
36
+ "use strict";
37
+ }
36
38
  });
37
- module.exports = __toCommonJS(src_exports);
38
-
39
- // src/storage/yamlStorage.ts
40
- var import_node_fs = require("fs");
41
- var import_node_path = require("path");
42
- var import_node_crypto = require("crypto");
43
- var import_yaml = require("yaml");
44
39
 
45
40
  // src/utils/deepCopy.ts
46
41
  function deepCopyData(source) {
@@ -48,11 +43,21 @@ function deepCopyData(source) {
48
43
  Object.entries(source).map(([k, v]) => [k, v.map((item) => ({ ...item }))])
49
44
  );
50
45
  }
46
+ var init_deepCopy = __esm({
47
+ "src/utils/deepCopy.ts"() {
48
+ "use strict";
49
+ init_cjs_shims();
50
+ }
51
+ });
51
52
 
52
- // src/storage/yamlStorage.ts
53
- function createYamlStorage(filePath) {
53
+ // src/storage/yrestStorage.ts
54
+ var yrestStorage_exports = {};
55
+ __export(yrestStorage_exports, {
56
+ createYrestStorage: () => createYrestStorage
57
+ });
58
+ function createYrestStorage(filePath) {
54
59
  const absPath = (0, import_node_path.resolve)(filePath);
55
- const raw = (0, import_yaml.parse)((0, import_node_fs.readFileSync)(absPath, "utf8")) ?? {};
60
+ const raw = (0, import_yaml2.parse)((0, import_node_fs2.readFileSync)(absPath, "utf8")) ?? {};
56
61
  const relations = raw["_rel"] ?? {};
57
62
  const routes = Array.isArray(raw["_routes"]) ? raw["_routes"] : [];
58
63
  const data = Object.fromEntries(
@@ -84,12 +89,12 @@ function createYamlStorage(filePath) {
84
89
  if (Object.keys(relations).length > 0) payload._rel = relations;
85
90
  if (routes.length > 0) payload._routes = routes;
86
91
  Object.assign(payload, data);
87
- const tmp = (0, import_node_path.resolve)((0, import_node_path.dirname)(absPath), `.yrest-${(0, import_node_crypto.randomUUID)()}.tmp`);
88
- (0, import_node_fs.writeFileSync)(tmp, (0, import_yaml.stringify)(payload), "utf8");
89
- (0, import_node_fs.renameSync)(tmp, absPath);
92
+ const tmp = (0, import_node_path.resolve)((0, import_node_path.dirname)(absPath), `.yrest-${(0, import_node_crypto2.randomUUID)()}.tmp`);
93
+ (0, import_node_fs2.writeFileSync)(tmp, (0, import_yaml2.stringify)(payload), "utf8");
94
+ (0, import_node_fs2.renameSync)(tmp, absPath);
90
95
  },
91
96
  reload() {
92
- const fresh = (0, import_yaml.parse)((0, import_node_fs.readFileSync)(absPath, "utf8")) ?? {};
97
+ const fresh = (0, import_yaml2.parse)((0, import_node_fs2.readFileSync)(absPath, "utf8")) ?? {};
93
98
  const freshRelations = fresh["_rel"] ?? {};
94
99
  const freshData = Object.fromEntries(
95
100
  Object.entries(fresh).filter(([key]) => key !== "_rel" && key !== "_routes")
@@ -119,13 +124,123 @@ function createYamlStorage(filePath) {
119
124
  }
120
125
  };
121
126
  }
127
+ var import_node_fs2, import_node_path, import_node_crypto2, import_yaml2;
128
+ var init_yrestStorage = __esm({
129
+ "src/storage/yrestStorage.ts"() {
130
+ "use strict";
131
+ init_cjs_shims();
132
+ import_node_fs2 = require("fs");
133
+ import_node_path = require("path");
134
+ import_node_crypto2 = require("crypto");
135
+ import_yaml2 = require("yaml");
136
+ init_deepCopy();
137
+ }
138
+ });
139
+
140
+ // src/index.ts
141
+ var src_exports = {};
142
+ __export(src_exports, {
143
+ createServer: () => createServer,
144
+ createYrestServer: () => createYrestServer,
145
+ createYrestServerFromStorage: () => createYrestServerFromStorage,
146
+ createYrestStorage: () => createYrestStorage,
147
+ yrest: () => yrest,
148
+ yrestOptionsSchema: () => yrestOptionsSchema
149
+ });
150
+ module.exports = __toCommonJS(src_exports);
151
+ init_cjs_shims();
152
+
153
+ // src/api/yrest.ts
154
+ init_cjs_shims();
155
+ var import_yaml = require("yaml");
156
+ function yrest(strings, ...values) {
157
+ const raw = strings.reduce(
158
+ (acc, str, i) => acc + str + (values[i] !== void 0 ? stringifyInterpolation(values[i]) : ""),
159
+ ""
160
+ );
161
+ const dedented = dedent(raw);
162
+ let parsed;
163
+ try {
164
+ parsed = (0, import_yaml.parse)(dedented);
165
+ } catch (e) {
166
+ throw new Error(`[yrest] Invalid YAML: ${e instanceof Error ? e.message : String(e)}`, {
167
+ cause: e
168
+ });
169
+ }
170
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
171
+ throw new Error("[yrest] Template must resolve to a YAML object with collection keys.");
172
+ }
173
+ return parsed;
174
+ }
175
+ function stringifyInterpolation(value) {
176
+ if (value === null || value === void 0) return String(value);
177
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
178
+ return String(value);
179
+ }
180
+ const type = Array.isArray(value) ? "array" : typeof value;
181
+ throw new Error(
182
+ `[yrest] Cannot interpolate a value of type "${type}". Only string, number, and boolean are supported.`
183
+ );
184
+ }
185
+ function dedent(str) {
186
+ const lines = str.split("\n");
187
+ const minIndent = lines.filter((line) => line.trim().length > 0).reduce((min, line) => {
188
+ const match = line.match(/^(\s*)/);
189
+ return Math.min(min, match ? match[1].length : 0);
190
+ }, Infinity);
191
+ const indent = minIndent === Infinity ? 0 : minIndent;
192
+ return lines.map((line) => line.slice(indent)).join("\n").trim();
193
+ }
194
+
195
+ // src/api/yrestServer.ts
196
+ init_cjs_shims();
197
+ var import_node_path2 = require("path");
198
+
199
+ // src/utils/handlers.ts
200
+ init_cjs_shims();
201
+ var import_node_fs = require("fs");
202
+ async function loadHandlers(filePath) {
203
+ if (!(0, import_node_fs.existsSync)(filePath)) return /* @__PURE__ */ new Map();
204
+ try {
205
+ const mod = await import(filePath);
206
+ const map = /* @__PURE__ */ new Map();
207
+ for (const [name, value] of Object.entries(mod)) {
208
+ if (typeof value === "function") map.set(name, value);
209
+ }
210
+ return map;
211
+ } catch (err) {
212
+ const msg = err instanceof Error ? err.message : String(err);
213
+ console.error(` \x1B[31m[handlers] failed to load ${filePath} \u2014 ${msg}\x1B[0m`);
214
+ return /* @__PURE__ */ new Map();
215
+ }
216
+ }
217
+
218
+ // src/api/yrestServer.ts
219
+ init_deepCopy();
220
+
221
+ // src/server/index.ts
222
+ init_cjs_shims();
122
223
 
123
224
  // src/server/createServer.ts
225
+ init_cjs_shims();
124
226
  var import_fastify = __toESM(require("fastify"));
125
227
  var import_cors = __toESM(require("@fastify/cors"));
126
228
 
229
+ // src/router/resource.router.ts
230
+ init_cjs_shims();
231
+
232
+ // src/router/routes/index.ts
233
+ init_cjs_shims();
234
+
235
+ // src/router/routes/about.routes.ts
236
+ init_cjs_shims();
237
+
238
+ // src/router/templates/about.template.ts
239
+ init_cjs_shims();
240
+
127
241
  // src/utils/interpolate.ts
128
- var import_node_crypto2 = require("crypto");
242
+ init_cjs_shims();
243
+ var import_node_crypto = require("crypto");
129
244
  function getPath(obj, path) {
130
245
  return path.split(".").reduce((acc, key) => {
131
246
  if (acc != null && typeof acc === "object") return acc[key];
@@ -134,7 +249,7 @@ function getPath(obj, path) {
134
249
  }
135
250
  function resolveVar(path, ctx) {
136
251
  if (path === "now") return (/* @__PURE__ */ new Date()).toISOString();
137
- if (path === "uuid") return (0, import_node_crypto2.randomUUID)();
252
+ if (path === "uuid") return (0, import_node_crypto.randomUUID)();
138
253
  if (path === "body") return ctx.body;
139
254
  if (path.startsWith("body.")) return getPath(ctx.body, path.slice(5));
140
255
  if (path.startsWith("params.")) return ctx.params[path.slice(7)] ?? "";
@@ -370,16 +485,33 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
370
485
  <table><tbody>
371
486
  ${customRoutes.map((r) => {
372
487
  const fullPath = `${base}${r.path}`;
488
+ const tags = [];
489
+ if (r.delay && r.delay > 0) {
490
+ tags.push(`<span style="color:#fb923c;font-size:11px">delay\xB7${r.delay}ms</span>`);
491
+ }
492
+ if (r.scenarios?.length) {
493
+ const hasOr = r.scenarios.some((s) => Array.isArray(s.when));
494
+ tags.push(
495
+ `<span style="color:#a371f7;font-size:11px">scenarios\xB7${r.scenarios.length}${hasOr ? " (OR)" : ""}</span>`
496
+ );
497
+ }
498
+ if (r.otherwise) {
499
+ tags.push(`<span style="color:var(--text-muted);font-size:11px">otherwise</span>`);
500
+ }
373
501
  let desc;
374
502
  if (r.handler) {
375
503
  const found = handlers.has(r.handler);
376
504
  desc = found ? `Handler \u2014 <code>${r.handler}()</code>` : `Handler \u2014 <code>${r.handler}()</code> <span style="color:#f85149">(not loaded)</span>`;
505
+ } else if (r.scenarios?.length) {
506
+ const hasTemplateInScenarios = r.scenarios.some((s) => s.response.body != null && hasTemplates(s.response.body)) || r.otherwise?.body != null && hasTemplates(r.otherwise.body);
507
+ desc = hasTemplateInScenarios ? `Scenarios \u2014 <code>{{\u2026}}</code>` : `Scenarios`;
377
508
  } else if (r.response?.body != null && hasTemplates(r.response.body)) {
378
- desc = `Dynamic body \u2014 <code>{{\u2026}}</code>`;
509
+ desc = `Dynamic \u2014 <code>{{\u2026}}</code>`;
379
510
  } else {
380
511
  const status = r.response?.status ?? 200;
381
- desc = `Static \u2014 <code>${status}</code>${r.response?.headers ? ` + custom headers` : ""}`;
512
+ desc = `Static \u2014 <code>${status}</code>${r.response?.headers ? ` + headers` : ""}`;
382
513
  }
514
+ if (tags.length) desc += `&ensp;${tags.join("&ensp;")}`;
383
515
  return endpointRow(r.method?.toUpperCase() ?? "GET", fullPath, desc);
384
516
  }).join("")}
385
517
  </tbody></table>
@@ -531,7 +663,7 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
531
663
 
532
664
  <div class="banner">
533
665
  <div class="banner-inner">
534
- <h1><span class="y">y</span><span class="rest">rest</span></h1>
666
+ <h1><span class="y">y</span><span class="rest">Rest</span></h1>
535
667
  <p>Zero-config REST API mock server</p>
536
668
  <div class="banner-meta">
537
669
  <span>URL <strong>${host}</strong></span>
@@ -583,7 +715,7 @@ function generateAboutHtml(storage, options, handlers = /* @__PURE__ */ new Map(
583
715
  ${collections.length ? `<h2>Examples</h2><div class="card">${examplesBlock(collections, relations, base, host, options, customRoutes[0])}</div>` : ""}
584
716
 
585
717
  <footer>
586
- Powered by <a href="https://github.com/aggiovato/yaml-rest" target="_blank">@aggiovato/yrest</a> &nbsp;\xB7&nbsp; <a href="/_about">/_about</a>
718
+ Powered by <a href="https://github.com/aggiovato/yRest" target="_blank">@yrest/cli</a> &nbsp;\xB7&nbsp; <a href="/_about">/_about</a>
587
719
  </footer>
588
720
 
589
721
  </div>
@@ -609,7 +741,11 @@ var AboutRouteCommand = class {
609
741
  }
610
742
  };
611
743
 
744
+ // src/router/routes/collection.routes.ts
745
+ init_cjs_shims();
746
+
612
747
  // src/utils/params.ts
748
+ init_cjs_shims();
613
749
  function nextId(items) {
614
750
  const ids = items.map((i) => i["id"]).filter((id) => typeof id === "number");
615
751
  return ids.length > 0 ? Math.max(...ids) + 1 : 1;
@@ -620,6 +756,7 @@ function firstParam(value) {
620
756
  }
621
757
 
622
758
  // src/services/query.service.ts
759
+ init_cjs_shims();
623
760
  var OPERATORS = ["_gte", "_lte", "_ne", "_like", "_start", "_regex"];
624
761
  function applyOperator(itemValue, op, filterValue) {
625
762
  const strItem = String(itemValue);
@@ -695,6 +832,7 @@ function paginate(items, page, limit) {
695
832
  }
696
833
 
697
834
  // src/services/resource.service.ts
835
+ init_cjs_shims();
698
836
  function findById(items, id) {
699
837
  return items.find((i) => String(i["id"]) === id);
700
838
  }
@@ -742,6 +880,7 @@ function deleteItem(storage, resource, id) {
742
880
  }
743
881
 
744
882
  // src/services/expand.service.ts
883
+ init_cjs_shims();
745
884
  function expandItems(input, query, resource, storage) {
746
885
  const isArray = Array.isArray(input);
747
886
  const items = isArray ? input : [input];
@@ -889,6 +1028,66 @@ var CollectionRouteCommand = class {
889
1028
  };
890
1029
 
891
1030
  // src/router/routes/custom.routes.ts
1031
+ init_cjs_shims();
1032
+
1033
+ // src/utils/conditions.ts
1034
+ init_cjs_shims();
1035
+ function resolveRequestPath(dotPath, req) {
1036
+ const [root, ...rest] = dotPath.split(".");
1037
+ let value;
1038
+ switch (root) {
1039
+ case "body":
1040
+ value = req.body;
1041
+ break;
1042
+ case "params":
1043
+ value = req.params;
1044
+ break;
1045
+ case "query":
1046
+ value = req.query;
1047
+ break;
1048
+ case "headers":
1049
+ value = req.headers;
1050
+ break;
1051
+ default:
1052
+ return void 0;
1053
+ }
1054
+ for (const key of rest) {
1055
+ if (value != null && typeof value === "object") {
1056
+ value = value[key];
1057
+ } else {
1058
+ return void 0;
1059
+ }
1060
+ }
1061
+ return value;
1062
+ }
1063
+ function matchConditionGroup(group, req) {
1064
+ return Object.entries(group).every(([key, expected]) => {
1065
+ const op = OPERATORS.find((o) => key.endsWith(o));
1066
+ if (op) {
1067
+ const path = key.slice(0, -op.length);
1068
+ const value2 = resolveRequestPath(path, req);
1069
+ if (value2 === void 0) return false;
1070
+ return applyOperator(value2, op, String(expected));
1071
+ }
1072
+ const value = resolveRequestPath(key, req);
1073
+ return String(value) === String(expected);
1074
+ });
1075
+ }
1076
+ function matchWhen(when, req) {
1077
+ if (Array.isArray(when)) {
1078
+ return when.some((group) => matchConditionGroup(group, req));
1079
+ }
1080
+ return matchConditionGroup(when, req);
1081
+ }
1082
+ function findMatchingScenario(scenarios, req) {
1083
+ return scenarios.find((s) => matchWhen(s.when, req));
1084
+ }
1085
+
1086
+ // src/router/routes/custom.routes.ts
1087
+ function resolveBody(body, ctx) {
1088
+ if (body != null && hasTemplates(body)) return interpolate(body, ctx);
1089
+ return body ?? null;
1090
+ }
892
1091
  var CustomRouteCommand = class {
893
1092
  constructor(storage, base, handlers = /* @__PURE__ */ new Map()) {
894
1093
  this.storage = storage;
@@ -913,6 +1112,9 @@ var CustomRouteCommand = class {
913
1112
  method,
914
1113
  url,
915
1114
  handler: async (req, reply) => {
1115
+ if (route.delay && route.delay > 0) {
1116
+ await new Promise((resolve3) => setTimeout(resolve3, route.delay));
1117
+ }
916
1118
  for (const [key, value] of Object.entries(headers)) {
917
1119
  reply.header(key, value);
918
1120
  }
@@ -922,13 +1124,13 @@ var CustomRouteCommand = class {
922
1124
  return reply.status(501).send({ error: `Handler "${handlerName}" is not defined in the handlers file` });
923
1125
  }
924
1126
  try {
925
- const ctx = {
1127
+ const ctx2 = {
926
1128
  params: req.params,
927
1129
  query: req.query,
928
1130
  body: req.body,
929
1131
  headers: req.headers
930
1132
  };
931
- const result = await fn(ctx);
1133
+ const result = await fn(ctx2);
932
1134
  const resStatus = result.status ?? 200;
933
1135
  for (const [k, v] of Object.entries(result.headers ?? {})) {
934
1136
  reply.header(k, v);
@@ -940,12 +1142,24 @@ var CustomRouteCommand = class {
940
1142
  return reply.status(500).send({ error: `Handler "${handlerName}" threw an error: ${msg}` });
941
1143
  }
942
1144
  }
943
- const body = dynamic ? interpolate(rawBody, {
1145
+ const ctx = {
944
1146
  params: req.params,
945
1147
  query: req.query,
946
1148
  body: req.body,
947
1149
  headers: req.headers
948
- }) : rawBody;
1150
+ };
1151
+ if (route.scenarios?.length) {
1152
+ const matched = findMatchingScenario(route.scenarios, ctx);
1153
+ const active = matched?.response ?? route.otherwise;
1154
+ if (active) {
1155
+ const aStatus = active.status ?? 200;
1156
+ const aBody = resolveBody(active.body, ctx);
1157
+ for (const [k, v] of Object.entries(active.headers ?? {})) reply.header(k, v);
1158
+ if (!active.body && aStatus === 204) return reply.status(aStatus).send();
1159
+ return reply.status(aStatus).send(aBody);
1160
+ }
1161
+ }
1162
+ const body = dynamic ? interpolate(rawBody, ctx) : rawBody;
949
1163
  if (body === null && status === 204) return reply.status(status).send();
950
1164
  return reply.status(status).send(body);
951
1165
  }
@@ -955,6 +1169,7 @@ var CustomRouteCommand = class {
955
1169
  };
956
1170
 
957
1171
  // src/router/routes/item.routes.ts
1172
+ init_cjs_shims();
958
1173
  var ItemRouteCommand = class {
959
1174
  constructor(storage, resource, base) {
960
1175
  this.storage = storage;
@@ -1004,6 +1219,7 @@ var ItemRouteCommand = class {
1004
1219
  };
1005
1220
 
1006
1221
  // src/router/routes/nested.routes.ts
1222
+ init_cjs_shims();
1007
1223
  var NestedRouteCommand = class {
1008
1224
  constructor(storage, relations, base) {
1009
1225
  this.storage = storage;
@@ -1043,6 +1259,7 @@ var NestedRouteCommand = class {
1043
1259
  };
1044
1260
 
1045
1261
  // src/router/routes/snapshot.routes.ts
1262
+ init_cjs_shims();
1046
1263
  var SnapshotRouteCommand = class {
1047
1264
  constructor(storage) {
1048
1265
  this.storage = storage;
@@ -1132,9 +1349,119 @@ async function createServer(storage, options, handlers = /* @__PURE__ */ new Map
1132
1349
  return server;
1133
1350
  }
1134
1351
 
1352
+ // src/server/yrestServer.ts
1353
+ init_cjs_shims();
1354
+ function createYrestServerFromStorage(storage, options, handlers = /* @__PURE__ */ new Map()) {
1355
+ let _port = 0;
1356
+ let _started = false;
1357
+ let _fastify = null;
1358
+ return {
1359
+ async start() {
1360
+ if (_started) return;
1361
+ _fastify = await createServer(storage, options, handlers);
1362
+ await _fastify.listen({ port: options.port, host: options.host });
1363
+ const address = _fastify.addresses()[0];
1364
+ _port = typeof address === "object" && "port" in address ? address.port : options.port;
1365
+ _started = true;
1366
+ },
1367
+ async stop() {
1368
+ if (!_started || !_fastify) return;
1369
+ await _fastify.close();
1370
+ _started = false;
1371
+ },
1372
+ get port() {
1373
+ return _port;
1374
+ },
1375
+ get url() {
1376
+ return `http://${options.host}:${_port}${options.base}`;
1377
+ }
1378
+ };
1379
+ }
1380
+
1381
+ // src/api/yrestServer.ts
1382
+ function createYrestServer(options) {
1383
+ const resolvedOptions = buildOptions(options);
1384
+ let _inner = null;
1385
+ return {
1386
+ async start() {
1387
+ const storage = "data" in options && options.data !== void 0 ? createInMemoryStorage(options.data) : (await Promise.resolve().then(() => (init_yrestStorage(), yrestStorage_exports))).createYrestStorage(resolvedOptions.file);
1388
+ const handlers = resolvedOptions.handlers ? await loadHandlers((0, import_node_path2.resolve)(resolvedOptions.handlers)) : /* @__PURE__ */ new Map();
1389
+ _inner = createYrestServerFromStorage(storage, resolvedOptions, handlers);
1390
+ await _inner.start();
1391
+ },
1392
+ async stop() {
1393
+ await _inner?.stop();
1394
+ },
1395
+ get port() {
1396
+ return _inner?.port ?? 0;
1397
+ },
1398
+ get url() {
1399
+ return _inner?.url ?? "";
1400
+ }
1401
+ };
1402
+ }
1403
+ function buildOptions(opts) {
1404
+ const pageable = opts.pageable;
1405
+ return {
1406
+ file: "file" in opts && opts.file ? opts.file : "",
1407
+ port: opts.port ?? 3070,
1408
+ host: opts.host ?? "localhost",
1409
+ base: opts.base ? opts.base.startsWith("/") ? opts.base : `/${opts.base}` : "",
1410
+ watch: false,
1411
+ snapshot: opts.snapshot ?? false,
1412
+ readonly: opts.readonly ?? false,
1413
+ delay: opts.delay ?? 0,
1414
+ handlers: opts.handlers,
1415
+ pageable: typeof pageable === "number" ? { enabled: true, limit: pageable } : pageable ? { enabled: true, limit: 10 } : { enabled: false, limit: 10 }
1416
+ };
1417
+ }
1418
+ function createInMemoryStorage(data) {
1419
+ const raw = data;
1420
+ const relations = raw["_rel"] ?? {};
1421
+ const routes = Array.isArray(raw["_routes"]) ? raw["_routes"] : [];
1422
+ const collections = Object.fromEntries(
1423
+ Object.entries(raw).filter(([k]) => k !== "_rel" && k !== "_routes")
1424
+ );
1425
+ let snapshot = {
1426
+ data: deepCopyData(collections),
1427
+ relations: { ...relations },
1428
+ savedAt: /* @__PURE__ */ new Date()
1429
+ };
1430
+ return {
1431
+ getData: () => collections,
1432
+ getRelations: () => relations,
1433
+ getRoutes: () => routes,
1434
+ getCollection: (name) => collections[name],
1435
+ setCollection: (name, items) => {
1436
+ collections[name] = items;
1437
+ },
1438
+ persist: () => {
1439
+ },
1440
+ reload: () => {
1441
+ },
1442
+ getSnapshot: () => snapshot,
1443
+ saveSnapshot: () => {
1444
+ snapshot = {
1445
+ data: deepCopyData(collections),
1446
+ relations: { ...relations },
1447
+ savedAt: /* @__PURE__ */ new Date()
1448
+ };
1449
+ },
1450
+ resetToSnapshot: () => {
1451
+ const snap = deepCopyData(snapshot.data);
1452
+ for (const key of Object.keys(collections)) delete collections[key];
1453
+ Object.assign(collections, snap);
1454
+ }
1455
+ };
1456
+ }
1457
+
1458
+ // src/index.ts
1459
+ init_yrestStorage();
1460
+
1135
1461
  // src/config/loadOptions.ts
1462
+ init_cjs_shims();
1136
1463
  var import_zod = require("zod");
1137
- var serverOptionsSchema = import_zod.z.object({
1464
+ var yrestOptionsSchema = import_zod.z.object({
1138
1465
  /** Path to the YAML database file. Must be a non-empty string. */
1139
1466
  file: import_zod.z.string().min(1),
1140
1467
  /** TCP port the server listens on. Accepts string input and coerces to number. */
@@ -1174,6 +1501,9 @@ var serverOptionsSchema = import_zod.z.object({
1174
1501
  // Annotate the CommonJS export names for ESM import in node:
1175
1502
  0 && (module.exports = {
1176
1503
  createServer,
1177
- createYamlStorage,
1178
- serverOptionsSchema
1504
+ createYrestServer,
1505
+ createYrestServerFromStorage,
1506
+ createYrestStorage,
1507
+ yrest,
1508
+ yrestOptionsSchema
1179
1509
  });