resora 0.2.1 → 0.2.3

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.cjs CHANGED
@@ -1,553 +1,10 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- //#region \0rolldown/runtime.js
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
- key = keys[i];
13
- if (!__hasOwnProp.call(to, key) && key !== except) {
14
- __defProp(to, key, {
15
- get: ((k) => from[k]).bind(null, key),
16
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
- });
18
- }
19
- }
20
- }
21
- return to;
22
- };
23
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
- value: mod,
25
- enumerable: true
26
- }) : target, mod));
27
-
28
- //#endregion
29
- let fs = require("fs");
30
- let path = require("path");
31
- path = __toESM(path);
32
- let _h3ravel_musket = require("@h3ravel/musket");
33
-
34
- //#region src/ApiResource.ts
35
- /**
36
- * ApiResource function to return the Resource instance
37
- *
38
- * @param instance Resource instance
39
- * @returns Resource instance
40
- */
41
- function ApiResource(instance) {
42
- return instance;
43
- }
44
-
45
- //#endregion
46
- //#region src/utilities/state.ts
47
- let globalPreferredCase;
48
- let globalResponseStructure;
49
- let globalPaginatedExtras = ["meta", "links"];
50
- let globalPaginatedLinks = {
51
- first: "first",
52
- last: "last",
53
- prev: "prev",
54
- next: "next"
55
- };
56
- let globalBaseUrl = "https://localhost";
57
- let globalPageName = "page";
58
- let globalPaginatedMeta = {
59
- to: "to",
60
- from: "from",
61
- links: "links",
62
- path: "path",
63
- total: "total",
64
- per_page: "per_page",
65
- last_page: "last_page",
66
- current_page: "current_page"
67
- };
68
- let globalCursorMeta = {
69
- previous: "previous",
70
- next: "next"
71
- };
72
- const setGlobalCase = (style) => {
73
- globalPreferredCase = style;
74
- };
75
- const getGlobalCase = () => {
76
- return globalPreferredCase;
77
- };
78
- const setGlobalResponseStructure = (config) => {
79
- globalResponseStructure = config;
80
- };
81
- const getGlobalResponseStructure = () => {
82
- return globalResponseStructure;
83
- };
84
- const setGlobalResponseRootKey = (rootKey) => {
85
- globalResponseStructure = {
86
- ...globalResponseStructure || {},
87
- rootKey
88
- };
89
- };
90
- const setGlobalResponseWrap = (wrap) => {
91
- globalResponseStructure = {
92
- ...globalResponseStructure || {},
93
- wrap
94
- };
95
- };
96
- const getGlobalResponseWrap = () => {
97
- return globalResponseStructure?.wrap;
98
- };
99
- const getGlobalResponseRootKey = () => {
100
- return globalResponseStructure?.rootKey;
101
- };
102
- const setGlobalResponseFactory = (factory) => {
103
- globalResponseStructure = {
104
- ...globalResponseStructure || {},
105
- factory
106
- };
107
- };
108
- const getGlobalResponseFactory = () => {
109
- return globalResponseStructure?.factory;
110
- };
111
- const setGlobalPaginatedExtras = (extras) => {
112
- globalPaginatedExtras = extras;
113
- };
114
- const getGlobalPaginatedExtras = () => {
115
- return globalPaginatedExtras;
116
- };
117
- const setGlobalPaginatedLinks = (links) => {
118
- globalPaginatedLinks = {
119
- ...globalPaginatedLinks,
120
- ...links
121
- };
122
- };
123
- const getGlobalPaginatedLinks = () => {
124
- return globalPaginatedLinks;
125
- };
126
- const setGlobalBaseUrl = (baseUrl) => {
127
- globalBaseUrl = baseUrl;
128
- };
129
- const getGlobalBaseUrl = () => {
130
- return globalBaseUrl;
131
- };
132
- const setGlobalPageName = (pageName) => {
133
- globalPageName = pageName;
134
- };
135
- const getGlobalPageName = () => {
136
- return globalPageName;
137
- };
138
- const setGlobalPaginatedMeta = (meta) => {
139
- globalPaginatedMeta = {
140
- ...globalPaginatedMeta,
141
- ...meta
142
- };
143
- };
144
- const getGlobalPaginatedMeta = () => {
145
- return globalPaginatedMeta;
146
- };
147
- const setGlobalCursorMeta = (meta) => {
148
- globalCursorMeta = {
149
- ...globalCursorMeta,
150
- ...meta
151
- };
152
- };
153
- const getGlobalCursorMeta = () => {
154
- return globalCursorMeta;
155
- };
156
-
157
- //#endregion
158
- //#region src/utilities/pagination.ts
159
- const getPaginationExtraKeys = () => {
160
- const extras = getGlobalPaginatedExtras();
161
- if (Array.isArray(extras)) return {
162
- metaKey: extras.includes("meta") ? "meta" : void 0,
163
- linksKey: extras.includes("links") ? "links" : void 0,
164
- cursorKey: extras.includes("cursor") ? "cursor" : void 0
165
- };
166
- return {
167
- metaKey: extras.meta,
168
- linksKey: extras.links,
169
- cursorKey: extras.cursor
170
- };
171
- };
172
- const buildPageUrl = (page, pathName) => {
173
- if (typeof page === "undefined") return;
174
- const rawPath = pathName || "";
175
- const base = getGlobalBaseUrl() || "";
176
- const isAbsolutePath = /^https?:\/\//i.test(rawPath);
177
- const normalizedBase = base.replace(/\/$/, "");
178
- const normalizedPath = rawPath.replace(/^\//, "");
179
- const root = isAbsolutePath ? rawPath : normalizedBase ? normalizedPath ? `${normalizedBase}/${normalizedPath}` : normalizedBase : "";
180
- if (!root) return;
181
- const url = new URL(root);
182
- url.searchParams.set(getGlobalPageName() || "page", String(page));
183
- return url.toString();
184
- };
185
- const buildPaginationExtras = (resource) => {
186
- const { metaKey, linksKey, cursorKey } = getPaginationExtraKeys();
187
- const extra = {};
188
- const pagination = resource?.pagination;
189
- const cursor = resource?.cursor;
190
- const metaBlock = {};
191
- const linksBlock = {};
192
- if (pagination) {
193
- const metaSource = {
194
- to: pagination.to,
195
- from: pagination.from,
196
- links: pagination.links,
197
- path: pagination.path,
198
- total: pagination.total,
199
- per_page: pagination.perPage,
200
- last_page: pagination.lastPage,
201
- current_page: pagination.currentPage
202
- };
203
- for (const [sourceKey, outputKey] of Object.entries(getGlobalPaginatedMeta())) {
204
- if (!outputKey) continue;
205
- const value = metaSource[sourceKey];
206
- if (typeof value !== "undefined") metaBlock[outputKey] = value;
207
- }
208
- const linksSource = {
209
- first: buildPageUrl(pagination.firstPage, pagination.path),
210
- last: buildPageUrl(pagination.lastPage, pagination.path),
211
- prev: buildPageUrl(pagination.prevPage, pagination.path),
212
- next: buildPageUrl(pagination.nextPage, pagination.path)
213
- };
214
- for (const [sourceKey, outputKey] of Object.entries(getGlobalPaginatedLinks())) {
215
- if (!outputKey) continue;
216
- const value = linksSource[sourceKey];
217
- if (typeof value !== "undefined") linksBlock[outputKey] = value;
218
- }
219
- }
220
- if (cursor) {
221
- const cursorBlock = {};
222
- const cursorSource = {
223
- previous: cursor.previous,
224
- next: cursor.next
225
- };
226
- for (const [sourceKey, outputKey] of Object.entries(getGlobalCursorMeta())) {
227
- if (!outputKey) continue;
228
- const value = cursorSource[sourceKey];
229
- if (typeof value !== "undefined") cursorBlock[outputKey] = value;
230
- }
231
- if (cursorKey && Object.keys(cursorBlock).length > 0) extra[cursorKey] = cursorBlock;
232
- else if (Object.keys(cursorBlock).length > 0) metaBlock.cursor = cursorBlock;
233
- }
234
- if (metaKey && Object.keys(metaBlock).length > 0) extra[metaKey] = metaBlock;
235
- if (linksKey && Object.keys(linksBlock).length > 0) extra[linksKey] = linksBlock;
236
- return extra;
237
- };
238
-
239
- //#endregion
240
- //#region src/utilities/objects.ts
241
- const isPlainObject = (value) => {
242
- if (typeof value !== "object" || value === null) return false;
243
- if (Array.isArray(value) || value instanceof Date || value instanceof RegExp) return false;
244
- const proto = Object.getPrototypeOf(value);
245
- return proto === Object.prototype || proto === null;
246
- };
247
- const appendRootProperties = (body, extra, rootKey = "data") => {
248
- if (!extra || Object.keys(extra).length === 0) return body;
249
- if (Array.isArray(body)) return {
250
- [rootKey]: body,
251
- ...extra
252
- };
253
- if (isPlainObject(body)) return {
254
- ...body,
255
- ...extra
256
- };
257
- return {
258
- [rootKey]: body,
259
- ...extra
260
- };
261
- };
262
- const mergeMetadata = (base, incoming) => {
263
- if (!incoming) return base;
264
- if (!base) return incoming;
265
- const merged = { ...base };
266
- for (const [key, value] of Object.entries(incoming)) {
267
- const existing = merged[key];
268
- if (isPlainObject(existing) && isPlainObject(value)) merged[key] = mergeMetadata(existing, value);
269
- else merged[key] = value;
270
- }
271
- return merged;
272
- };
273
-
274
- //#endregion
275
- //#region src/utilities/response.ts
276
- const buildResponseEnvelope = ({ payload, meta, metaKey = "meta", wrap = true, rootKey = "data", factory, context }) => {
277
- if (factory) return factory(payload, {
278
- ...context,
279
- rootKey,
280
- meta
281
- });
282
- if (!wrap) {
283
- if (typeof meta === "undefined") return payload;
284
- if (isPlainObject(payload)) return {
285
- ...payload,
286
- [metaKey]: meta
287
- };
288
- return {
289
- [rootKey]: payload,
290
- [metaKey]: meta
291
- };
292
- }
293
- const body = { [rootKey]: payload };
294
- if (typeof meta !== "undefined") body[metaKey] = meta;
295
- return body;
296
- };
297
-
298
- //#endregion
299
- //#region src/utilities/metadata.ts
300
- const resolveWithHookMetadata = (instance, baseWithMethod) => {
301
- const candidate = instance?.with;
302
- if (typeof candidate !== "function" || candidate === baseWithMethod) return;
303
- if (candidate.length > 0) return;
304
- const result = candidate.call(instance);
305
- return isPlainObject(result) ? result : void 0;
306
- };
307
-
308
- //#endregion
309
- //#region src/utilities/conditional.ts
310
- const CONDITIONAL_ATTRIBUTE_MISSING = Symbol("resora.conditional.missing");
311
- const resolveWhen = (condition, value) => {
312
- if (!condition) return CONDITIONAL_ATTRIBUTE_MISSING;
313
- return typeof value === "function" ? value() : value;
314
- };
315
- const resolveWhenNotNull = (value) => {
316
- return value === null || typeof value === "undefined" ? CONDITIONAL_ATTRIBUTE_MISSING : value;
317
- };
318
- const resolveMergeWhen = (condition, value) => {
319
- if (!condition) return {};
320
- const resolved = typeof value === "function" ? value() : value;
321
- return isPlainObject(resolved) ? resolved : {};
322
- };
323
- const sanitizeConditionalAttributes = (value) => {
324
- if (value === CONDITIONAL_ATTRIBUTE_MISSING) return CONDITIONAL_ATTRIBUTE_MISSING;
325
- if (Array.isArray(value)) return value.map((item) => sanitizeConditionalAttributes(item)).filter((item) => item !== CONDITIONAL_ATTRIBUTE_MISSING);
326
- if (isPlainObject(value)) {
327
- const result = {};
328
- for (const [key, nestedValue] of Object.entries(value)) {
329
- const sanitizedValue = sanitizeConditionalAttributes(nestedValue);
330
- if (sanitizedValue === CONDITIONAL_ATTRIBUTE_MISSING) continue;
331
- result[key] = sanitizedValue;
332
- }
333
- return result;
334
- }
335
- return value;
336
- };
337
-
338
- //#endregion
339
- //#region src/utilities/case.ts
340
- const splitWords = (str) => {
341
- return str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[-_\s]+/g, " ").trim().toLowerCase().split(" ").filter(Boolean);
342
- };
343
- const toCamelCase = (str) => {
344
- return splitWords(str).map((w, i) => i === 0 ? w : w.charAt(0).toUpperCase() + w.slice(1)).join("");
345
- };
346
- const toSnakeCase = (str) => {
347
- return splitWords(str).join("_");
348
- };
349
- const toPascalCase = (str) => {
350
- return splitWords(str).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
351
- };
352
- const toKebabCase = (str) => {
353
- return splitWords(str).join("-");
354
- };
355
- const getCaseTransformer = (style) => {
356
- if (typeof style === "function") return style;
357
- switch (style) {
358
- case "camel": return toCamelCase;
359
- case "snake": return toSnakeCase;
360
- case "pascal": return toPascalCase;
361
- case "kebab": return toKebabCase;
362
- }
363
- };
364
- const transformKeys = (obj, transformer) => {
365
- if (obj === null || obj === void 0) return obj;
366
- if (Array.isArray(obj)) return obj.map((item) => transformKeys(item, transformer));
367
- if (obj instanceof Date || obj instanceof RegExp) return obj;
368
- if (typeof obj === "object") return Object.fromEntries(Object.entries(obj).map(([key, value]) => [transformer(key), transformKeys(value, transformer)]));
369
- return obj;
370
- };
371
-
372
- //#endregion
373
- //#region src/utilities/config.ts
374
- let stubsDir = path.default.resolve(process.cwd(), "node_modules/resora/stubs");
375
- if (!(0, fs.existsSync)(stubsDir)) stubsDir = path.default.resolve(process.cwd(), "stubs");
376
- const getDefaultConfig = () => {
377
- return {
378
- stubsDir,
379
- preferredCase: "camel",
380
- responseStructure: {
381
- wrap: true,
382
- rootKey: "data"
383
- },
384
- paginatedExtras: ["meta", "links"],
385
- baseUrl: "https://localhost",
386
- pageName: "page",
387
- paginatedLinks: {
388
- first: "first",
389
- last: "last",
390
- prev: "prev",
391
- next: "next"
392
- },
393
- paginatedMeta: {
394
- to: "to",
395
- from: "from",
396
- links: "links",
397
- path: "path",
398
- total: "total",
399
- per_page: "per_page",
400
- last_page: "last_page",
401
- current_page: "current_page"
402
- },
403
- cursorMeta: {
404
- previous: "previous",
405
- next: "next"
406
- },
407
- resourcesDir: "src/resources",
408
- stubs: {
409
- config: "resora.config.stub",
410
- resource: "resource.stub",
411
- collection: "resource.collection.stub"
412
- }
413
- };
414
- };
415
- const defineConfig = (userConfig = {}) => {
416
- const defaultConfig = getDefaultConfig();
417
- return Object.assign(defaultConfig, userConfig, { stubs: Object.assign(defaultConfig.stubs, userConfig.stubs || {}) });
418
- };
419
-
420
- //#endregion
421
- //#region src/cli/CliApp.ts
422
- var CliApp = class {
423
- command;
424
- config = {};
425
- constructor(config = {}) {
426
- this.config = defineConfig(config);
427
- }
428
- async loadConfig(config = {}) {
429
- this.config = defineConfig(config);
430
- const possibleConfigPaths = [
431
- (0, path.join)(process.cwd(), "resora.config.ts"),
432
- (0, path.join)(process.cwd(), "resora.config.js"),
433
- (0, path.join)(process.cwd(), "resora.config.cjs")
434
- ];
435
- for (const configPath of possibleConfigPaths) if ((0, fs.existsSync)(configPath)) try {
436
- const { default: userConfig } = await import(configPath);
437
- Object.assign(this.config, userConfig);
438
- break;
439
- } catch (e) {
440
- console.error(`Error loading config file at ${configPath}:`, e);
441
- }
442
- return this;
443
- }
444
- /**
445
- * Get the current configuration object
446
- * @returns
447
- */
448
- getConfig() {
449
- return this.config;
450
- }
451
- /**
452
- * Initialize Resora by creating a default config file in the current directory
453
- *
454
- * @returns
455
- */
456
- init() {
457
- const outputPath = (0, path.join)(process.cwd(), "resora.config.js");
458
- const stubPath = (0, path.join)(this.config.stubsDir, this.config.stubs.config);
459
- if ((0, fs.existsSync)(outputPath) && !this.command.option("force")) {
460
- this.command.error(`Error: ${outputPath} already exists.`);
461
- process.exit(1);
462
- }
463
- this.ensureDirectory(outputPath);
464
- if ((0, fs.existsSync)(outputPath) && this.command.option("force")) (0, fs.copyFileSync)(outputPath, outputPath.replace(/\.js$/, `.backup.${Date.now()}.js`));
465
- (0, fs.writeFileSync)(outputPath, (0, fs.readFileSync)(stubPath, "utf-8"));
466
- return { path: outputPath };
467
- }
468
- /**
469
- * Utility to ensure directory exists
470
- *
471
- * @param filePath
472
- */
473
- ensureDirectory(filePath) {
474
- const dir = (0, path.dirname)(filePath);
475
- if (!(0, fs.existsSync)(dir)) (0, fs.mkdirSync)(dir, { recursive: true });
476
- }
477
- /**
478
- * Utility to generate file from stub
479
- *
480
- * @param stubPath
481
- * @param outputPath
482
- * @param replacements
483
- */
484
- generateFile(stubPath, outputPath, replacements, options) {
485
- if ((0, fs.existsSync)(outputPath) && !options?.force) {
486
- this.command.error(`Error: ${outputPath} already exists.`);
487
- process.exit(1);
488
- } else if ((0, fs.existsSync)(outputPath) && options?.force) (0, fs.rmSync)(outputPath);
489
- let content = (0, fs.readFileSync)(stubPath, "utf-8");
490
- for (const [key, value] of Object.entries(replacements)) content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
491
- this.ensureDirectory(outputPath);
492
- (0, fs.writeFileSync)(outputPath, content);
493
- return outputPath;
494
- }
495
- /**
496
- * Command to create a new resource or resource collection file
497
- *
498
- * @param name
499
- * @param options
500
- */
501
- makeResource(name, options) {
502
- let resourceName = name;
503
- if (options?.collection && !name.endsWith("Collection") && !name.endsWith("Resource")) resourceName += "Collection";
504
- else if (!options?.collection && !name.endsWith("Resource") && !name.endsWith("Collection")) resourceName += "Resource";
505
- const fileName = `${resourceName}.ts`;
506
- const outputPath = (0, path.join)(this.config.resourcesDir, fileName);
507
- const stubPath = (0, path.join)(this.config.stubsDir, options?.collection || name.endsWith("Collection") ? this.config.stubs.collection : this.config.stubs.resource);
508
- if (!(0, fs.existsSync)(stubPath)) {
509
- this.command.error(`Error: Stub file ${stubPath} not found.`);
510
- process.exit(1);
511
- }
512
- const collectsName = resourceName.replace(/(Resource|Collection)$/, "") + "Resource";
513
- const collects = `/**
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`fs`),l=require(`path`);l=s(l);let u=require(`module`),d=require(`url`),f=require(`@h3ravel/musket`);function ee(e){return e}let p,m,h=[`meta`,`links`],g={first:`first`,last:`last`,prev:`prev`,next:`next`},_=`https://localhost`,te=`page`,v={to:`to`,from:`from`,links:`links`,path:`path`,total:`total`,per_page:`per_page`,last_page:`last_page`,current_page:`current_page`},y={previous:`previous`,next:`next`};const b=e=>{p=e},x=()=>p,S=e=>{m=e},C=()=>m,ne=e=>{m={...m||{},rootKey:e}},re=e=>{m={...m||{},wrap:e}},ie=()=>m?.wrap,ae=()=>m?.rootKey,oe=e=>{m={...m||{},factory:e}},se=()=>m?.factory,w=e=>{h=e},T=()=>h,E=e=>{g={...g,...e}},ce=()=>g,le=e=>{_=e},ue=()=>_,de=e=>{te=e},fe=()=>te,pe=e=>{v={...v,...e}},me=()=>v,D=e=>{y={...y,...e}},O=()=>y,k=()=>{let e=T();return Array.isArray(e)?{metaKey:e.includes(`meta`)?`meta`:void 0,linksKey:e.includes(`links`)?`links`:void 0,cursorKey:e.includes(`cursor`)?`cursor`:void 0}:{metaKey:e.meta,linksKey:e.links,cursorKey:e.cursor}},A=(e,t)=>{if(e===void 0)return;let n=t||``,r=ue()||``,i=/^https?:\/\//i.test(n),a=r.replace(/\/$/,``),o=n.replace(/^\//,``),s=i?n:a?o?`${a}/${o}`:a:``;if(!s)return;let c=new URL(s);return c.searchParams.set(fe()||`page`,String(e)),c.toString()},j=e=>{let{metaKey:t,linksKey:n,cursorKey:r}=k(),i={},a=e?.pagination,o=e?.cursor,s={},c={};if(a){let e={to:a.to,from:a.from,links:a.links,path:a.path,total:a.total,per_page:a.perPage,last_page:a.lastPage,current_page:a.currentPage};for(let[t,n]of Object.entries(me())){if(!n)continue;let r=e[t];r!==void 0&&(s[n]=r)}let t={first:A(a.firstPage,a.path),last:A(a.lastPage,a.path),prev:A(a.prevPage,a.path),next:A(a.nextPage,a.path)};for(let[e,n]of Object.entries(ce())){if(!n)continue;let r=t[e];r!==void 0&&(c[n]=r)}}if(o){let e={},t={previous:o.previous,next:o.next};for(let[n,r]of Object.entries(O())){if(!r)continue;let i=t[n];i!==void 0&&(e[r]=i)}r&&Object.keys(e).length>0?i[r]=e:Object.keys(e).length>0&&(s.cursor=e)}return t&&Object.keys(s).length>0&&(i[t]=s),n&&Object.keys(c).length>0&&(i[n]=c),i},M=e=>{if(typeof e!=`object`||!e||Array.isArray(e)||e instanceof Date||e instanceof RegExp)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},N=(e,t,n=`data`)=>!t||Object.keys(t).length===0?e:Array.isArray(e)?{[n]:e,...t}:M(e)?{...e,...t}:{[n]:e,...t},P=(e,t)=>{if(!t)return e;if(!e)return t;let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];M(t)&&M(r)?n[e]=P(t,r):n[e]=r}return n},F=({payload:e,meta:t,metaKey:n=`meta`,wrap:r=!0,rootKey:i=`data`,factory:a,context:o})=>{if(a)return a(e,{...o,rootKey:i,meta:t});if(!r)return t===void 0?e:M(e)?{...e,[n]:t}:{[i]:e,[n]:t};let s={[i]:e};return t!==void 0&&(s[n]=t),s},I=(e,t)=>{let n=e?.with;if(typeof n!=`function`||n===t||n.length>0)return;let r=n.call(e);return M(r)?r:void 0},L=Symbol(`resora.conditional.missing`),R=(e,t)=>e?typeof t==`function`?t():t:L,z=e=>e??L,B=(e,t)=>{if(!e)return{};let n=typeof t==`function`?t():t;return M(n)?n:{}},V=e=>{if(e===L)return L;if(Array.isArray(e))return e.map(e=>V(e)).filter(e=>e!==L);if(M(e)){let t={};for(let[n,r]of Object.entries(e)){let e=V(r);e!==L&&(t[n]=e)}return t}return e},H=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1 $2`).replace(/([A-Z]+)([A-Z][a-z])/g,`$1 $2`).replace(/[-_\s]+/g,` `).trim().toLowerCase().split(` `).filter(Boolean),U=e=>H(e).map((e,t)=>t===0?e:e.charAt(0).toUpperCase()+e.slice(1)).join(``),W=e=>H(e).join(`_`),G=e=>H(e).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``),K=e=>H(e).join(`-`),q=e=>{if(typeof e==`function`)return e;switch(e){case`camel`:return U;case`snake`:return W;case`pascal`:return G;case`kebab`:return K}},J=(e,t)=>e==null?e:Array.isArray(e)?e.map(e=>J(e,t)):e instanceof Date||e instanceof RegExp?e:typeof e==`object`?Object.fromEntries(Object.entries(e).map(([e,n])=>[t(e),J(n,t)])):e;let Y=l.default.resolve(process.cwd(),`node_modules/resora/stubs`);(0,c.existsSync)(Y)||(Y=l.default.resolve(process.cwd(),`stubs`));const he=()=>({stubsDir:Y,preferredCase:`camel`,responseStructure:{wrap:!0,rootKey:`data`},paginatedExtras:[`meta`,`links`],baseUrl:`https://localhost`,pageName:`page`,paginatedLinks:{first:`first`,last:`last`,prev:`prev`,next:`next`},paginatedMeta:{to:`to`,from:`from`,links:`links`,path:`path`,total:`total`,per_page:`per_page`,last_page:`last_page`,current_page:`current_page`},cursorMeta:{previous:`previous`,next:`next`},resourcesDir:`src/resources`,stubs:{config:`resora.config.stub`,resource:`resource.stub`,collection:`resource.collection.stub`}}),X=e=>{let t=he();return Object.assign(t,e,{stubs:Object.assign(t.stubs,e.stubs||{})},{cursorMeta:Object.assign(t.cursorMeta,e.cursorMeta||{})},{paginatedMeta:Object.assign(t.paginatedMeta,e.paginatedMeta||{})},{paginatedLinks:Object.assign(t.paginatedLinks,e.paginatedLinks||{})},{responseStructure:Object.assign(t.responseStructure,e.responseStructure||{})})};let Z=!1,Q;const ge=()=>{Z=!1,Q=void 0},_e=e=>{e.preferredCase!==`camel`&&b(e.preferredCase),S(e.responseStructure),w(e.paginatedExtras),E(e.paginatedLinks),pe(e.paginatedMeta),D(e.cursorMeta),le(e.baseUrl),de(e.pageName)},ve=async e=>await import(`${(0,d.pathToFileURL)(e).href}?resora_runtime=${Date.now()}`),ye=e=>{_e(X((e?.default??e)||{})),Z=!0},be=()=>{let e=(0,u.createRequire)(e(`url`).pathToFileURL(__filename).href),t=[l.default.join(process.cwd(),`resora.config.cjs`)];for(let n of t)if((0,c.existsSync)(n))try{return ye(e(n)),!0}catch{continue}return!1},xe=async()=>{if(!Z){if(Q)return await Q;be()||(Q=(async()=>{let e=[l.default.join(process.cwd(),`resora.config.js`),l.default.join(process.cwd(),`resora.config.ts`)];for(let t of e)if((0,c.existsSync)(t))try{ye(await ve(t));return}catch{continue}Z=!0})(),await Q)}};xe();var Se=class{command;config={};constructor(e={}){this.config=X(e)}async loadConfig(e={}){this.config=X(e);let t=[(0,l.join)(process.cwd(),`resora.config.ts`),(0,l.join)(process.cwd(),`resora.config.js`),(0,l.join)(process.cwd(),`resora.config.cjs`)];for(let e of t)if((0,c.existsSync)(e))try{let{default:t}=await import(e);Object.assign(this.config,t);break}catch(t){console.error(`Error loading config file at ${e}:`,t)}return this}getConfig(){return this.config}init(){let e=(0,l.join)(process.cwd(),`resora.config.js`),t=(0,l.join)(this.config.stubsDir,this.config.stubs.config);return(0,c.existsSync)(e)&&!this.command.option(`force`)&&(this.command.error(`Error: ${e} already exists.`),process.exit(1)),this.ensureDirectory(e),(0,c.existsSync)(e)&&this.command.option(`force`)&&(0,c.copyFileSync)(e,e.replace(/\.js$/,`.backup.${Date.now()}.js`)),(0,c.writeFileSync)(e,(0,c.readFileSync)(t,`utf-8`)),{path:e}}ensureDirectory(e){let t=(0,l.dirname)(e);(0,c.existsSync)(t)||(0,c.mkdirSync)(t,{recursive:!0})}generateFile(e,t,n,r){(0,c.existsSync)(t)&&!r?.force?(this.command.error(`Error: ${t} already exists.`),process.exit(1)):(0,c.existsSync)(t)&&r?.force&&(0,c.rmSync)(t);let i=(0,c.readFileSync)(e,`utf-8`);for(let[e,t]of Object.entries(n))i=i.replace(RegExp(`{{${e}}}`,`g`),t);return this.ensureDirectory(t),(0,c.writeFileSync)(t,i),t}makeResource(e,t){let n=e;t?.collection&&!e.endsWith(`Collection`)&&!e.endsWith(`Resource`)?n+=`Collection`:!t?.collection&&!e.endsWith(`Resource`)&&!e.endsWith(`Collection`)&&(n+=`Resource`);let r=`${n}.ts`,i=(0,l.join)(this.config.resourcesDir,r),a=(0,l.join)(this.config.stubsDir,t?.collection||e.endsWith(`Collection`)?this.config.stubs.collection:this.config.stubs.resource);(0,c.existsSync)(a)||(this.command.error(`Error: Stub file ${a} not found.`),process.exit(1));let o=n.replace(/(Resource|Collection)$/,``)+`Resource`,s=`/**
514
2
  * The resource that this collection collects.
515
3
  */
516
- collects = ${collectsName}
517
- `;
518
- const collectsImport = `import ${collectsName} from './${collectsName}'\n`;
519
- const hasCollects = (!!options?.collection || name.endsWith("Collection")) && (0, fs.existsSync)((0, path.join)(this.config.resourcesDir, `${collectsName}.ts`));
520
- const path$2 = this.generateFile(stubPath, outputPath, {
521
- ResourceName: resourceName,
522
- CollectionResourceName: resourceName.replace(/(Resource|Collection)$/, "") + "Resource",
523
- "collects = Resource": hasCollects ? collects : "",
524
- "import = Resource": hasCollects ? collectsImport : ""
525
- }, options);
526
- return {
527
- name: resourceName,
528
- path: path$2
529
- };
530
- }
531
- };
532
-
533
- //#endregion
534
- //#region src/cli/commands/InitCommand.ts
535
- var InitCommand = class extends _h3ravel_musket.Command {
536
- signature = `init
4
+ collects = ${o}
5
+ `,u=`import ${o} from './${o}'\n`,d=(!!t?.collection||e.endsWith(`Collection`))&&(0,c.existsSync)((0,l.join)(this.config.resourcesDir,`${o}.ts`)),f=this.generateFile(a,i,{ResourceName:n,CollectionResourceName:n.replace(/(Resource|Collection)$/,``)+`Resource`,"collects = Resource":d?s:``,"import = Resource":d?u:``},t);return{name:n,path:f}}},Ce=class extends f.Command{signature=`init
537
6
  {--force : Force overwrite if config file already exists (existing file will be backed up) }
538
- `;
539
- description = "Initialize Resora";
540
- async handle() {
541
- this.app.command = this;
542
- this.app.init();
543
- this.success("Resora initialized");
544
- }
545
- };
546
-
547
- //#endregion
548
- //#region src/cli/commands/MakeResource.ts
549
- var MakeResource = class extends _h3ravel_musket.Command {
550
- signature = `#create:
7
+ `;description=`Initialize Resora`;async handle(){this.app.command=this,this.app.init(),this.success(`Resora initialized`)}},we=class extends f.Command{signature=`#create:
551
8
  {resource : Generates a new resource file.
552
9
  | {name : Name of the resource to create}
553
10
  | {--c|collection : Make a resource collection}
@@ -561,966 +18,11 @@ var MakeResource = class extends _h3ravel_musket.Command {
561
18
  | {prefix : prefix of the resources to create, "Admin" will create AdminResource, AdminCollection}
562
19
  | {--force : Create the resource or collection file even if it already exists.}
563
20
  }
564
- `;
565
- description = "Create a new resource or resource collection file";
566
- async handle() {
567
- this.app.command = this;
568
- let path = "";
569
- const action = this.dictionary.name || this.dictionary.baseCommand;
570
- if (["resource", "collection"].includes(action) && !this.argument("name")) return void this.error("Error: Name argument is required.");
571
- if (action === "all" && !this.argument("prefix")) return void this.error("Error: Prefix argument is required.");
572
- switch (action) {
573
- case "resource":
574
- ({path} = this.app.makeResource(this.argument("name"), this.options()));
575
- break;
576
- case "collection":
577
- ({path} = this.app.makeResource(this.argument("name") + "Collection", this.options()));
578
- break;
579
- case "all": {
580
- const o1 = this.app.makeResource(this.argument("prefix"), { force: this.option("force") });
581
- const o2 = this.app.makeResource(this.argument("prefix") + "Collection", {
582
- collection: true,
583
- force: this.option("force")
584
- });
585
- path = `${o1.path}, ${o2.path}`;
586
- break;
587
- }
588
- default: this.fail(`Unknown action: ${action}`);
589
- }
590
- this.success(`Created: ${path}`);
591
- }
592
- };
593
-
594
- //#endregion
595
- //#region src/cli/logo.ts
596
- var logo_default = String.raw`
21
+ `;description=`Create a new resource or resource collection file`;async handle(){this.app.command=this;let e=``,t=this.dictionary.name||this.dictionary.baseCommand;if([`resource`,`collection`].includes(t)&&!this.argument(`name`))return void this.error(`Error: Name argument is required.`);if(t===`all`&&!this.argument(`prefix`))return void this.error(`Error: Prefix argument is required.`);switch(t){case`resource`:({path:e}=this.app.makeResource(this.argument(`name`),this.options()));break;case`collection`:({path:e}=this.app.makeResource(this.argument(`name`)+`Collection`,this.options()));break;case`all`:{let t=this.app.makeResource(this.argument(`prefix`),{force:this.option(`force`)}),n=this.app.makeResource(this.argument(`prefix`)+`Collection`,{collection:!0,force:this.option(`force`)});e=`${t.path}, ${n.path}`;break}default:this.fail(`Unknown action: ${t}`)}this.success(`Created: ${e}`)}};String.raw`
597
22
  _____
598
23
  | __ \
599
24
  | |__) |___ ___ ___ _ __ __ _
600
25
  | _ // _ \/ __|/ _ \| '__/ _, |
601
26
  | | \ \ __/\__ \ (_) | | | (_| |
602
27
  |_| \_\___||___/\___/|_| \__,_|
603
- `;
604
-
605
- //#endregion
606
- //#region src/ServerResponse.ts
607
- var ServerResponse = class {
608
- _status = 200;
609
- headers = {};
610
- constructor(response, body) {
611
- this.response = response;
612
- this.body = body;
613
- }
614
- /**
615
- * Set the HTTP status code for the response
616
- *
617
- * @param status
618
- * @returns The current ServerResponse instance
619
- */
620
- setStatusCode(status) {
621
- this._status = status;
622
- if ("status" in this.response && typeof this.response.status === "function") this.response.status(status);
623
- else if ("status" in this.response) this.response.status = status;
624
- return this;
625
- }
626
- /**
627
- * Get the current HTTP status code for the response
628
- *
629
- * @returns
630
- */
631
- status() {
632
- return this._status;
633
- }
634
- /**
635
- * Get the current HTTP status text for the response
636
- *
637
- * @returns
638
- */
639
- statusText() {
640
- if ("statusMessage" in this.response) return this.response.statusMessage;
641
- else if ("statusText" in this.response) return this.response.statusText;
642
- }
643
- /**
644
- * Set a cookie in the response header
645
- *
646
- * @param name The name of the cookie
647
- * @param value The value of the cookie
648
- * @param options Optional cookie attributes (e.g., path, domain, maxAge)
649
- * @returns The current ServerResponse instance
650
- */
651
- setCookie(name, value, options) {
652
- this.#addHeader("Set-Cookie", `${name}=${value}; ${Object.entries(options || {}).map(([key, val]) => `${key}=${val}`).join("; ")}`);
653
- return this;
654
- }
655
- /**
656
- * Convert the resource to a JSON response body
657
- *
658
- * @param headers Optional headers to add to the response
659
- * @returns The current ServerResponse instance
660
- */
661
- setHeaders(headers) {
662
- for (const [key, value] of Object.entries(headers)) this.#addHeader(key, value);
663
- return this;
664
- }
665
- /**
666
- * Add a single header to the response
667
- *
668
- * @param key The name of the header
669
- * @param value The value of the header
670
- * @returns The current ServerResponse instance
671
- */
672
- header(key, value) {
673
- this.#addHeader(key, value);
674
- return this;
675
- }
676
- /**
677
- * Add a single header to the response
678
- *
679
- * @param key The name of the header
680
- * @param value The value of the header
681
- */
682
- #addHeader(key, value) {
683
- this.headers[key] = value;
684
- if ("headers" in this.response) this.response.headers.set(key, value);
685
- else if ("setHeader" in this.response) this.response.setHeader(key, value);
686
- }
687
- /**
688
- * Promise-like then method to allow chaining with async/await or .then() syntax
689
- *
690
- * @param onfulfilled Callback to handle the fulfilled state of the promise, receiving the response body
691
- * @param onrejected Callback to handle the rejected state of the promise, receiving the error reason
692
- * @returns A promise that resolves to the result of the onfulfilled or onrejected callback
693
- */
694
- then(onfulfilled, onrejected) {
695
- const resolved = Promise.resolve(this.body).then(onfulfilled, onrejected);
696
- if ("send" in this.response) this.response.send(this.body);
697
- return resolved;
698
- }
699
- /**
700
- * Promise-like catch method to handle rejected state of the promise
701
- *
702
- * @param onrejected
703
- * @returns
704
- */
705
- catch(onrejected) {
706
- return this.then(void 0, onrejected);
707
- }
708
- /**
709
- * Promise-like finally method to handle cleanup after promise is settled
710
- *
711
- * @param onfinally
712
- * @returns
713
- */
714
- finally(onfinally) {
715
- return this.then(onfinally, onfinally);
716
- }
717
- };
718
-
719
- //#endregion
720
- //#region src/GenericResource.ts
721
- /**
722
- * GenericResource class to handle API resource transformation and response building
723
- */
724
- var GenericResource = class GenericResource {
725
- body = { data: {} };
726
- resource;
727
- collects;
728
- additionalMeta;
729
- withResponseContext;
730
- /**
731
- * Preferred case style for this resource's output keys.
732
- * Set on a subclass to override the global default.
733
- */
734
- static preferredCase;
735
- /**
736
- * Response structure override for this generic resource class.
737
- */
738
- static responseStructure;
739
- called = {};
740
- constructor(rsc, res) {
741
- this.res = res;
742
- this.resource = rsc;
743
- /**
744
- * Copy properties from rsc to this instance for easy
745
- * access, but only if data is not an array
746
- */
747
- if (!Array.isArray(this.resource.data ?? this.resource)) {
748
- for (const key of Object.keys(this.resource.data ?? this.resource)) if (!(key in this)) Object.defineProperty(this, key, {
749
- enumerable: true,
750
- configurable: true,
751
- get: () => {
752
- return this.resource.data?.[key] ?? this.resource[key];
753
- },
754
- set: (value) => {
755
- if (this.resource.data && this.resource.data[key]) this.resource.data[key] = value;
756
- else this.resource[key] = value;
757
- }
758
- });
759
- }
760
- }
761
- /**
762
- * Get the original resource data
763
- */
764
- data() {
765
- return this.resource;
766
- }
767
- /**
768
- * Get the current serialized output body.
769
- */
770
- getBody() {
771
- this.json();
772
- return this.body;
773
- }
774
- /**
775
- * Replace the current serialized output body.
776
- */
777
- setBody(body) {
778
- this.body = body;
779
- return this;
780
- }
781
- /**
782
- * Conditionally include a value in serialized output.
783
- */
784
- when(condition, value) {
785
- return resolveWhen(condition, value);
786
- }
787
- /**
788
- * Include a value only when it is not null/undefined.
789
- */
790
- whenNotNull(value) {
791
- return resolveWhenNotNull(value);
792
- }
793
- /**
794
- * Conditionally merge object attributes into serialized output.
795
- */
796
- mergeWhen(condition, value) {
797
- return resolveMergeWhen(condition, value);
798
- }
799
- resolveResponseStructure() {
800
- const local = this.constructor.responseStructure;
801
- const collectsLocal = this.collects?.responseStructure;
802
- const global = getGlobalResponseStructure();
803
- return {
804
- wrap: local?.wrap ?? collectsLocal?.wrap ?? global?.wrap ?? true,
805
- rootKey: local?.rootKey ?? collectsLocal?.rootKey ?? global?.rootKey ?? "data",
806
- factory: local?.factory ?? collectsLocal?.factory ?? global?.factory
807
- };
808
- }
809
- getPayloadKey() {
810
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
811
- return factory || !wrap ? void 0 : rootKey;
812
- }
813
- /**
814
- * Convert resource to JSON response format
815
- *
816
- * @returns
817
- */
818
- json() {
819
- if (!this.called.json) {
820
- this.called.json = true;
821
- const resource = this.data();
822
- let data = Array.isArray(resource) ? [...resource] : { ...resource };
823
- if (Array.isArray(data) && this.collects) {
824
- data = data.map((item) => new this.collects(item).data());
825
- this.resource = data;
826
- }
827
- if (typeof data.data !== "undefined") data = data.data;
828
- data = sanitizeConditionalAttributes(data);
829
- const paginationExtras = buildPaginationExtras(this.resource);
830
- const { metaKey } = getPaginationExtraKeys();
831
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
832
- if (metaKey) delete paginationExtras[metaKey];
833
- const caseStyle = this.constructor.preferredCase ?? getGlobalCase();
834
- if (caseStyle) {
835
- const transformer = getCaseTransformer(caseStyle);
836
- data = transformKeys(data, transformer);
837
- }
838
- const customMeta = mergeMetadata(resolveWithHookMetadata(this, GenericResource.prototype.with), this.additionalMeta);
839
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
840
- this.body = buildResponseEnvelope({
841
- payload: data,
842
- meta: configuredMeta,
843
- metaKey,
844
- wrap,
845
- rootKey,
846
- factory,
847
- context: {
848
- type: "generic",
849
- resource: this.resource
850
- }
851
- });
852
- this.body = appendRootProperties(this.body, {
853
- ...paginationExtras,
854
- ...customMeta || {}
855
- }, rootKey);
856
- }
857
- return this;
858
- }
859
- /**
860
- * Append structured metadata to the response body.
861
- *
862
- * @param meta Metadata object or metadata factory
863
- * @returns
864
- */
865
- with(meta) {
866
- this.called.with = true;
867
- if (typeof meta === "undefined") return this.additionalMeta || {};
868
- const resolvedMeta = typeof meta === "function" ? meta(this.resource) : meta;
869
- this.additionalMeta = mergeMetadata(this.additionalMeta, resolvedMeta);
870
- if (this.called.json) {
871
- const { rootKey } = this.resolveResponseStructure();
872
- this.body = appendRootProperties(this.body, resolvedMeta, rootKey);
873
- }
874
- return this;
875
- }
876
- /**
877
- * Typed fluent metadata helper.
878
- *
879
- * @param meta Metadata object or metadata factory
880
- * @returns
881
- */
882
- withMeta(meta) {
883
- this.with(meta);
884
- return this;
885
- }
886
- /**
887
- * Convert resource to array format (for collections)
888
- *
889
- * @returns
890
- */
891
- toArray() {
892
- this.called.toArray = true;
893
- this.json();
894
- let data = Array.isArray(this.resource) ? [...this.resource] : { ...this.resource };
895
- if (typeof data.data !== "undefined") data = data.data;
896
- return data;
897
- }
898
- /**
899
- * Add additional properties to the response body
900
- *
901
- * @param extra Additional properties to merge into the response body
902
- * @returns
903
- */
904
- additional(extra) {
905
- this.called.additional = true;
906
- this.json();
907
- const extraData = extra.data;
908
- delete extra.data;
909
- delete extra.pagination;
910
- const payloadKey = this.getPayloadKey();
911
- if (extraData && payloadKey && typeof this.body[payloadKey] !== "undefined") this.body[payloadKey] = Array.isArray(this.body[payloadKey]) ? [...this.body[payloadKey], ...extraData] : {
912
- ...this.body[payloadKey],
913
- ...extraData
914
- };
915
- this.body = {
916
- ...this.body,
917
- ...extra
918
- };
919
- return this;
920
- }
921
- response(res) {
922
- this.called.toResponse = true;
923
- this.json();
924
- const rawResponse = res ?? this.res;
925
- const response = new ServerResponse(rawResponse, this.body);
926
- this.withResponseContext = {
927
- response,
928
- raw: rawResponse
929
- };
930
- this.called.withResponse = true;
931
- this.withResponse(response, rawResponse);
932
- return response;
933
- }
934
- /**
935
- * Customize the outgoing transport response right before dispatch.
936
- *
937
- * Override in custom classes to mutate headers/status/body.
938
- */
939
- withResponse(_response, _rawResponse) {
940
- return this;
941
- }
942
- /**
943
- * Promise-like then method to allow chaining with async/await or .then() syntax
944
- *
945
- * @param onfulfilled Callback to handle the fulfilled state of the promise, receiving the response body
946
- * @param onrejected Callback to handle the rejected state of the promise, receiving the error reason
947
- * @returns A promise that resolves to the result of the onfulfilled or onrejected callback
948
- */
949
- then(onfulfilled, onrejected) {
950
- this.called.then = true;
951
- this.json();
952
- if (this.res) {
953
- const response = new ServerResponse(this.res, this.body);
954
- this.withResponseContext = {
955
- response,
956
- raw: this.res
957
- };
958
- this.called.withResponse = true;
959
- this.withResponse(response, this.res);
960
- } else {
961
- this.called.withResponse = true;
962
- this.withResponse();
963
- }
964
- const resolved = Promise.resolve(this.body).then(onfulfilled, onrejected);
965
- if (this.res) this.res.send(this.body);
966
- return resolved;
967
- }
968
- };
969
-
970
- //#endregion
971
- //#region src/ResourceCollection.ts
972
- /**
973
- * ResourceCollection class to handle API resource transformation and response building for collections
974
- */
975
- var ResourceCollection = class ResourceCollection {
976
- body = { data: [] };
977
- resource;
978
- collects;
979
- additionalMeta;
980
- withResponseContext;
981
- /**
982
- * Preferred case style for this collection's output keys.
983
- * Set on a subclass to override the global default.
984
- */
985
- static preferredCase;
986
- /**
987
- * Response structure override for this collection class.
988
- */
989
- static responseStructure;
990
- called = {};
991
- constructor(rsc, res) {
992
- this.res = res;
993
- this.resource = rsc;
994
- }
995
- /**
996
- * Get the original resource data
997
- */
998
- data() {
999
- return this.toArray();
1000
- }
1001
- /**
1002
- * Get the current serialized output body.
1003
- */
1004
- getBody() {
1005
- this.json();
1006
- return this.body;
1007
- }
1008
- /**
1009
- * Replace the current serialized output body.
1010
- */
1011
- setBody(body) {
1012
- this.body = body;
1013
- return this;
1014
- }
1015
- /**
1016
- * Conditionally include a value in serialized output.
1017
- */
1018
- when(condition, value) {
1019
- return resolveWhen(condition, value);
1020
- }
1021
- /**
1022
- * Include a value only when it is not null/undefined.
1023
- */
1024
- whenNotNull(value) {
1025
- return resolveWhenNotNull(value);
1026
- }
1027
- /**
1028
- * Conditionally merge object attributes into serialized output.
1029
- */
1030
- mergeWhen(condition, value) {
1031
- return resolveMergeWhen(condition, value);
1032
- }
1033
- resolveResponseStructure() {
1034
- const local = this.constructor.responseStructure;
1035
- const collectsLocal = this.collects?.responseStructure;
1036
- const global = getGlobalResponseStructure();
1037
- return {
1038
- wrap: local?.wrap ?? collectsLocal?.wrap ?? global?.wrap ?? true,
1039
- rootKey: local?.rootKey ?? collectsLocal?.rootKey ?? global?.rootKey ?? "data",
1040
- factory: local?.factory ?? collectsLocal?.factory ?? global?.factory
1041
- };
1042
- }
1043
- getPayloadKey() {
1044
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
1045
- return factory || !wrap ? void 0 : rootKey;
1046
- }
1047
- /**
1048
- * Convert resource to JSON response format
1049
- *
1050
- * @returns
1051
- */
1052
- json() {
1053
- if (!this.called.json) {
1054
- this.called.json = true;
1055
- let data = this.data();
1056
- if (this.collects) data = data.map((item) => new this.collects(item).data());
1057
- data = sanitizeConditionalAttributes(data);
1058
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
1059
- const { metaKey } = getPaginationExtraKeys();
1060
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
1061
- if (metaKey) delete paginationExtras[metaKey];
1062
- const caseStyle = this.constructor.preferredCase ?? this.collects?.preferredCase ?? getGlobalCase();
1063
- if (caseStyle) {
1064
- const transformer = getCaseTransformer(caseStyle);
1065
- data = transformKeys(data, transformer);
1066
- }
1067
- const customMeta = mergeMetadata(resolveWithHookMetadata(this, ResourceCollection.prototype.with), this.additionalMeta);
1068
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
1069
- this.body = buildResponseEnvelope({
1070
- payload: data,
1071
- meta: configuredMeta,
1072
- metaKey,
1073
- wrap,
1074
- rootKey,
1075
- factory,
1076
- context: {
1077
- type: "collection",
1078
- resource: this.resource
1079
- }
1080
- });
1081
- this.body = appendRootProperties(this.body, {
1082
- ...paginationExtras,
1083
- ...customMeta || {}
1084
- }, rootKey);
1085
- }
1086
- return this;
1087
- }
1088
- /**
1089
- * Append structured metadata to the response body.
1090
- *
1091
- * @param meta Metadata object or metadata factory
1092
- * @returns
1093
- */
1094
- with(meta) {
1095
- this.called.with = true;
1096
- if (typeof meta === "undefined") return this.additionalMeta || {};
1097
- const resolvedMeta = typeof meta === "function" ? meta(this.resource) : meta;
1098
- this.additionalMeta = mergeMetadata(this.additionalMeta, resolvedMeta);
1099
- if (this.called.json) {
1100
- const { rootKey } = this.resolveResponseStructure();
1101
- this.body = appendRootProperties(this.body, resolvedMeta, rootKey);
1102
- }
1103
- return this;
1104
- }
1105
- /**
1106
- * Typed fluent metadata helper.
1107
- *
1108
- * @param meta Metadata object or metadata factory
1109
- * @returns
1110
- */
1111
- withMeta(meta) {
1112
- this.with(meta);
1113
- return this;
1114
- }
1115
- /**
1116
- * Flatten resource to return original data
1117
- *
1118
- * @returns
1119
- */
1120
- toArray() {
1121
- this.called.toArray = true;
1122
- this.json();
1123
- return Array.isArray(this.resource) ? [...this.resource] : [...this.resource.data];
1124
- }
1125
- /**
1126
- * Add additional properties to the response body
1127
- *
1128
- * @param extra Additional properties to merge into the response body
1129
- * @returns
1130
- */
1131
- additional(extra) {
1132
- this.called.additional = true;
1133
- this.json();
1134
- delete extra.cursor;
1135
- delete extra.pagination;
1136
- const payloadKey = this.getPayloadKey();
1137
- if (extra.data && payloadKey && Array.isArray(this.body[payloadKey])) this.body[payloadKey] = [...this.body[payloadKey], ...extra.data];
1138
- this.body = {
1139
- ...this.body,
1140
- ...extra
1141
- };
1142
- return this;
1143
- }
1144
- response(res) {
1145
- this.called.toResponse = true;
1146
- this.json();
1147
- const rawResponse = res ?? this.res;
1148
- const response = new ServerResponse(rawResponse, this.body);
1149
- this.withResponseContext = {
1150
- response,
1151
- raw: rawResponse
1152
- };
1153
- this.called.withResponse = true;
1154
- this.withResponse(response, rawResponse);
1155
- return response;
1156
- }
1157
- /**
1158
- * Customize the outgoing transport response right before dispatch.
1159
- *
1160
- * Override in custom classes to mutate headers/status/body.
1161
- */
1162
- withResponse(_response, _rawResponse) {
1163
- return this;
1164
- }
1165
- setCollects(collects) {
1166
- this.collects = collects;
1167
- return this;
1168
- }
1169
- /**
1170
- * Promise-like then method to allow chaining with async/await or .then() syntax
1171
- *
1172
- * @param onfulfilled Callback to handle the fulfilled state of the promise, receiving the response body
1173
- * @param onrejected Callback to handle the rejected state of the promise, receiving the error reason
1174
- * @returns A promise that resolves to the result of the onfulfilled or onrejected callback
1175
- */
1176
- then(onfulfilled, onrejected) {
1177
- this.called.then = true;
1178
- this.json();
1179
- if (this.res) {
1180
- const response = new ServerResponse(this.res, this.body);
1181
- this.withResponseContext = {
1182
- response,
1183
- raw: this.res
1184
- };
1185
- this.called.withResponse = true;
1186
- this.withResponse(response, this.res);
1187
- } else {
1188
- this.called.withResponse = true;
1189
- this.withResponse();
1190
- }
1191
- const resolved = Promise.resolve(this.body).then(onfulfilled, onrejected);
1192
- if (this.res) this.res.send(this.body);
1193
- return resolved;
1194
- }
1195
- /**
1196
- * Promise-like catch method to handle rejected state of the promise
1197
- *
1198
- * @param onrejected
1199
- * @returns
1200
- */
1201
- catch(onrejected) {
1202
- return this.then(void 0, onrejected);
1203
- }
1204
- /**
1205
- * Promise-like finally method to handle cleanup after promise is settled
1206
- *
1207
- * @param onfinally
1208
- * @returns
1209
- */
1210
- finally(onfinally) {
1211
- return this.then(onfinally, onfinally);
1212
- }
1213
- };
1214
-
1215
- //#endregion
1216
- //#region src/Resource.ts
1217
- /**
1218
- * Resource class to handle API resource transformation and response building
1219
- */
1220
- var Resource = class Resource {
1221
- body = { data: {} };
1222
- resource;
1223
- additionalMeta;
1224
- withResponseContext;
1225
- /**
1226
- * Preferred case style for this resource's output keys.
1227
- * Set on a subclass to override the global default.
1228
- */
1229
- static preferredCase;
1230
- /**
1231
- * Response structure override for this resource class.
1232
- */
1233
- static responseStructure;
1234
- called = {};
1235
- constructor(rsc, res) {
1236
- this.res = res;
1237
- this.resource = rsc;
1238
- /**
1239
- * Copy properties from rsc to this instance for easy
1240
- * access, but only if data is not an array
1241
- */
1242
- if (!Array.isArray(this.resource.data ?? this.resource)) {
1243
- for (const key of Object.keys(this.resource.data ?? this.resource)) if (!(key in this)) Object.defineProperty(this, key, {
1244
- enumerable: true,
1245
- configurable: true,
1246
- get: () => {
1247
- return this.resource.data?.[key] ?? this.resource[key];
1248
- },
1249
- set: (value) => {
1250
- if (this.resource.data && this.resource.data[key]) this.resource.data[key] = value;
1251
- else this.resource[key] = value;
1252
- }
1253
- });
1254
- }
1255
- }
1256
- /**
1257
- * Create a ResourceCollection from an array of resource data or a Collectible instance
1258
- *
1259
- * @param data
1260
- * @returns
1261
- */
1262
- static collection(data) {
1263
- return new ResourceCollection(data).setCollects(this);
1264
- }
1265
- /**
1266
- * Get the original resource data
1267
- */
1268
- data() {
1269
- return this.toArray();
1270
- }
1271
- /**
1272
- * Get the current serialized output body.
1273
- */
1274
- getBody() {
1275
- this.json();
1276
- return this.body;
1277
- }
1278
- /**
1279
- * Replace the current serialized output body.
1280
- */
1281
- setBody(body) {
1282
- this.body = body;
1283
- return this;
1284
- }
1285
- /**
1286
- * Conditionally include a value in serialized output.
1287
- */
1288
- when(condition, value) {
1289
- return resolveWhen(condition, value);
1290
- }
1291
- /**
1292
- * Include a value only when it is not null/undefined.
1293
- */
1294
- whenNotNull(value) {
1295
- return resolveWhenNotNull(value);
1296
- }
1297
- /**
1298
- * Conditionally merge object attributes into serialized output.
1299
- */
1300
- mergeWhen(condition, value) {
1301
- return resolveMergeWhen(condition, value);
1302
- }
1303
- resolveResponseStructure() {
1304
- const local = this.constructor.responseStructure;
1305
- const global = getGlobalResponseStructure();
1306
- return {
1307
- wrap: local?.wrap ?? global?.wrap ?? true,
1308
- rootKey: local?.rootKey ?? global?.rootKey ?? "data",
1309
- factory: local?.factory ?? global?.factory
1310
- };
1311
- }
1312
- getPayloadKey() {
1313
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
1314
- return factory || !wrap ? void 0 : rootKey;
1315
- }
1316
- /**
1317
- * Convert resource to JSON response format
1318
- *
1319
- * @returns
1320
- */
1321
- json() {
1322
- if (!this.called.json) {
1323
- this.called.json = true;
1324
- const resource = this.data();
1325
- let data = Array.isArray(resource) ? [...resource] : { ...resource };
1326
- if (typeof data.data !== "undefined") data = data.data;
1327
- data = sanitizeConditionalAttributes(data);
1328
- const caseStyle = this.constructor.preferredCase ?? getGlobalCase();
1329
- if (caseStyle) {
1330
- const transformer = getCaseTransformer(caseStyle);
1331
- data = transformKeys(data, transformer);
1332
- }
1333
- const customMeta = mergeMetadata(resolveWithHookMetadata(this, Resource.prototype.with), this.additionalMeta);
1334
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
1335
- this.body = buildResponseEnvelope({
1336
- payload: data,
1337
- wrap,
1338
- rootKey,
1339
- factory,
1340
- context: {
1341
- type: "resource",
1342
- resource: this.resource
1343
- }
1344
- });
1345
- this.body = appendRootProperties(this.body, customMeta, rootKey);
1346
- }
1347
- return this;
1348
- }
1349
- /**
1350
- * Append structured metadata to the response body.
1351
- *
1352
- * @param meta Metadata object or metadata factory
1353
- * @returns
1354
- */
1355
- with(meta) {
1356
- this.called.with = true;
1357
- if (typeof meta === "undefined") return this.additionalMeta || {};
1358
- const resolvedMeta = typeof meta === "function" ? meta(this.resource) : meta;
1359
- this.additionalMeta = mergeMetadata(this.additionalMeta, resolvedMeta);
1360
- if (this.called.json) {
1361
- const { rootKey } = this.resolveResponseStructure();
1362
- this.body = appendRootProperties(this.body, resolvedMeta, rootKey);
1363
- }
1364
- return this;
1365
- }
1366
- /**
1367
- * Typed fluent metadata helper.
1368
- *
1369
- * @param meta Metadata object or metadata factory
1370
- * @returns
1371
- */
1372
- withMeta(meta) {
1373
- this.with(meta);
1374
- return this;
1375
- }
1376
- /**
1377
- * Flatten resource to array format (for collections) or return original data for single resources
1378
- *
1379
- * @returns
1380
- */
1381
- toArray() {
1382
- this.called.toArray = true;
1383
- this.json();
1384
- let data = Array.isArray(this.resource) ? [...this.resource] : { ...this.resource };
1385
- if (!Array.isArray(data) && typeof data.data !== "undefined") data = data.data;
1386
- return data;
1387
- }
1388
- /**
1389
- * Add additional properties to the response body
1390
- *
1391
- * @param extra Additional properties to merge into the response body
1392
- * @returns
1393
- */
1394
- additional(extra) {
1395
- this.called.additional = true;
1396
- this.json();
1397
- const payloadKey = this.getPayloadKey();
1398
- if (extra.data && payloadKey && typeof this.body[payloadKey] !== "undefined") this.body[payloadKey] = Array.isArray(this.body[payloadKey]) ? [...this.body[payloadKey], ...extra.data] : {
1399
- ...this.body[payloadKey],
1400
- ...extra.data
1401
- };
1402
- this.body = {
1403
- ...this.body,
1404
- ...extra
1405
- };
1406
- return this;
1407
- }
1408
- response(res) {
1409
- this.called.toResponse = true;
1410
- this.json();
1411
- const rawResponse = res ?? this.res;
1412
- const response = new ServerResponse(rawResponse, this.body);
1413
- this.withResponseContext = {
1414
- response,
1415
- raw: rawResponse
1416
- };
1417
- this.called.withResponse = true;
1418
- this.withResponse(response, rawResponse);
1419
- return response;
1420
- }
1421
- /**
1422
- * Customize the outgoing transport response right before dispatch.
1423
- *
1424
- * Override in custom classes to mutate headers/status/body.
1425
- */
1426
- withResponse(_response, _rawResponse) {
1427
- return this;
1428
- }
1429
- /**
1430
- * Promise-like then method to allow chaining with async/await or .then() syntax
1431
- *
1432
- * @param onfulfilled Callback to handle the fulfilled state of the promise, receiving the response body
1433
- * @param onrejected Callback to handle the rejected state of the promise, receiving the error reason
1434
- * @returns A promise that resolves to the result of the onfulfilled or onrejected callback
1435
- */
1436
- then(onfulfilled, onrejected) {
1437
- this.called.then = true;
1438
- this.json();
1439
- if (this.res) {
1440
- const response = new ServerResponse(this.res, this.body);
1441
- this.withResponseContext = {
1442
- response,
1443
- raw: this.res
1444
- };
1445
- this.called.withResponse = true;
1446
- this.withResponse(response, this.res);
1447
- } else {
1448
- this.called.withResponse = true;
1449
- this.withResponse();
1450
- }
1451
- const resolved = Promise.resolve(this.body).then(onfulfilled, onrejected);
1452
- if (this.res) this.res.send(this.body);
1453
- return resolved;
1454
- }
1455
- /**
1456
- * Promise-like catch method to handle rejected state of the promise
1457
- *
1458
- * @param onrejected
1459
- * @returns
1460
- */
1461
- catch(onrejected) {
1462
- return this.then(void 0, onrejected);
1463
- }
1464
- /**
1465
- * Promise-like finally method to handle cleanup after promise is settled
1466
- *
1467
- * @param onfinally
1468
- * @returns
1469
- */
1470
- finally(onfinally) {
1471
- return this.then(onfinally, onfinally);
1472
- }
1473
- };
1474
-
1475
- //#endregion
1476
- exports.ApiResource = ApiResource;
1477
- exports.CONDITIONAL_ATTRIBUTE_MISSING = CONDITIONAL_ATTRIBUTE_MISSING;
1478
- exports.CliApp = CliApp;
1479
- exports.GenericResource = GenericResource;
1480
- exports.InitCommand = InitCommand;
1481
- exports.MakeResource = MakeResource;
1482
- exports.Resource = Resource;
1483
- exports.ResourceCollection = ResourceCollection;
1484
- exports.ServerResponse = ServerResponse;
1485
- exports.appendRootProperties = appendRootProperties;
1486
- exports.buildPaginationExtras = buildPaginationExtras;
1487
- exports.buildResponseEnvelope = buildResponseEnvelope;
1488
- exports.defineConfig = defineConfig;
1489
- exports.getCaseTransformer = getCaseTransformer;
1490
- exports.getDefaultConfig = getDefaultConfig;
1491
- exports.getGlobalBaseUrl = getGlobalBaseUrl;
1492
- exports.getGlobalCase = getGlobalCase;
1493
- exports.getGlobalCursorMeta = getGlobalCursorMeta;
1494
- exports.getGlobalPageName = getGlobalPageName;
1495
- exports.getGlobalPaginatedExtras = getGlobalPaginatedExtras;
1496
- exports.getGlobalPaginatedLinks = getGlobalPaginatedLinks;
1497
- exports.getGlobalPaginatedMeta = getGlobalPaginatedMeta;
1498
- exports.getGlobalResponseFactory = getGlobalResponseFactory;
1499
- exports.getGlobalResponseRootKey = getGlobalResponseRootKey;
1500
- exports.getGlobalResponseStructure = getGlobalResponseStructure;
1501
- exports.getGlobalResponseWrap = getGlobalResponseWrap;
1502
- exports.getPaginationExtraKeys = getPaginationExtraKeys;
1503
- exports.isPlainObject = isPlainObject;
1504
- exports.mergeMetadata = mergeMetadata;
1505
- exports.resolveMergeWhen = resolveMergeWhen;
1506
- exports.resolveWhen = resolveWhen;
1507
- exports.resolveWhenNotNull = resolveWhenNotNull;
1508
- exports.resolveWithHookMetadata = resolveWithHookMetadata;
1509
- exports.sanitizeConditionalAttributes = sanitizeConditionalAttributes;
1510
- exports.setGlobalBaseUrl = setGlobalBaseUrl;
1511
- exports.setGlobalCase = setGlobalCase;
1512
- exports.setGlobalCursorMeta = setGlobalCursorMeta;
1513
- exports.setGlobalPageName = setGlobalPageName;
1514
- exports.setGlobalPaginatedExtras = setGlobalPaginatedExtras;
1515
- exports.setGlobalPaginatedLinks = setGlobalPaginatedLinks;
1516
- exports.setGlobalPaginatedMeta = setGlobalPaginatedMeta;
1517
- exports.setGlobalResponseFactory = setGlobalResponseFactory;
1518
- exports.setGlobalResponseRootKey = setGlobalResponseRootKey;
1519
- exports.setGlobalResponseStructure = setGlobalResponseStructure;
1520
- exports.setGlobalResponseWrap = setGlobalResponseWrap;
1521
- exports.splitWords = splitWords;
1522
- exports.toCamelCase = toCamelCase;
1523
- exports.toKebabCase = toKebabCase;
1524
- exports.toPascalCase = toPascalCase;
1525
- exports.toSnakeCase = toSnakeCase;
1526
- exports.transformKeys = transformKeys;
28
+ `;var $=class{_status=200;headers={};constructor(e,t){this.response=e,this.body=t}setStatusCode(e){return this._status=e,`status`in this.response&&typeof this.response.status==`function`?this.response.status(e):`status`in this.response&&(this.response.status=e),this}status(){return this._status}statusText(){if(`statusMessage`in this.response)return this.response.statusMessage;if(`statusText`in this.response)return this.response.statusText}setCookie(e,t,n){return this.#e(`Set-Cookie`,`${e}=${t}; ${Object.entries(n||{}).map(([e,t])=>`${e}=${t}`).join(`; `)}`),this}setHeaders(e){for(let[t,n]of Object.entries(e))this.#e(t,n);return this}header(e,t){return this.#e(e,t),this}#e(e,t){this.headers[e]=t,`headers`in this.response?this.response.headers.set(e,t):`setHeader`in this.response&&this.response.setHeader(e,t)}then(e,t){let n=Promise.resolve(this.body).then(e,t);return`send`in this.response&&this.response.send(this.body),n}catch(e){return this.then(void 0,e)}finally(e){return this.then(e,e)}},Te=class e{body={data:{}};resource;collects;additionalMeta;withResponseContext;static preferredCase;static responseStructure;called={};constructor(e,t){if(this.res=t,this.resource=e,!Array.isArray(this.resource.data??this.resource))for(let e of Object.keys(this.resource.data??this.resource))e in this||Object.defineProperty(this,e,{enumerable:!0,configurable:!0,get:()=>this.resource.data?.[e]??this.resource[e],set:t=>{this.resource.data&&this.resource.data[e]?this.resource.data[e]=t:this.resource[e]=t}})}data(){return this.resource}getBody(){return this.json(),this.body}setBody(e){return this.body=e,this}when(e,t){return R(e,t)}whenNotNull(e){return z(e)}mergeWhen(e,t){return B(e,t)}resolveResponseStructure(){let e=this.constructor.responseStructure,t=this.collects?.responseStructure,n=C();return{wrap:e?.wrap??t?.wrap??n?.wrap??!0,rootKey:e?.rootKey??t?.rootKey??n?.rootKey??`data`,factory:e?.factory??t?.factory??n?.factory}}getPayloadKey(){let{wrap:e,rootKey:t,factory:n}=this.resolveResponseStructure();return n||!e?void 0:t}json(){if(!this.called.json){this.called.json=!0;let t=this.data(),n=Array.isArray(t)?[...t]:{...t};Array.isArray(n)&&this.collects&&(n=n.map(e=>new this.collects(e).data()),this.resource=n),n.data!==void 0&&(n=n.data),n=V(n);let r=j(this.resource),{metaKey:i}=k(),a=i?r[i]:void 0;i&&delete r[i];let o=this.constructor.preferredCase??x();if(o){let e=q(o);n=J(n,e)}let s=P(I(this,e.prototype.with),this.additionalMeta),{wrap:c,rootKey:l,factory:u}=this.resolveResponseStructure();this.body=F({payload:n,meta:a,metaKey:i,wrap:c,rootKey:l,factory:u,context:{type:`generic`,resource:this.resource}}),this.body=N(this.body,{...r,...s||{}},l)}return this}with(e){if(this.called.with=!0,e===void 0)return this.additionalMeta||{};let t=typeof e==`function`?e(this.resource):e;if(this.additionalMeta=P(this.additionalMeta,t),this.called.json){let{rootKey:e}=this.resolveResponseStructure();this.body=N(this.body,t,e)}return this}withMeta(e){return this.with(e),this}toArray(){this.called.toArray=!0,this.json();let e=Array.isArray(this.resource)?[...this.resource]:{...this.resource};return e.data!==void 0&&(e=e.data),e}additional(e){this.called.additional=!0,this.json();let t=e.data;delete e.data,delete e.pagination;let n=this.getPayloadKey();return t&&n&&this.body[n]!==void 0&&(this.body[n]=Array.isArray(this.body[n])?[...this.body[n],...t]:{...this.body[n],...t}),this.body={...this.body,...e},this}response(e){this.called.toResponse=!0,this.json();let t=e??this.res,n=new $(t,this.body);return this.withResponseContext={response:n,raw:t},this.called.withResponse=!0,this.withResponse(n,t),n}withResponse(e,t){return this}then(e,t){if(this.called.then=!0,this.json(),this.res){let e=new $(this.res,this.body);this.withResponseContext={response:e,raw:this.res},this.called.withResponse=!0,this.withResponse(e,this.res)}else this.called.withResponse=!0,this.withResponse();let n=Promise.resolve(this.body).then(e,t);return this.res&&this.res.send(this.body),n}},Ee=class e{body={data:[]};resource;collects;additionalMeta;withResponseContext;static preferredCase;static responseStructure;called={};constructor(e,t){this.res=t,this.resource=e}data(){return this.toArray()}getBody(){return this.json(),this.body}setBody(e){return this.body=e,this}when(e,t){return R(e,t)}whenNotNull(e){return z(e)}mergeWhen(e,t){return B(e,t)}resolveResponseStructure(){let e=this.constructor.responseStructure,t=this.collects?.responseStructure,n=C();return{wrap:e?.wrap??t?.wrap??n?.wrap??!0,rootKey:e?.rootKey??t?.rootKey??n?.rootKey??`data`,factory:e?.factory??t?.factory??n?.factory}}getPayloadKey(){let{wrap:e,rootKey:t,factory:n}=this.resolveResponseStructure();return n||!e?void 0:t}json(){if(!this.called.json){this.called.json=!0;let t=this.data();this.collects&&(t=t.map(e=>new this.collects(e).data())),t=V(t);let n=Array.isArray(this.resource)?{}:j(this.resource),{metaKey:r}=k(),i=r?n[r]:void 0;r&&delete n[r];let a=this.constructor.preferredCase??this.collects?.preferredCase??x();if(a){let e=q(a);t=J(t,e)}let o=P(I(this,e.prototype.with),this.additionalMeta),{wrap:s,rootKey:c,factory:l}=this.resolveResponseStructure();this.body=F({payload:t,meta:i,metaKey:r,wrap:s,rootKey:c,factory:l,context:{type:`collection`,resource:this.resource}}),this.body=N(this.body,{...n,...o||{}},c)}return this}with(e){if(this.called.with=!0,e===void 0)return this.additionalMeta||{};let t=typeof e==`function`?e(this.resource):e;if(this.additionalMeta=P(this.additionalMeta,t),this.called.json){let{rootKey:e}=this.resolveResponseStructure();this.body=N(this.body,t,e)}return this}withMeta(e){return this.with(e),this}toArray(){return this.called.toArray=!0,this.json(),Array.isArray(this.resource)?[...this.resource]:[...this.resource.data]}additional(e){this.called.additional=!0,this.json(),delete e.cursor,delete e.pagination;let t=this.getPayloadKey();return e.data&&t&&Array.isArray(this.body[t])&&(this.body[t]=[...this.body[t],...e.data]),this.body={...this.body,...e},this}response(e){this.called.toResponse=!0,this.json();let t=e??this.res,n=new $(t,this.body);return this.withResponseContext={response:n,raw:t},this.called.withResponse=!0,this.withResponse(n,t),n}withResponse(e,t){return this}setCollects(e){return this.collects=e,this}then(e,t){if(this.called.then=!0,this.json(),this.res){let e=new $(this.res,this.body);this.withResponseContext={response:e,raw:this.res},this.called.withResponse=!0,this.withResponse(e,this.res)}else this.called.withResponse=!0,this.withResponse();let n=Promise.resolve(this.body).then(e,t);return this.res&&this.res.send(this.body),n}catch(e){return this.then(void 0,e)}finally(e){return this.then(e,e)}},De=class e{body={data:{}};resource;additionalMeta;withResponseContext;static preferredCase;static responseStructure;called={};constructor(e,t){if(this.res=t,this.resource=e,!Array.isArray(this.resource.data??this.resource))for(let e of Object.keys(this.resource.data??this.resource))e in this||Object.defineProperty(this,e,{enumerable:!0,configurable:!0,get:()=>this.resource.data?.[e]??this.resource[e],set:t=>{this.resource.data&&this.resource.data[e]?this.resource.data[e]=t:this.resource[e]=t}})}static collection(e){return new Ee(e).setCollects(this)}data(){return this.toArray()}getBody(){return this.json(),this.body}setBody(e){return this.body=e,this}when(e,t){return R(e,t)}whenNotNull(e){return z(e)}mergeWhen(e,t){return B(e,t)}resolveResponseStructure(){let e=this.constructor.responseStructure,t=C();return{wrap:e?.wrap??t?.wrap??!0,rootKey:e?.rootKey??t?.rootKey??`data`,factory:e?.factory??t?.factory}}getPayloadKey(){let{wrap:e,rootKey:t,factory:n}=this.resolveResponseStructure();return n||!e?void 0:t}json(){if(!this.called.json){this.called.json=!0;let t=this.data(),n=Array.isArray(t)?[...t]:{...t};n.data!==void 0&&(n=n.data),n=V(n);let r=this.constructor.preferredCase??x();if(r){let e=q(r);n=J(n,e)}let i=P(I(this,e.prototype.with),this.additionalMeta),{wrap:a,rootKey:o,factory:s}=this.resolveResponseStructure();this.body=F({payload:n,wrap:a,rootKey:o,factory:s,context:{type:`resource`,resource:this.resource}}),this.body=N(this.body,i,o)}return this}with(e){if(this.called.with=!0,e===void 0)return this.additionalMeta||{};let t=typeof e==`function`?e(this.resource):e;if(this.additionalMeta=P(this.additionalMeta,t),this.called.json){let{rootKey:e}=this.resolveResponseStructure();this.body=N(this.body,t,e)}return this}withMeta(e){return this.with(e),this}toArray(){this.called.toArray=!0,this.json();let e=Array.isArray(this.resource)?[...this.resource]:{...this.resource};return!Array.isArray(e)&&e.data!==void 0&&(e=e.data),e}additional(e){this.called.additional=!0,this.json();let t=this.getPayloadKey();return e.data&&t&&this.body[t]!==void 0&&(this.body[t]=Array.isArray(this.body[t])?[...this.body[t],...e.data]:{...this.body[t],...e.data}),this.body={...this.body,...e},this}response(e){this.called.toResponse=!0,this.json();let t=e??this.res,n=new $(t,this.body);return this.withResponseContext={response:n,raw:t},this.called.withResponse=!0,this.withResponse(n,t),n}withResponse(e,t){return this}then(e,t){if(this.called.then=!0,this.json(),this.res){let e=new $(this.res,this.body);this.withResponseContext={response:e,raw:this.res},this.called.withResponse=!0,this.withResponse(e,this.res)}else this.called.withResponse=!0,this.withResponse();let n=Promise.resolve(this.body).then(e,t);return this.res&&this.res.send(this.body),n}catch(e){return this.then(void 0,e)}finally(e){return this.then(e,e)}};exports.ApiResource=ee,exports.CONDITIONAL_ATTRIBUTE_MISSING=L,exports.CliApp=Se,exports.GenericResource=Te,exports.InitCommand=Ce,exports.MakeResource=we,exports.Resource=De,exports.ResourceCollection=Ee,exports.ServerResponse=$,exports.appendRootProperties=N,exports.applyRuntimeConfig=_e,exports.buildPaginationExtras=j,exports.buildResponseEnvelope=F,exports.defineConfig=X,exports.getCaseTransformer=q,exports.getDefaultConfig=he,exports.getGlobalBaseUrl=ue,exports.getGlobalCase=x,exports.getGlobalCursorMeta=O,exports.getGlobalPageName=fe,exports.getGlobalPaginatedExtras=T,exports.getGlobalPaginatedLinks=ce,exports.getGlobalPaginatedMeta=me,exports.getGlobalResponseFactory=se,exports.getGlobalResponseRootKey=ae,exports.getGlobalResponseStructure=C,exports.getGlobalResponseWrap=ie,exports.getPaginationExtraKeys=k,exports.isPlainObject=M,exports.loadRuntimeConfig=xe,exports.mergeMetadata=P,exports.resetRuntimeConfigForTests=ge,exports.resolveMergeWhen=B,exports.resolveWhen=R,exports.resolveWhenNotNull=z,exports.resolveWithHookMetadata=I,exports.sanitizeConditionalAttributes=V,exports.setGlobalBaseUrl=le,exports.setGlobalCase=b,exports.setGlobalCursorMeta=D,exports.setGlobalPageName=de,exports.setGlobalPaginatedExtras=w,exports.setGlobalPaginatedLinks=E,exports.setGlobalPaginatedMeta=pe,exports.setGlobalResponseFactory=oe,exports.setGlobalResponseRootKey=ne,exports.setGlobalResponseStructure=S,exports.setGlobalResponseWrap=re,exports.splitWords=H,exports.toCamelCase=U,exports.toKebabCase=K,exports.toPascalCase=G,exports.toSnakeCase=W,exports.transformKeys=J;