resora 1.3.4 → 1.3.5

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
@@ -436,17 +436,17 @@ const mergeMetadata = (base, incoming) => {
436
436
  //#endregion
437
437
  //#region src/utilities/arkorm.ts
438
438
  /**
439
- * Type guard to check if a value is an Arkorm-like model.
440
- *
441
- * Arkorm models expose `toObject()`. Some production model variants/proxies do
442
- * not expose `getRawAttributes()`, so the serializer should not require it.
439
+ * Type guard to check if a value is an Arkorm-like model, which is defined as an object
440
+ * that has a toObject method and optionally getRawAttributes, getAttribute, and
441
+ * setAttribute methods.
443
442
  *
444
443
  * @param value The value to check
445
444
  * @returns True if the value is an Arkorm-like model, false otherwise
446
445
  */
447
446
  const isArkormLikeModel = (value) => {
448
447
  if (!value || typeof value !== "object") return false;
449
- return typeof value.toObject === "function";
448
+ const candidate = value;
449
+ return typeof candidate.toObject === "function" && typeof candidate.getRawAttributes === "function";
450
450
  };
451
451
  /**
452
452
  * Type guard to check if a value is an Arkorm-like collection, which is defined as an object
@@ -491,30 +491,6 @@ const normalizeSerializableData = (value) => {
491
491
  }, {});
492
492
  return value;
493
493
  };
494
- const isPromiseLike = (value) => {
495
- return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
496
- };
497
- /**
498
- * Async variant of normalizeSerializableData. It resolves promise-like values at
499
- * every nesting level before converting Arkorm-like models and collections.
500
- *
501
- * @param value The value to normalize
502
- * @returns The normalized value, ready for serialization
503
- */
504
- const normalizeSerializableDataAsync = async (value) => {
505
- const resolvedValue = isPromiseLike(value) ? await value : value;
506
- if (Array.isArray(resolvedValue)) return Promise.all(resolvedValue.map((item) => normalizeSerializableDataAsync(item)));
507
- if (isResoraCollectionLike(resolvedValue)) return normalizeSerializableDataAsync(resolvedValue.toObject());
508
- if (isArkormLikeModel(resolvedValue)) return normalizeSerializableDataAsync(resolvedValue.toObject());
509
- if (isArkormLikeCollection(resolvedValue)) return normalizeSerializableDataAsync(resolvedValue.all());
510
- if (isPlainObject(resolvedValue)) return (await Promise.all(Object.entries(resolvedValue).map(async ([key, nestedValue]) => {
511
- return [key, await normalizeSerializableDataAsync(nestedValue)];
512
- }))).reduce((accumulator, [key, nestedValue]) => {
513
- accumulator[key] = nestedValue;
514
- return accumulator;
515
- }, {});
516
- return resolvedValue;
517
- };
518
494
 
519
495
  //#endregion
520
496
  //#region src/utilities/pagination.ts
@@ -1490,7 +1466,6 @@ var BaseSerializer = class {
1490
1466
  static ctx;
1491
1467
  instanceConfig;
1492
1468
  additionalMeta;
1493
- serializationPromise;
1494
1469
  called = {};
1495
1470
  constructor() {
1496
1471
  loadRuntimeConfig();
@@ -1591,12 +1566,6 @@ var BaseSerializer = class {
1591
1566
  resolveSerializationContext() {
1592
1567
  return getCtx() ?? this.constructor.ctx;
1593
1568
  }
1594
- isPromiseLike(value) {
1595
- return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
1596
- }
1597
- waitForSerialization() {
1598
- return this.serializationPromise ?? Promise.resolve();
1599
- }
1600
1569
  /**
1601
1570
  * Dispatch a body to a raw response object when it exposes a send() transport method.
1602
1571
  *
@@ -1672,28 +1641,27 @@ var BaseSerializer = class {
1672
1641
  runThen(input) {
1673
1642
  this.called.then = true;
1674
1643
  input.ensureJson();
1675
- return this.waitForSerialization().then(() => {
1676
- const initialBody = input.body();
1677
- let response;
1678
- if (typeof input.rawResponse !== "undefined") {
1679
- response = input.createServerResponse(input.rawResponse, initialBody);
1680
- this.called.withResponse = true;
1681
- input.callWithResponse(response, input.rawResponse);
1682
- } else {
1683
- this.called.withResponse = true;
1684
- input.callWithResponse();
1685
- }
1686
- const resolvedBody = input.body();
1687
- if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1688
- const dispatchedBody = this.applyResponsePlugins({
1689
- body: resolvedBody,
1690
- rawResponse: input.rawResponse,
1691
- response
1692
- });
1693
- if (typeof response?.send === "function") response.send(dispatchedBody);
1694
- else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1695
- return dispatchedBody;
1696
- }).then(input.onfulfilled, input.onrejected);
1644
+ const initialBody = input.body();
1645
+ let response;
1646
+ if (typeof input.rawResponse !== "undefined") {
1647
+ response = input.createServerResponse(input.rawResponse, initialBody);
1648
+ this.called.withResponse = true;
1649
+ input.callWithResponse(response, input.rawResponse);
1650
+ } else {
1651
+ this.called.withResponse = true;
1652
+ input.callWithResponse();
1653
+ }
1654
+ const resolvedBody = input.body();
1655
+ if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1656
+ const dispatchedBody = this.applyResponsePlugins({
1657
+ body: resolvedBody,
1658
+ rawResponse: input.rawResponse,
1659
+ response
1660
+ });
1661
+ const resolved = Promise.resolve(dispatchedBody).then(input.onfulfilled, input.onrejected);
1662
+ if (typeof response?.send === "function") response.send(dispatchedBody);
1663
+ else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1664
+ return resolved;
1697
1665
  }
1698
1666
  /**
1699
1667
  * Get or set the resource-level configuration for this serializer instance.
@@ -1883,52 +1851,17 @@ var GenericResource = class GenericResource extends BaseSerializer {
1883
1851
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
1884
1852
  return factory || !wrap ? void 0 : rootKey;
1885
1853
  }
1886
- serializeGenericResource(resource, ctx) {
1887
- let data = normalizeSerializableData(resource);
1888
- const serialize = (resolvedData) => {
1889
- data = resolvedData;
1890
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1891
- data = sanitizeConditionalAttributes(data);
1892
- const paginationExtras = buildPaginationExtras(this.resource);
1893
- const { metaKey } = getPaginationExtraKeys();
1894
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
1895
- if (metaKey) delete paginationExtras[metaKey];
1896
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
1897
- if (caseStyle) {
1898
- const transformer = getCaseTransformer(caseStyle);
1899
- data = transformKeys(data, transformer);
1900
- }
1901
- const customMeta = this.resolveMergedMeta(GenericResource.prototype.with);
1902
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
1903
- this.body = buildResponseEnvelope({
1904
- payload: data,
1905
- meta: configuredMeta,
1906
- metaKey,
1907
- wrap,
1908
- rootKey,
1909
- factory,
1910
- context: {
1911
- type: "generic",
1912
- resource: this.resource
1913
- }
1914
- });
1915
- this.body = appendRootProperties(this.body, {
1916
- ...paginationExtras,
1917
- ...customMeta || {}
1918
- }, rootKey);
1919
- this.body = this.applySerializePlugins(this.body);
1920
- };
1921
- if (Array.isArray(data) && this.collects) {
1922
- const collected = data.map((item) => new this.collects(item).data(ctx));
1923
- if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected).then(serialize);
1924
- data = collected;
1925
- }
1926
- serialize(data);
1927
- }
1928
- async serializeGenericResourceAsync(resource, ctx) {
1929
- let data = await normalizeSerializableDataAsync(resource);
1930
- const serialize = (resolvedData) => {
1931
- data = resolvedData;
1854
+ /**
1855
+ * Convert resource to JSON response format
1856
+ *
1857
+ * @returns
1858
+ */
1859
+ json() {
1860
+ if (!this.called.json) {
1861
+ this.called.json = true;
1862
+ const ctx = this.resolveSerializationContext();
1863
+ let data = normalizeSerializableData(this.data(ctx));
1864
+ if (Array.isArray(data) && this.collects) data = data.map((item) => new this.collects(item).data(ctx));
1932
1865
  if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1933
1866
  data = sanitizeConditionalAttributes(data);
1934
1867
  const paginationExtras = buildPaginationExtras(this.resource);
@@ -1959,31 +1892,6 @@ var GenericResource = class GenericResource extends BaseSerializer {
1959
1892
  ...customMeta || {}
1960
1893
  }, rootKey);
1961
1894
  this.body = this.applySerializePlugins(this.body);
1962
- };
1963
- if (Array.isArray(data) && this.collects) {
1964
- const collected = data.map((item) => new this.collects(item).data(ctx));
1965
- data = await Promise.all(collected);
1966
- data = await normalizeSerializableDataAsync(data);
1967
- }
1968
- serialize(data);
1969
- }
1970
- /**
1971
- * Convert resource to JSON response format
1972
- *
1973
- * @returns
1974
- */
1975
- json() {
1976
- if (!this.called.json) {
1977
- this.called.json = true;
1978
- const ctx = this.resolveSerializationContext();
1979
- const resource = this.data(ctx);
1980
- if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
1981
- return this.serializeGenericResourceAsync(resolved, ctx);
1982
- });
1983
- else {
1984
- const result = this.serializeGenericResource(resource, ctx);
1985
- if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
1986
- }
1987
1895
  }
1988
1896
  return this;
1989
1897
  }
@@ -2277,78 +2185,6 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2277
2185
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2278
2186
  return factory || !wrap ? void 0 : rootKey;
2279
2187
  }
2280
- serializeCollectionData(items) {
2281
- let data = normalizeSerializableData(items);
2282
- data = sanitizeConditionalAttributes(data);
2283
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2284
- const { metaKey } = getPaginationExtraKeys();
2285
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2286
- if (metaKey) delete paginationExtras[metaKey];
2287
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2288
- if (caseStyle) {
2289
- const transformer = getCaseTransformer(caseStyle);
2290
- data = transformKeys(data, transformer);
2291
- }
2292
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2293
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2294
- this.body = buildResponseEnvelope({
2295
- payload: data,
2296
- meta: configuredMeta,
2297
- metaKey,
2298
- wrap,
2299
- rootKey,
2300
- factory,
2301
- context: {
2302
- type: "collection",
2303
- resource: this.resource
2304
- }
2305
- });
2306
- this.body = appendRootProperties(this.body, {
2307
- ...paginationExtras,
2308
- ...customMeta || {}
2309
- }, rootKey);
2310
- this.body = this.applySerializePlugins(this.body);
2311
- }
2312
- async serializeCollectionDataAsync(items) {
2313
- let data = await normalizeSerializableDataAsync(items);
2314
- data = sanitizeConditionalAttributes(data);
2315
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2316
- const { metaKey } = getPaginationExtraKeys();
2317
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2318
- if (metaKey) delete paginationExtras[metaKey];
2319
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2320
- if (caseStyle) {
2321
- const transformer = getCaseTransformer(caseStyle);
2322
- data = transformKeys(data, transformer);
2323
- }
2324
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2325
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2326
- this.body = buildResponseEnvelope({
2327
- payload: data,
2328
- meta: configuredMeta,
2329
- metaKey,
2330
- wrap,
2331
- rootKey,
2332
- factory,
2333
- context: {
2334
- type: "collection",
2335
- resource: this.resource
2336
- }
2337
- });
2338
- this.body = appendRootProperties(this.body, {
2339
- ...paginationExtras,
2340
- ...customMeta || {}
2341
- }, rootKey);
2342
- this.body = this.applySerializePlugins(this.body);
2343
- }
2344
- resolveCollectionDataForSerialization(items, ctx) {
2345
- if (this.collects && this.data === ResourceCollection.prototype.data) {
2346
- const collected = items.map((item) => new this.collects(item).data(ctx));
2347
- if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected);
2348
- return collected;
2349
- }
2350
- return items;
2351
- }
2352
2188
  /**
2353
2189
  * Convert resource to JSON response format
2354
2190
  *
@@ -2358,24 +2194,38 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2358
2194
  if (!this.called.json) {
2359
2195
  this.called.json = true;
2360
2196
  const ctx = this.resolveSerializationContext();
2361
- const data = this.data(ctx);
2362
- const serialize = (items) => {
2363
- const resolvedData = this.resolveCollectionDataForSerialization(items, ctx);
2364
- if (this.isPromiseLike(resolvedData)) return resolvedData.then((resolved) => {
2365
- return this.serializeCollectionDataAsync(resolved);
2366
- });
2367
- this.serializeCollectionData(resolvedData);
2368
- };
2369
- if (this.isPromiseLike(data)) this.serializationPromise = Promise.resolve(data).then((items) => {
2370
- const resolvedData = this.resolveCollectionDataForSerialization(items, ctx);
2371
- return Promise.resolve(resolvedData).then((resolved) => {
2372
- return this.serializeCollectionDataAsync(resolved);
2373
- });
2374
- });
2375
- else {
2376
- const result = serialize(data);
2377
- if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
2197
+ let data = this.data(ctx);
2198
+ if (this.collects && this.data === ResourceCollection.prototype.data) data = data.map((item) => new this.collects(item).data(ctx));
2199
+ data = normalizeSerializableData(data);
2200
+ data = sanitizeConditionalAttributes(data);
2201
+ const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2202
+ const { metaKey } = getPaginationExtraKeys();
2203
+ const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2204
+ if (metaKey) delete paginationExtras[metaKey];
2205
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2206
+ if (caseStyle) {
2207
+ const transformer = getCaseTransformer(caseStyle);
2208
+ data = transformKeys(data, transformer);
2378
2209
  }
2210
+ const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2211
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2212
+ this.body = buildResponseEnvelope({
2213
+ payload: data,
2214
+ meta: configuredMeta,
2215
+ metaKey,
2216
+ wrap,
2217
+ rootKey,
2218
+ factory,
2219
+ context: {
2220
+ type: "collection",
2221
+ resource: this.resource
2222
+ }
2223
+ });
2224
+ this.body = appendRootProperties(this.body, {
2225
+ ...paginationExtras,
2226
+ ...customMeta || {}
2227
+ }, rootKey);
2228
+ this.body = this.applySerializePlugins(this.body);
2379
2229
  }
2380
2230
  return this;
2381
2231
  }
@@ -2646,54 +2496,6 @@ var Resource = class Resource extends BaseSerializer {
2646
2496
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2647
2497
  return factory || !wrap ? void 0 : rootKey;
2648
2498
  }
2649
- serializeResource(resource) {
2650
- let data = normalizeSerializableData(resource);
2651
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2652
- data = sanitizeConditionalAttributes(data);
2653
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2654
- if (caseStyle) {
2655
- const transformer = getCaseTransformer(caseStyle);
2656
- data = transformKeys(data, transformer);
2657
- }
2658
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2659
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2660
- this.body = buildResponseEnvelope({
2661
- payload: data,
2662
- wrap,
2663
- rootKey,
2664
- factory,
2665
- context: {
2666
- type: "resource",
2667
- resource: this.resource
2668
- }
2669
- });
2670
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2671
- this.body = this.applySerializePlugins(this.body);
2672
- }
2673
- async serializeResourceAsync(resource) {
2674
- let data = await normalizeSerializableDataAsync(resource);
2675
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2676
- data = sanitizeConditionalAttributes(data);
2677
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2678
- if (caseStyle) {
2679
- const transformer = getCaseTransformer(caseStyle);
2680
- data = transformKeys(data, transformer);
2681
- }
2682
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2683
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2684
- this.body = buildResponseEnvelope({
2685
- payload: data,
2686
- wrap,
2687
- rootKey,
2688
- factory,
2689
- context: {
2690
- type: "resource",
2691
- resource: this.resource
2692
- }
2693
- });
2694
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2695
- this.body = this.applySerializePlugins(this.body);
2696
- }
2697
2499
  /**
2698
2500
  * Convert resource to JSON response format
2699
2501
  *
@@ -2703,11 +2505,28 @@ var Resource = class Resource extends BaseSerializer {
2703
2505
  if (!this.called.json) {
2704
2506
  this.called.json = true;
2705
2507
  const ctx = this.resolveSerializationContext();
2706
- const resource = this.data(ctx);
2707
- if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
2708
- return this.serializeResourceAsync(resolved);
2508
+ let data = normalizeSerializableData(this.data(ctx));
2509
+ if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2510
+ data = sanitizeConditionalAttributes(data);
2511
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2512
+ if (caseStyle) {
2513
+ const transformer = getCaseTransformer(caseStyle);
2514
+ data = transformKeys(data, transformer);
2515
+ }
2516
+ const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2517
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2518
+ this.body = buildResponseEnvelope({
2519
+ payload: data,
2520
+ wrap,
2521
+ rootKey,
2522
+ factory,
2523
+ context: {
2524
+ type: "resource",
2525
+ resource: this.resource
2526
+ }
2709
2527
  });
2710
- else this.serializeResource(resource);
2528
+ this.body = appendRootProperties(this.body, customMeta, rootKey);
2529
+ this.body = this.applySerializePlugins(this.body);
2711
2530
  }
2712
2531
  return this;
2713
2532
  }
@@ -2921,7 +2740,6 @@ exports.isResoraCollectionLike = isResoraCollectionLike;
2921
2740
  exports.loadRuntimeConfig = loadRuntimeConfig;
2922
2741
  exports.mergeMetadata = mergeMetadata;
2923
2742
  exports.normalizeSerializableData = normalizeSerializableData;
2924
- exports.normalizeSerializableDataAsync = normalizeSerializableDataAsync;
2925
2743
  exports.registerPlugin = registerPlugin;
2926
2744
  exports.registerUtility = registerUtility;
2927
2745
  exports.resetPluginsForTests = resetPluginsForTests;
package/dist/index.d.cts CHANGED
@@ -519,7 +519,6 @@ declare abstract class BaseSerializer<TResource = any> {
519
519
  protected static ctx?: Response | H3Event | Record<string, any>;
520
520
  protected instanceConfig?: ResourceLevelConfig;
521
521
  protected additionalMeta?: MetaData;
522
- protected serializationPromise?: Promise<void>;
523
522
  protected called: {
524
523
  json?: boolean;
525
524
  data?: boolean;
@@ -606,8 +605,6 @@ declare abstract class BaseSerializer<TResource = any> {
606
605
  * Resolve the active request context for data transformation hooks.
607
606
  */
608
607
  protected resolveSerializationContext(): unknown;
609
- protected isPromiseLike<T = any>(value: unknown): value is PromiseLike<T>;
610
- protected waitForSerialization(): Promise<void>;
611
608
  /**
612
609
  * Dispatch a body to a raw response object when it exposes a send() transport method.
613
610
  *
@@ -749,7 +746,7 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
749
746
  /**
750
747
  * Get the original resource data
751
748
  */
752
- data(_ctx?: any): any;
749
+ data(_ctx?: unknown): (R extends Collectible ? R["data"][number] : R extends PaginatorLike<infer TPaginatorData> ? TPaginatorData : R extends CollectionLike<infer TCollectionData> ? TCollectionData : R extends ResourceData[] ? R[number] : never)[];
753
750
  /**
754
751
  * Get the current serialized output body.
755
752
  */
@@ -789,9 +786,6 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
789
786
  * @returns The key to use for the response payload, or undefined if no key is needed.
790
787
  */
791
788
  private getPayloadKey;
792
- private serializeCollectionData;
793
- private serializeCollectionDataAsync;
794
- private resolveCollectionDataForSerialization;
795
789
  /**
796
790
  * Convert resource to JSON response format
797
791
  *
@@ -889,7 +883,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
889
883
  /**
890
884
  * Get the original resource data
891
885
  */
892
- data(_ctx?: any): any;
886
+ data(_ctx?: unknown): R extends NonCollectible ? R["data"] : R;
893
887
  /**
894
888
  * Get the current serialized output body.
895
889
  */
@@ -909,8 +903,6 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
909
903
  protected getResourceForMeta(): R;
910
904
  protected getSerializerType(): "resource";
911
905
  private getPayloadKey;
912
- private serializeResource;
913
- private serializeResourceAsync;
914
906
  /**
915
907
  * Convert resource to JSON response format
916
908
  *
@@ -1000,7 +992,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1000
992
  /**
1001
993
  * Get the original resource data
1002
994
  */
1003
- data(_ctx?: any): any;
995
+ data(_ctx?: unknown): R;
1004
996
  /**
1005
997
  * Get the current serialized output body.
1006
998
  */
@@ -1032,8 +1024,6 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1032
1024
  protected getResourceForMeta(): R;
1033
1025
  protected getSerializerType(): "generic";
1034
1026
  private getPayloadKey;
1035
- private serializeGenericResource;
1036
- private serializeGenericResourceAsync;
1037
1027
  /**
1038
1028
  * Convert resource to JSON response format
1039
1029
  *
@@ -1225,7 +1215,7 @@ declare const defineConfig: (config: ResoraConfig) => Config;
1225
1215
  //#endregion
1226
1216
  //#region src/utilities/arkorm.d.ts
1227
1217
  type ArkormLikeModel = {
1228
- toObject: () => Record<string, any> | PromiseLike<Record<string, any>>;
1218
+ toObject: () => Record<string, any>;
1229
1219
  getRawAttributes?: () => Record<string, any>;
1230
1220
  getAttribute?: (key: string) => unknown;
1231
1221
  setAttribute?: (key: string, value: unknown) => unknown;
@@ -1240,10 +1230,9 @@ type ResoraCollectionLike = {
1240
1230
  setCollects: (...args: unknown[]) => unknown;
1241
1231
  };
1242
1232
  /**
1243
- * Type guard to check if a value is an Arkorm-like model.
1244
- *
1245
- * Arkorm models expose `toObject()`. Some production model variants/proxies do
1246
- * not expose `getRawAttributes()`, so the serializer should not require it.
1233
+ * Type guard to check if a value is an Arkorm-like model, which is defined as an object
1234
+ * that has a toObject method and optionally getRawAttributes, getAttribute, and
1235
+ * setAttribute methods.
1247
1236
  *
1248
1237
  * @param value The value to check
1249
1238
  * @returns True if the value is an Arkorm-like model, false otherwise
@@ -1271,14 +1260,6 @@ declare const isResoraCollectionLike: (value: unknown) => value is ResoraCollect
1271
1260
  * @returns The normalized value, ready for serialization
1272
1261
  */
1273
1262
  declare const normalizeSerializableData: (value: unknown) => unknown;
1274
- /**
1275
- * Async variant of normalizeSerializableData. It resolves promise-like values at
1276
- * every nesting level before converting Arkorm-like models and collections.
1277
- *
1278
- * @param value The value to normalize
1279
- * @returns The normalized value, ready for serialization
1280
- */
1281
- declare const normalizeSerializableDataAsync: (value: unknown) => Promise<unknown>;
1282
1263
  //#endregion
1283
1264
  //#region src/utilities/metadata.d.ts
1284
1265
  /**
@@ -1612,4 +1593,4 @@ declare const extractResponseFromCtx: (ctx: unknown) => any | undefined;
1612
1593
  */
1613
1594
  declare const setCtx: (ctx: unknown) => void;
1614
1595
  //#endregion
1615
- export { ApiResource, CONDITIONAL_ATTRIBUTE_MISSING, CaseStyle, CliApp, Collectible, CollectionBody, CollectionLike, Config, Cursor, GenericBody, GenericResource, InitCommand, MakeResource, MetaData, NonCollectible, PaginatedMetaData, Pagination, PaginatorLike, ResoraConfig, ResoraPlugin, ResoraPluginApi, ResoraPluginUtility, Resource, ResourceBody, ResourceCollection, ResourceData, ResourceDef, ResourceLevelConfig, ResponseData, ResponseDataCollection, ResponseFactory, ResponseFactoryContext, ResponseKind, ResponsePluginEvent, ResponseStructureConfig, SendPluginEvent, SerializePluginEvent, ServerResponse, appendRootProperties, applyRuntimeConfig, buildPaginationExtras, buildResponseEnvelope, createArkormCurrentPageResolver, defineConfig, definePlugin, extractRequestUrl, extractResponseFromCtx, getCaseTransformer, getCtx, getDefaultConfig, getGlobalBaseUrl, getGlobalCase, getGlobalCursorMeta, getGlobalPageName, getGlobalPaginatedExtras, getGlobalPaginatedLinks, getGlobalPaginatedMeta, getGlobalResponseFactory, getGlobalResponseRootKey, getGlobalResponseStructure, getGlobalResponseWrap, getPaginationExtraKeys, getRegisteredPlugins, getRequestUrl, getUtility, hasPaginationLink, isArkormLikeCollection, isArkormLikeModel, isPlainObject, isResoraCollectionLike, loadRuntimeConfig, mergeMetadata, normalizeSerializableData, normalizeSerializableDataAsync, registerPlugin, registerUtility, resetPluginsForTests, resetRuntimeConfigForTests, resolveCurrentPage, resolveMergeWhen, resolveWhen, resolveWhenNotNull, resolveWithHookMetadata, runPluginHook, runWithCtx, sanitizeConditionalAttributes, setCtx, setGlobalBaseUrl, setGlobalCase, setGlobalCursorMeta, setGlobalPageName, setGlobalPaginatedExtras, setGlobalPaginatedLinks, setGlobalPaginatedMeta, setGlobalResponseFactory, setGlobalResponseRootKey, setGlobalResponseStructure, setGlobalResponseWrap, setRequestUrl, splitWords, toCamelCase, toKebabCase, toPascalCase, toSnakeCase, transformKeys };
1596
+ export { ApiResource, CONDITIONAL_ATTRIBUTE_MISSING, CaseStyle, CliApp, Collectible, CollectionBody, CollectionLike, Config, Cursor, GenericBody, GenericResource, InitCommand, MakeResource, MetaData, NonCollectible, PaginatedMetaData, Pagination, PaginatorLike, ResoraConfig, ResoraPlugin, ResoraPluginApi, ResoraPluginUtility, Resource, ResourceBody, ResourceCollection, ResourceData, ResourceDef, ResourceLevelConfig, ResponseData, ResponseDataCollection, ResponseFactory, ResponseFactoryContext, ResponseKind, ResponsePluginEvent, ResponseStructureConfig, SendPluginEvent, SerializePluginEvent, ServerResponse, appendRootProperties, applyRuntimeConfig, buildPaginationExtras, buildResponseEnvelope, createArkormCurrentPageResolver, defineConfig, definePlugin, extractRequestUrl, extractResponseFromCtx, getCaseTransformer, getCtx, getDefaultConfig, getGlobalBaseUrl, getGlobalCase, getGlobalCursorMeta, getGlobalPageName, getGlobalPaginatedExtras, getGlobalPaginatedLinks, getGlobalPaginatedMeta, getGlobalResponseFactory, getGlobalResponseRootKey, getGlobalResponseStructure, getGlobalResponseWrap, getPaginationExtraKeys, getRegisteredPlugins, getRequestUrl, getUtility, hasPaginationLink, isArkormLikeCollection, isArkormLikeModel, isPlainObject, isResoraCollectionLike, loadRuntimeConfig, mergeMetadata, normalizeSerializableData, registerPlugin, registerUtility, resetPluginsForTests, resetRuntimeConfigForTests, resolveCurrentPage, resolveMergeWhen, resolveWhen, resolveWhenNotNull, resolveWithHookMetadata, runPluginHook, runWithCtx, sanitizeConditionalAttributes, setCtx, setGlobalBaseUrl, setGlobalCase, setGlobalCursorMeta, setGlobalPageName, setGlobalPaginatedExtras, setGlobalPaginatedLinks, setGlobalPaginatedMeta, setGlobalResponseFactory, setGlobalResponseRootKey, setGlobalResponseStructure, setGlobalResponseWrap, setRequestUrl, splitWords, toCamelCase, toKebabCase, toPascalCase, toSnakeCase, transformKeys };
package/dist/index.d.mts CHANGED
@@ -519,7 +519,6 @@ declare abstract class BaseSerializer<TResource = any> {
519
519
  protected static ctx?: Response | H3Event | Record<string, any>;
520
520
  protected instanceConfig?: ResourceLevelConfig;
521
521
  protected additionalMeta?: MetaData;
522
- protected serializationPromise?: Promise<void>;
523
522
  protected called: {
524
523
  json?: boolean;
525
524
  data?: boolean;
@@ -606,8 +605,6 @@ declare abstract class BaseSerializer<TResource = any> {
606
605
  * Resolve the active request context for data transformation hooks.
607
606
  */
608
607
  protected resolveSerializationContext(): unknown;
609
- protected isPromiseLike<T = any>(value: unknown): value is PromiseLike<T>;
610
- protected waitForSerialization(): Promise<void>;
611
608
  /**
612
609
  * Dispatch a body to a raw response object when it exposes a send() transport method.
613
610
  *
@@ -749,7 +746,7 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
749
746
  /**
750
747
  * Get the original resource data
751
748
  */
752
- data(_ctx?: any): any;
749
+ data(_ctx?: unknown): (R extends Collectible ? R["data"][number] : R extends PaginatorLike<infer TPaginatorData> ? TPaginatorData : R extends CollectionLike<infer TCollectionData> ? TCollectionData : R extends ResourceData[] ? R[number] : never)[];
753
750
  /**
754
751
  * Get the current serialized output body.
755
752
  */
@@ -789,9 +786,6 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
789
786
  * @returns The key to use for the response payload, or undefined if no key is needed.
790
787
  */
791
788
  private getPayloadKey;
792
- private serializeCollectionData;
793
- private serializeCollectionDataAsync;
794
- private resolveCollectionDataForSerialization;
795
789
  /**
796
790
  * Convert resource to JSON response format
797
791
  *
@@ -889,7 +883,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
889
883
  /**
890
884
  * Get the original resource data
891
885
  */
892
- data(_ctx?: any): any;
886
+ data(_ctx?: unknown): R extends NonCollectible ? R["data"] : R;
893
887
  /**
894
888
  * Get the current serialized output body.
895
889
  */
@@ -909,8 +903,6 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
909
903
  protected getResourceForMeta(): R;
910
904
  protected getSerializerType(): "resource";
911
905
  private getPayloadKey;
912
- private serializeResource;
913
- private serializeResourceAsync;
914
906
  /**
915
907
  * Convert resource to JSON response format
916
908
  *
@@ -1000,7 +992,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1000
992
  /**
1001
993
  * Get the original resource data
1002
994
  */
1003
- data(_ctx?: any): any;
995
+ data(_ctx?: unknown): R;
1004
996
  /**
1005
997
  * Get the current serialized output body.
1006
998
  */
@@ -1032,8 +1024,6 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1032
1024
  protected getResourceForMeta(): R;
1033
1025
  protected getSerializerType(): "generic";
1034
1026
  private getPayloadKey;
1035
- private serializeGenericResource;
1036
- private serializeGenericResourceAsync;
1037
1027
  /**
1038
1028
  * Convert resource to JSON response format
1039
1029
  *
@@ -1225,7 +1215,7 @@ declare const defineConfig: (config: ResoraConfig) => Config;
1225
1215
  //#endregion
1226
1216
  //#region src/utilities/arkorm.d.ts
1227
1217
  type ArkormLikeModel = {
1228
- toObject: () => Record<string, any> | PromiseLike<Record<string, any>>;
1218
+ toObject: () => Record<string, any>;
1229
1219
  getRawAttributes?: () => Record<string, any>;
1230
1220
  getAttribute?: (key: string) => unknown;
1231
1221
  setAttribute?: (key: string, value: unknown) => unknown;
@@ -1240,10 +1230,9 @@ type ResoraCollectionLike = {
1240
1230
  setCollects: (...args: unknown[]) => unknown;
1241
1231
  };
1242
1232
  /**
1243
- * Type guard to check if a value is an Arkorm-like model.
1244
- *
1245
- * Arkorm models expose `toObject()`. Some production model variants/proxies do
1246
- * not expose `getRawAttributes()`, so the serializer should not require it.
1233
+ * Type guard to check if a value is an Arkorm-like model, which is defined as an object
1234
+ * that has a toObject method and optionally getRawAttributes, getAttribute, and
1235
+ * setAttribute methods.
1247
1236
  *
1248
1237
  * @param value The value to check
1249
1238
  * @returns True if the value is an Arkorm-like model, false otherwise
@@ -1271,14 +1260,6 @@ declare const isResoraCollectionLike: (value: unknown) => value is ResoraCollect
1271
1260
  * @returns The normalized value, ready for serialization
1272
1261
  */
1273
1262
  declare const normalizeSerializableData: (value: unknown) => unknown;
1274
- /**
1275
- * Async variant of normalizeSerializableData. It resolves promise-like values at
1276
- * every nesting level before converting Arkorm-like models and collections.
1277
- *
1278
- * @param value The value to normalize
1279
- * @returns The normalized value, ready for serialization
1280
- */
1281
- declare const normalizeSerializableDataAsync: (value: unknown) => Promise<unknown>;
1282
1263
  //#endregion
1283
1264
  //#region src/utilities/metadata.d.ts
1284
1265
  /**
@@ -1612,4 +1593,4 @@ declare const extractResponseFromCtx: (ctx: unknown) => any | undefined;
1612
1593
  */
1613
1594
  declare const setCtx: (ctx: unknown) => void;
1614
1595
  //#endregion
1615
- export { ApiResource, CONDITIONAL_ATTRIBUTE_MISSING, CaseStyle, CliApp, Collectible, CollectionBody, CollectionLike, Config, Cursor, GenericBody, GenericResource, InitCommand, MakeResource, MetaData, NonCollectible, PaginatedMetaData, Pagination, PaginatorLike, ResoraConfig, ResoraPlugin, ResoraPluginApi, ResoraPluginUtility, Resource, ResourceBody, ResourceCollection, ResourceData, ResourceDef, ResourceLevelConfig, ResponseData, ResponseDataCollection, ResponseFactory, ResponseFactoryContext, ResponseKind, ResponsePluginEvent, ResponseStructureConfig, SendPluginEvent, SerializePluginEvent, ServerResponse, appendRootProperties, applyRuntimeConfig, buildPaginationExtras, buildResponseEnvelope, createArkormCurrentPageResolver, defineConfig, definePlugin, extractRequestUrl, extractResponseFromCtx, getCaseTransformer, getCtx, getDefaultConfig, getGlobalBaseUrl, getGlobalCase, getGlobalCursorMeta, getGlobalPageName, getGlobalPaginatedExtras, getGlobalPaginatedLinks, getGlobalPaginatedMeta, getGlobalResponseFactory, getGlobalResponseRootKey, getGlobalResponseStructure, getGlobalResponseWrap, getPaginationExtraKeys, getRegisteredPlugins, getRequestUrl, getUtility, hasPaginationLink, isArkormLikeCollection, isArkormLikeModel, isPlainObject, isResoraCollectionLike, loadRuntimeConfig, mergeMetadata, normalizeSerializableData, normalizeSerializableDataAsync, registerPlugin, registerUtility, resetPluginsForTests, resetRuntimeConfigForTests, resolveCurrentPage, resolveMergeWhen, resolveWhen, resolveWhenNotNull, resolveWithHookMetadata, runPluginHook, runWithCtx, sanitizeConditionalAttributes, setCtx, setGlobalBaseUrl, setGlobalCase, setGlobalCursorMeta, setGlobalPageName, setGlobalPaginatedExtras, setGlobalPaginatedLinks, setGlobalPaginatedMeta, setGlobalResponseFactory, setGlobalResponseRootKey, setGlobalResponseStructure, setGlobalResponseWrap, setRequestUrl, splitWords, toCamelCase, toKebabCase, toPascalCase, toSnakeCase, transformKeys };
1596
+ export { ApiResource, CONDITIONAL_ATTRIBUTE_MISSING, CaseStyle, CliApp, Collectible, CollectionBody, CollectionLike, Config, Cursor, GenericBody, GenericResource, InitCommand, MakeResource, MetaData, NonCollectible, PaginatedMetaData, Pagination, PaginatorLike, ResoraConfig, ResoraPlugin, ResoraPluginApi, ResoraPluginUtility, Resource, ResourceBody, ResourceCollection, ResourceData, ResourceDef, ResourceLevelConfig, ResponseData, ResponseDataCollection, ResponseFactory, ResponseFactoryContext, ResponseKind, ResponsePluginEvent, ResponseStructureConfig, SendPluginEvent, SerializePluginEvent, ServerResponse, appendRootProperties, applyRuntimeConfig, buildPaginationExtras, buildResponseEnvelope, createArkormCurrentPageResolver, defineConfig, definePlugin, extractRequestUrl, extractResponseFromCtx, getCaseTransformer, getCtx, getDefaultConfig, getGlobalBaseUrl, getGlobalCase, getGlobalCursorMeta, getGlobalPageName, getGlobalPaginatedExtras, getGlobalPaginatedLinks, getGlobalPaginatedMeta, getGlobalResponseFactory, getGlobalResponseRootKey, getGlobalResponseStructure, getGlobalResponseWrap, getPaginationExtraKeys, getRegisteredPlugins, getRequestUrl, getUtility, hasPaginationLink, isArkormLikeCollection, isArkormLikeModel, isPlainObject, isResoraCollectionLike, loadRuntimeConfig, mergeMetadata, normalizeSerializableData, registerPlugin, registerUtility, resetPluginsForTests, resetRuntimeConfigForTests, resolveCurrentPage, resolveMergeWhen, resolveWhen, resolveWhenNotNull, resolveWithHookMetadata, runPluginHook, runWithCtx, sanitizeConditionalAttributes, setCtx, setGlobalBaseUrl, setGlobalCase, setGlobalCursorMeta, setGlobalPageName, setGlobalPaginatedExtras, setGlobalPaginatedLinks, setGlobalPaginatedMeta, setGlobalResponseFactory, setGlobalResponseRootKey, setGlobalResponseStructure, setGlobalResponseWrap, setRequestUrl, splitWords, toCamelCase, toKebabCase, toPascalCase, toSnakeCase, transformKeys };
package/dist/index.mjs CHANGED
@@ -407,17 +407,17 @@ const mergeMetadata = (base, incoming) => {
407
407
  //#endregion
408
408
  //#region src/utilities/arkorm.ts
409
409
  /**
410
- * Type guard to check if a value is an Arkorm-like model.
411
- *
412
- * Arkorm models expose `toObject()`. Some production model variants/proxies do
413
- * not expose `getRawAttributes()`, so the serializer should not require it.
410
+ * Type guard to check if a value is an Arkorm-like model, which is defined as an object
411
+ * that has a toObject method and optionally getRawAttributes, getAttribute, and
412
+ * setAttribute methods.
414
413
  *
415
414
  * @param value The value to check
416
415
  * @returns True if the value is an Arkorm-like model, false otherwise
417
416
  */
418
417
  const isArkormLikeModel = (value) => {
419
418
  if (!value || typeof value !== "object") return false;
420
- return typeof value.toObject === "function";
419
+ const candidate = value;
420
+ return typeof candidate.toObject === "function" && typeof candidate.getRawAttributes === "function";
421
421
  };
422
422
  /**
423
423
  * Type guard to check if a value is an Arkorm-like collection, which is defined as an object
@@ -462,30 +462,6 @@ const normalizeSerializableData = (value) => {
462
462
  }, {});
463
463
  return value;
464
464
  };
465
- const isPromiseLike = (value) => {
466
- return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
467
- };
468
- /**
469
- * Async variant of normalizeSerializableData. It resolves promise-like values at
470
- * every nesting level before converting Arkorm-like models and collections.
471
- *
472
- * @param value The value to normalize
473
- * @returns The normalized value, ready for serialization
474
- */
475
- const normalizeSerializableDataAsync = async (value) => {
476
- const resolvedValue = isPromiseLike(value) ? await value : value;
477
- if (Array.isArray(resolvedValue)) return Promise.all(resolvedValue.map((item) => normalizeSerializableDataAsync(item)));
478
- if (isResoraCollectionLike(resolvedValue)) return normalizeSerializableDataAsync(resolvedValue.toObject());
479
- if (isArkormLikeModel(resolvedValue)) return normalizeSerializableDataAsync(resolvedValue.toObject());
480
- if (isArkormLikeCollection(resolvedValue)) return normalizeSerializableDataAsync(resolvedValue.all());
481
- if (isPlainObject(resolvedValue)) return (await Promise.all(Object.entries(resolvedValue).map(async ([key, nestedValue]) => {
482
- return [key, await normalizeSerializableDataAsync(nestedValue)];
483
- }))).reduce((accumulator, [key, nestedValue]) => {
484
- accumulator[key] = nestedValue;
485
- return accumulator;
486
- }, {});
487
- return resolvedValue;
488
- };
489
465
 
490
466
  //#endregion
491
467
  //#region src/utilities/pagination.ts
@@ -1461,7 +1437,6 @@ var BaseSerializer = class {
1461
1437
  static ctx;
1462
1438
  instanceConfig;
1463
1439
  additionalMeta;
1464
- serializationPromise;
1465
1440
  called = {};
1466
1441
  constructor() {
1467
1442
  loadRuntimeConfig();
@@ -1562,12 +1537,6 @@ var BaseSerializer = class {
1562
1537
  resolveSerializationContext() {
1563
1538
  return getCtx() ?? this.constructor.ctx;
1564
1539
  }
1565
- isPromiseLike(value) {
1566
- return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
1567
- }
1568
- waitForSerialization() {
1569
- return this.serializationPromise ?? Promise.resolve();
1570
- }
1571
1540
  /**
1572
1541
  * Dispatch a body to a raw response object when it exposes a send() transport method.
1573
1542
  *
@@ -1643,28 +1612,27 @@ var BaseSerializer = class {
1643
1612
  runThen(input) {
1644
1613
  this.called.then = true;
1645
1614
  input.ensureJson();
1646
- return this.waitForSerialization().then(() => {
1647
- const initialBody = input.body();
1648
- let response;
1649
- if (typeof input.rawResponse !== "undefined") {
1650
- response = input.createServerResponse(input.rawResponse, initialBody);
1651
- this.called.withResponse = true;
1652
- input.callWithResponse(response, input.rawResponse);
1653
- } else {
1654
- this.called.withResponse = true;
1655
- input.callWithResponse();
1656
- }
1657
- const resolvedBody = input.body();
1658
- if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1659
- const dispatchedBody = this.applyResponsePlugins({
1660
- body: resolvedBody,
1661
- rawResponse: input.rawResponse,
1662
- response
1663
- });
1664
- if (typeof response?.send === "function") response.send(dispatchedBody);
1665
- else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1666
- return dispatchedBody;
1667
- }).then(input.onfulfilled, input.onrejected);
1615
+ const initialBody = input.body();
1616
+ let response;
1617
+ if (typeof input.rawResponse !== "undefined") {
1618
+ response = input.createServerResponse(input.rawResponse, initialBody);
1619
+ this.called.withResponse = true;
1620
+ input.callWithResponse(response, input.rawResponse);
1621
+ } else {
1622
+ this.called.withResponse = true;
1623
+ input.callWithResponse();
1624
+ }
1625
+ const resolvedBody = input.body();
1626
+ if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1627
+ const dispatchedBody = this.applyResponsePlugins({
1628
+ body: resolvedBody,
1629
+ rawResponse: input.rawResponse,
1630
+ response
1631
+ });
1632
+ const resolved = Promise.resolve(dispatchedBody).then(input.onfulfilled, input.onrejected);
1633
+ if (typeof response?.send === "function") response.send(dispatchedBody);
1634
+ else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1635
+ return resolved;
1668
1636
  }
1669
1637
  /**
1670
1638
  * Get or set the resource-level configuration for this serializer instance.
@@ -1854,52 +1822,17 @@ var GenericResource = class GenericResource extends BaseSerializer {
1854
1822
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
1855
1823
  return factory || !wrap ? void 0 : rootKey;
1856
1824
  }
1857
- serializeGenericResource(resource, ctx) {
1858
- let data = normalizeSerializableData(resource);
1859
- const serialize = (resolvedData) => {
1860
- data = resolvedData;
1861
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1862
- data = sanitizeConditionalAttributes(data);
1863
- const paginationExtras = buildPaginationExtras(this.resource);
1864
- const { metaKey } = getPaginationExtraKeys();
1865
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
1866
- if (metaKey) delete paginationExtras[metaKey];
1867
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
1868
- if (caseStyle) {
1869
- const transformer = getCaseTransformer(caseStyle);
1870
- data = transformKeys(data, transformer);
1871
- }
1872
- const customMeta = this.resolveMergedMeta(GenericResource.prototype.with);
1873
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
1874
- this.body = buildResponseEnvelope({
1875
- payload: data,
1876
- meta: configuredMeta,
1877
- metaKey,
1878
- wrap,
1879
- rootKey,
1880
- factory,
1881
- context: {
1882
- type: "generic",
1883
- resource: this.resource
1884
- }
1885
- });
1886
- this.body = appendRootProperties(this.body, {
1887
- ...paginationExtras,
1888
- ...customMeta || {}
1889
- }, rootKey);
1890
- this.body = this.applySerializePlugins(this.body);
1891
- };
1892
- if (Array.isArray(data) && this.collects) {
1893
- const collected = data.map((item) => new this.collects(item).data(ctx));
1894
- if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected).then(serialize);
1895
- data = collected;
1896
- }
1897
- serialize(data);
1898
- }
1899
- async serializeGenericResourceAsync(resource, ctx) {
1900
- let data = await normalizeSerializableDataAsync(resource);
1901
- const serialize = (resolvedData) => {
1902
- data = resolvedData;
1825
+ /**
1826
+ * Convert resource to JSON response format
1827
+ *
1828
+ * @returns
1829
+ */
1830
+ json() {
1831
+ if (!this.called.json) {
1832
+ this.called.json = true;
1833
+ const ctx = this.resolveSerializationContext();
1834
+ let data = normalizeSerializableData(this.data(ctx));
1835
+ if (Array.isArray(data) && this.collects) data = data.map((item) => new this.collects(item).data(ctx));
1903
1836
  if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1904
1837
  data = sanitizeConditionalAttributes(data);
1905
1838
  const paginationExtras = buildPaginationExtras(this.resource);
@@ -1930,31 +1863,6 @@ var GenericResource = class GenericResource extends BaseSerializer {
1930
1863
  ...customMeta || {}
1931
1864
  }, rootKey);
1932
1865
  this.body = this.applySerializePlugins(this.body);
1933
- };
1934
- if (Array.isArray(data) && this.collects) {
1935
- const collected = data.map((item) => new this.collects(item).data(ctx));
1936
- data = await Promise.all(collected);
1937
- data = await normalizeSerializableDataAsync(data);
1938
- }
1939
- serialize(data);
1940
- }
1941
- /**
1942
- * Convert resource to JSON response format
1943
- *
1944
- * @returns
1945
- */
1946
- json() {
1947
- if (!this.called.json) {
1948
- this.called.json = true;
1949
- const ctx = this.resolveSerializationContext();
1950
- const resource = this.data(ctx);
1951
- if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
1952
- return this.serializeGenericResourceAsync(resolved, ctx);
1953
- });
1954
- else {
1955
- const result = this.serializeGenericResource(resource, ctx);
1956
- if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
1957
- }
1958
1866
  }
1959
1867
  return this;
1960
1868
  }
@@ -2248,78 +2156,6 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2248
2156
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2249
2157
  return factory || !wrap ? void 0 : rootKey;
2250
2158
  }
2251
- serializeCollectionData(items) {
2252
- let data = normalizeSerializableData(items);
2253
- data = sanitizeConditionalAttributes(data);
2254
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2255
- const { metaKey } = getPaginationExtraKeys();
2256
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2257
- if (metaKey) delete paginationExtras[metaKey];
2258
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2259
- if (caseStyle) {
2260
- const transformer = getCaseTransformer(caseStyle);
2261
- data = transformKeys(data, transformer);
2262
- }
2263
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2264
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2265
- this.body = buildResponseEnvelope({
2266
- payload: data,
2267
- meta: configuredMeta,
2268
- metaKey,
2269
- wrap,
2270
- rootKey,
2271
- factory,
2272
- context: {
2273
- type: "collection",
2274
- resource: this.resource
2275
- }
2276
- });
2277
- this.body = appendRootProperties(this.body, {
2278
- ...paginationExtras,
2279
- ...customMeta || {}
2280
- }, rootKey);
2281
- this.body = this.applySerializePlugins(this.body);
2282
- }
2283
- async serializeCollectionDataAsync(items) {
2284
- let data = await normalizeSerializableDataAsync(items);
2285
- data = sanitizeConditionalAttributes(data);
2286
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2287
- const { metaKey } = getPaginationExtraKeys();
2288
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2289
- if (metaKey) delete paginationExtras[metaKey];
2290
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2291
- if (caseStyle) {
2292
- const transformer = getCaseTransformer(caseStyle);
2293
- data = transformKeys(data, transformer);
2294
- }
2295
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2296
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2297
- this.body = buildResponseEnvelope({
2298
- payload: data,
2299
- meta: configuredMeta,
2300
- metaKey,
2301
- wrap,
2302
- rootKey,
2303
- factory,
2304
- context: {
2305
- type: "collection",
2306
- resource: this.resource
2307
- }
2308
- });
2309
- this.body = appendRootProperties(this.body, {
2310
- ...paginationExtras,
2311
- ...customMeta || {}
2312
- }, rootKey);
2313
- this.body = this.applySerializePlugins(this.body);
2314
- }
2315
- resolveCollectionDataForSerialization(items, ctx) {
2316
- if (this.collects && this.data === ResourceCollection.prototype.data) {
2317
- const collected = items.map((item) => new this.collects(item).data(ctx));
2318
- if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected);
2319
- return collected;
2320
- }
2321
- return items;
2322
- }
2323
2159
  /**
2324
2160
  * Convert resource to JSON response format
2325
2161
  *
@@ -2329,24 +2165,38 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2329
2165
  if (!this.called.json) {
2330
2166
  this.called.json = true;
2331
2167
  const ctx = this.resolveSerializationContext();
2332
- const data = this.data(ctx);
2333
- const serialize = (items) => {
2334
- const resolvedData = this.resolveCollectionDataForSerialization(items, ctx);
2335
- if (this.isPromiseLike(resolvedData)) return resolvedData.then((resolved) => {
2336
- return this.serializeCollectionDataAsync(resolved);
2337
- });
2338
- this.serializeCollectionData(resolvedData);
2339
- };
2340
- if (this.isPromiseLike(data)) this.serializationPromise = Promise.resolve(data).then((items) => {
2341
- const resolvedData = this.resolveCollectionDataForSerialization(items, ctx);
2342
- return Promise.resolve(resolvedData).then((resolved) => {
2343
- return this.serializeCollectionDataAsync(resolved);
2344
- });
2345
- });
2346
- else {
2347
- const result = serialize(data);
2348
- if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
2168
+ let data = this.data(ctx);
2169
+ if (this.collects && this.data === ResourceCollection.prototype.data) data = data.map((item) => new this.collects(item).data(ctx));
2170
+ data = normalizeSerializableData(data);
2171
+ data = sanitizeConditionalAttributes(data);
2172
+ const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2173
+ const { metaKey } = getPaginationExtraKeys();
2174
+ const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2175
+ if (metaKey) delete paginationExtras[metaKey];
2176
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2177
+ if (caseStyle) {
2178
+ const transformer = getCaseTransformer(caseStyle);
2179
+ data = transformKeys(data, transformer);
2349
2180
  }
2181
+ const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2182
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2183
+ this.body = buildResponseEnvelope({
2184
+ payload: data,
2185
+ meta: configuredMeta,
2186
+ metaKey,
2187
+ wrap,
2188
+ rootKey,
2189
+ factory,
2190
+ context: {
2191
+ type: "collection",
2192
+ resource: this.resource
2193
+ }
2194
+ });
2195
+ this.body = appendRootProperties(this.body, {
2196
+ ...paginationExtras,
2197
+ ...customMeta || {}
2198
+ }, rootKey);
2199
+ this.body = this.applySerializePlugins(this.body);
2350
2200
  }
2351
2201
  return this;
2352
2202
  }
@@ -2617,54 +2467,6 @@ var Resource = class Resource extends BaseSerializer {
2617
2467
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2618
2468
  return factory || !wrap ? void 0 : rootKey;
2619
2469
  }
2620
- serializeResource(resource) {
2621
- let data = normalizeSerializableData(resource);
2622
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2623
- data = sanitizeConditionalAttributes(data);
2624
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2625
- if (caseStyle) {
2626
- const transformer = getCaseTransformer(caseStyle);
2627
- data = transformKeys(data, transformer);
2628
- }
2629
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2630
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2631
- this.body = buildResponseEnvelope({
2632
- payload: data,
2633
- wrap,
2634
- rootKey,
2635
- factory,
2636
- context: {
2637
- type: "resource",
2638
- resource: this.resource
2639
- }
2640
- });
2641
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2642
- this.body = this.applySerializePlugins(this.body);
2643
- }
2644
- async serializeResourceAsync(resource) {
2645
- let data = await normalizeSerializableDataAsync(resource);
2646
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2647
- data = sanitizeConditionalAttributes(data);
2648
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2649
- if (caseStyle) {
2650
- const transformer = getCaseTransformer(caseStyle);
2651
- data = transformKeys(data, transformer);
2652
- }
2653
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2654
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2655
- this.body = buildResponseEnvelope({
2656
- payload: data,
2657
- wrap,
2658
- rootKey,
2659
- factory,
2660
- context: {
2661
- type: "resource",
2662
- resource: this.resource
2663
- }
2664
- });
2665
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2666
- this.body = this.applySerializePlugins(this.body);
2667
- }
2668
2470
  /**
2669
2471
  * Convert resource to JSON response format
2670
2472
  *
@@ -2674,11 +2476,28 @@ var Resource = class Resource extends BaseSerializer {
2674
2476
  if (!this.called.json) {
2675
2477
  this.called.json = true;
2676
2478
  const ctx = this.resolveSerializationContext();
2677
- const resource = this.data(ctx);
2678
- if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
2679
- return this.serializeResourceAsync(resolved);
2479
+ let data = normalizeSerializableData(this.data(ctx));
2480
+ if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2481
+ data = sanitizeConditionalAttributes(data);
2482
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2483
+ if (caseStyle) {
2484
+ const transformer = getCaseTransformer(caseStyle);
2485
+ data = transformKeys(data, transformer);
2486
+ }
2487
+ const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2488
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2489
+ this.body = buildResponseEnvelope({
2490
+ payload: data,
2491
+ wrap,
2492
+ rootKey,
2493
+ factory,
2494
+ context: {
2495
+ type: "resource",
2496
+ resource: this.resource
2497
+ }
2680
2498
  });
2681
- else this.serializeResource(resource);
2499
+ this.body = appendRootProperties(this.body, customMeta, rootKey);
2500
+ this.body = this.applySerializePlugins(this.body);
2682
2501
  }
2683
2502
  return this;
2684
2503
  }
@@ -2848,4 +2667,4 @@ var Resource = class Resource extends BaseSerializer {
2848
2667
  };
2849
2668
 
2850
2669
  //#endregion
2851
- export { ApiResource, CONDITIONAL_ATTRIBUTE_MISSING, CliApp, GenericResource, InitCommand, MakeResource, Resource, ResourceCollection, ServerResponse, appendRootProperties, applyRuntimeConfig, buildPaginationExtras, buildResponseEnvelope, createArkormCurrentPageResolver, defineConfig, definePlugin, extractRequestUrl, extractResponseFromCtx, getCaseTransformer, getCtx, getDefaultConfig, getGlobalBaseUrl, getGlobalCase, getGlobalCursorMeta, getGlobalPageName, getGlobalPaginatedExtras, getGlobalPaginatedLinks, getGlobalPaginatedMeta, getGlobalResponseFactory, getGlobalResponseRootKey, getGlobalResponseStructure, getGlobalResponseWrap, getPaginationExtraKeys, getRegisteredPlugins, getRequestUrl, getUtility, hasPaginationLink, isArkormLikeCollection, isArkormLikeModel, isPlainObject, isResoraCollectionLike, loadRuntimeConfig, mergeMetadata, normalizeSerializableData, normalizeSerializableDataAsync, registerPlugin, registerUtility, resetPluginsForTests, resetRuntimeConfigForTests, resolveCurrentPage, resolveMergeWhen, resolveWhen, resolveWhenNotNull, resolveWithHookMetadata, runPluginHook, runWithCtx, sanitizeConditionalAttributes, setCtx, setGlobalBaseUrl, setGlobalCase, setGlobalCursorMeta, setGlobalPageName, setGlobalPaginatedExtras, setGlobalPaginatedLinks, setGlobalPaginatedMeta, setGlobalResponseFactory, setGlobalResponseRootKey, setGlobalResponseStructure, setGlobalResponseWrap, setRequestUrl, splitWords, toCamelCase, toKebabCase, toPascalCase, toSnakeCase, transformKeys };
2670
+ export { ApiResource, CONDITIONAL_ATTRIBUTE_MISSING, CliApp, GenericResource, InitCommand, MakeResource, Resource, ResourceCollection, ServerResponse, appendRootProperties, applyRuntimeConfig, buildPaginationExtras, buildResponseEnvelope, createArkormCurrentPageResolver, defineConfig, definePlugin, extractRequestUrl, extractResponseFromCtx, getCaseTransformer, getCtx, getDefaultConfig, getGlobalBaseUrl, getGlobalCase, getGlobalCursorMeta, getGlobalPageName, getGlobalPaginatedExtras, getGlobalPaginatedLinks, getGlobalPaginatedMeta, getGlobalResponseFactory, getGlobalResponseRootKey, getGlobalResponseStructure, getGlobalResponseWrap, getPaginationExtraKeys, getRegisteredPlugins, getRequestUrl, getUtility, hasPaginationLink, isArkormLikeCollection, isArkormLikeModel, isPlainObject, isResoraCollectionLike, loadRuntimeConfig, mergeMetadata, normalizeSerializableData, registerPlugin, registerUtility, resetPluginsForTests, resetRuntimeConfigForTests, resolveCurrentPage, resolveMergeWhen, resolveWhen, resolveWhenNotNull, resolveWithHookMetadata, runPluginHook, runWithCtx, sanitizeConditionalAttributes, setCtx, setGlobalBaseUrl, setGlobalCase, setGlobalCursorMeta, setGlobalPageName, setGlobalPaginatedExtras, setGlobalPaginatedLinks, setGlobalPaginatedMeta, setGlobalResponseFactory, setGlobalResponseRootKey, setGlobalResponseStructure, setGlobalResponseWrap, setRequestUrl, splitWords, toCamelCase, toKebabCase, toPascalCase, toSnakeCase, transformKeys };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resora",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "A structured API response layer for Node.js and TypeScript with automatic JSON responses, collection support, and pagination handling.",
5
5
  "keywords": [
6
6
  "api",