@websolutespa/bom-mixer-store 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -154,66 +154,6 @@ async function mockApiDelete(url, options = {}) {
154
154
  // src/store/store.handler.ts
155
155
  import { asEquatable, qsDeserialize } from "@websolutespa/bom-core";
156
156
 
157
- // src/store/store.ts
158
- var StoreStrategy = /* @__PURE__ */ ((StoreStrategy2) => {
159
- StoreStrategy2["Api"] = "api";
160
- StoreStrategy2["Data"] = "data";
161
- StoreStrategy2["Mock"] = "mock";
162
- return StoreStrategy2;
163
- })(StoreStrategy || {});
164
- function getStoreStrategy() {
165
- let storeStrategy2 = "mock" /* Mock */;
166
- if (process && process.env.STORE_STRATEGY) {
167
- storeStrategy2 = process.env.STORE_STRATEGY;
168
- }
169
- return storeStrategy2;
170
- }
171
- var storeStrategy = getStoreStrategy();
172
- var ENV_COLLECTIONS = process.env.COLLECTIONS ? process.env.COLLECTIONS.split(",") : [];
173
- var MOCK_COLLECTIONS = process.env.MOCKS ? process.env.MOCKS.split(",") : [];
174
- var STATIC_COLLECTIONS = [];
175
- var KNOWN_COLLECTIONS = [
176
- "category",
177
- "label",
178
- "locale",
179
- "market",
180
- "menu",
181
- "template",
182
- "page",
183
- "redirect",
184
- "route",
185
- ...STATIC_COLLECTIONS
186
- ];
187
- var COLLECTIONS = [...ENV_COLLECTIONS, ...KNOWN_COLLECTIONS];
188
-
189
- // src/mock/mock.store.ts
190
- import { isDevelopment } from "@websolutespa/bom-core";
191
-
192
- // src/fs/fs.service.ts
193
- import * as fs from "fs";
194
- async function fsRead(pathname, option) {
195
- try {
196
- const data = await fs.promises.readFile(pathname, option?.encoding || "utf8");
197
- return data || void 0;
198
- } catch (error) {
199
- console.log("fsRead.error", error, pathname);
200
- return;
201
- }
202
- }
203
- async function fsReadJson(pathname) {
204
- try {
205
- const data = await fsRead(pathname);
206
- if (data) {
207
- return JSON.parse(data);
208
- } else {
209
- return;
210
- }
211
- } catch (error) {
212
- console.log("fsReadJson.error", error, pathname);
213
- return;
214
- }
215
- }
216
-
217
157
  // src/static/static.ts
218
158
  var staticCollections = [{
219
159
  src: "https://actarian.github.io/cms-i18n-react/api/continent.json",
@@ -417,15 +357,177 @@ var staticCollections = [{
417
357
  ]
418
358
  }];
419
359
 
360
+ // src/store/store.ts
361
+ var StoreStrategy = /* @__PURE__ */ ((StoreStrategy2) => {
362
+ StoreStrategy2["Api"] = "api";
363
+ StoreStrategy2["Data"] = "data";
364
+ StoreStrategy2["Mock"] = "mock";
365
+ return StoreStrategy2;
366
+ })(StoreStrategy || {});
367
+ function getStoreStrategy() {
368
+ let storeStrategy2 = "mock" /* Mock */;
369
+ if (process && process.env.STORE_STRATEGY) {
370
+ storeStrategy2 = process.env.STORE_STRATEGY;
371
+ }
372
+ return storeStrategy2;
373
+ }
374
+ var storeStrategy = getStoreStrategy();
375
+ var ENV_COLLECTIONS = process.env.COLLECTIONS ? process.env.COLLECTIONS.split(",") : [];
376
+ var MOCK_COLLECTIONS = process.env.MOCKS ? process.env.MOCKS.split(",") : [];
377
+ var STATIC_COLLECTIONS = staticCollections.map((x) => x.slug);
378
+ var KNOWN_COLLECTIONS = [
379
+ "category",
380
+ "label",
381
+ "locale",
382
+ "market",
383
+ "menu",
384
+ "template",
385
+ "redirect",
386
+ "route",
387
+ ...STATIC_COLLECTIONS
388
+ ];
389
+ var COLLECTIONS = [...ENV_COLLECTIONS, ...KNOWN_COLLECTIONS];
390
+
391
+ // src/mock/mock.store.ts
392
+ import { isDevelopment } from "@websolutespa/bom-core";
393
+
394
+ // src/fs/fs.service.ts
395
+ import * as fs from "fs";
396
+ async function fsRead(pathname, option) {
397
+ try {
398
+ const data = await fs.promises.readFile(pathname, option?.encoding || "utf8");
399
+ return data || void 0;
400
+ } catch (error) {
401
+ console.log("fsRead.error", error, pathname);
402
+ return;
403
+ }
404
+ }
405
+ async function fsReadJson(pathname) {
406
+ try {
407
+ const data = await fsRead(pathname);
408
+ if (data) {
409
+ return JSON.parse(data);
410
+ } else {
411
+ return;
412
+ }
413
+ } catch (error) {
414
+ console.log("fsReadJson.error", error, pathname);
415
+ return;
416
+ }
417
+ }
418
+
420
419
  // src/static/static.service.ts
421
- import { JsonService, httpGet, localizeItem } from "@websolutespa/bom-core";
422
- var StaticService = class extends JsonService {
420
+ import { JsonService as JsonService2, httpGet } from "@websolutespa/bom-core";
421
+
422
+ // src/mock/mock.service.ts
423
+ import { cloneItem, isArray, isObject, isUnresolvedRelation, JsonService, localizeItem } from "@websolutespa/bom-core";
424
+ var MOCK_SERVICE_DEFAULT_DEPTH = 2;
425
+ var MockService = class extends JsonService {
426
+ constructor(items, store) {
427
+ super(items);
428
+ this.store = store;
429
+ }
430
+ async decorateOne_(item, params = {}) {
431
+ let decoratedItem = await localizeItem_(item, params);
432
+ decoratedItem = await decorateRelation_(this.store, decoratedItem, {
433
+ market: params.market,
434
+ locale: params.locale,
435
+ depth: params.depth != null ? params.depth : MOCK_SERVICE_DEFAULT_DEPTH
436
+ });
437
+ return decoratedItem;
438
+ }
439
+ async decorateMany_(items, params = {}) {
440
+ let decoratedItems = await localizeItems_(items, params);
441
+ decoratedItems = await decorateRelations_(this.store, decoratedItems, {
442
+ market: params.market,
443
+ locale: params.locale,
444
+ depth: params.depth != null ? params.depth : MOCK_SERVICE_DEFAULT_DEPTH
445
+ });
446
+ return decoratedItems;
447
+ }
448
+ };
449
+ async function localizeItem_(item, params = {}) {
450
+ if (params.locale) {
451
+ return localizeItem(item, params.locale);
452
+ } else {
453
+ return cloneItem(item);
454
+ }
455
+ }
456
+ async function localizeItems_(items, params = {}) {
457
+ const decoratedItems = [];
458
+ for (const item of items) {
459
+ const decoratedItem = params.locale ? localizeItem(item, params.locale) : cloneItem(item);
460
+ decoratedItems.push(decoratedItem);
461
+ }
462
+ return decoratedItems;
463
+ }
464
+ function collectRelations_(item, relations = []) {
465
+ if (isObject(item)) {
466
+ Object.entries(item).forEach(([key, value]) => {
467
+ if (key === "relation" && isUnresolvedRelation(value)) {
468
+ if (value.relationTo !== item.schema || value.value !== item.id) {
469
+ relations.push(value);
470
+ }
471
+ } else if (isArray(value)) {
472
+ value.forEach((x) => collectRelations_(x, relations));
473
+ } else if (isObject(value)) {
474
+ collectRelations_(value, relations);
475
+ }
476
+ });
477
+ }
478
+ return relations;
479
+ }
480
+ async function decorateRelation_(store, item, params = {}) {
481
+ const depth = params.depth != null ? params.depth : MOCK_SERVICE_DEFAULT_DEPTH;
482
+ if (depth === 0) {
483
+ return item;
484
+ }
485
+ const relations = collectRelations_(item);
486
+ for (const relation of relations) {
487
+ const isMany = Array.isArray(relation.value);
488
+ const items = await store[relation.relationTo].findMany({
489
+ ...params,
490
+ where: {
491
+ id: { in: isMany ? relation.value : [relation.value] }
492
+ },
493
+ depth: depth - 1
494
+ });
495
+ if (isMany) {
496
+ relation.value = items;
497
+ } else {
498
+ relation.value = items.length ? items[0] : void 0;
499
+ }
500
+ }
501
+ return item;
502
+ }
503
+ async function decorateRelations_(store, items, params = {}) {
504
+ for (const item of items) {
505
+ await decorateRelation_(store, item, params);
506
+ }
507
+ return items;
508
+ }
509
+
510
+ // src/static/static.service.ts
511
+ var StaticService = class extends JsonService2 {
423
512
  constructor(config, store) {
424
513
  super([]);
425
514
  this.loaded = false;
426
515
  this.config = config;
427
516
  this.store = store;
428
517
  }
518
+ mapItems_(items, map) {
519
+ if (typeof map === "object") {
520
+ items = items.map((x) => {
521
+ const item = {};
522
+ Object.entries(x).forEach(([k, v]) => {
523
+ const key = map[k] || k;
524
+ item[key] = v;
525
+ });
526
+ return item;
527
+ });
528
+ }
529
+ return items;
530
+ }
429
531
  async getItems() {
430
532
  let items = this.items;
431
533
  if (this.loaded && items) {
@@ -451,163 +553,121 @@ var StaticService = class extends JsonService {
451
553
  return items;
452
554
  }
453
555
  }
454
- async findOne(id, params = {}) {
455
- let items = await this.getItems();
456
- params.where = params.where || {};
457
- params.where.id = params.where.id || { equals: id };
458
- items = this.whereItems_(items, params.where);
459
- if (items.length > 0) {
460
- let item = items[0];
461
- if (params.depth !== 0) {
462
- item = await this.relatedItems_(item, this.config.fields);
463
- }
464
- return this.decorator_(item, params);
465
- } else {
466
- console.log("StaticService.findOne.notfound", id, params);
467
- return void 0;
468
- }
556
+ async decorateOne_(item, params = {}) {
557
+ let decoratedItem = await localizeItem_(item, params);
558
+ decoratedItem = await decorateStaticRelation_(this.store, this.config.fields, decoratedItem, {
559
+ market: params.market,
560
+ locale: params.locale,
561
+ depth: params.depth
562
+ });
563
+ return decoratedItem;
469
564
  }
470
- mapItems_(items, map) {
471
- if (typeof map === "object") {
472
- items = items.map((x) => {
473
- const item = {};
474
- Object.entries(x).forEach(([k, v]) => {
475
- const key = map[k] || k;
476
- item[key] = v;
477
- });
478
- return item;
479
- });
480
- }
481
- return items;
565
+ async decorateMany_(items, params = {}) {
566
+ let decoratedItems = await localizeItems_(items, params);
567
+ decoratedItems = await decorateStaticRelations_(this.store, this.config.fields, decoratedItems, {
568
+ market: params.market,
569
+ locale: params.locale,
570
+ depth: params.depth
571
+ });
572
+ return decoratedItems;
482
573
  }
483
- // !!! todo make recursive by depth with traverse
484
- async relatedItems_(item, fields, locale = "en") {
485
- const x = { ...item };
486
- for (const field of fields) {
487
- if (field.type === "relationship" && typeof field.relationTo === "string") {
488
- const name = field.name;
489
- const items = await this.store[field.relationTo].findMany();
490
- if (field.hasMany) {
491
- const ids = x[name];
492
- x[name] = items.filter((x2) => ids.indexOf(x2.id) !== -1);
493
- } else {
494
- const id = x[name];
495
- x[name] = items.find((x2) => x2.id === id) || id;
496
- }
574
+ };
575
+ async function decorateStaticRelation_(store, fields, item, params = {}) {
576
+ const depth = params.depth != null ? params.depth : MOCK_SERVICE_DEFAULT_DEPTH;
577
+ if (depth === 0) {
578
+ return item;
579
+ }
580
+ const decoratedItem = { ...item };
581
+ for (const field of fields) {
582
+ if (field.type === "relationship" && typeof field.relationTo === "string") {
583
+ const name = field.name;
584
+ const value = item[name];
585
+ const ids = field.hasMany ? value : [value];
586
+ const items = await store[field.relationTo].findMany({
587
+ where: {
588
+ id: { in: ids }
589
+ },
590
+ depth: depth - 1,
591
+ locale: params.locale
592
+ });
593
+ if (field.hasMany) {
594
+ decoratedItem[name] = items;
595
+ } else {
596
+ decoratedItem[name] = items.length ? items[0] : void 0;
497
597
  }
498
598
  }
499
- return x;
500
599
  }
501
- decorator_(item, params = {}) {
502
- if (params.locale) {
503
- item = localizeItem(item, params.locale);
504
- }
505
- return item;
600
+ return decoratedItem;
601
+ }
602
+ async function decorateStaticRelations_(store, fields, items, params = {}) {
603
+ const decoratedItems = [];
604
+ for (const item of items) {
605
+ const decoratedItem = await decorateStaticRelation_(store, fields, item, params);
606
+ decoratedItems.push(decoratedItem);
506
607
  }
507
- };
608
+ return decoratedItems;
609
+ }
508
610
 
509
611
  // src/mock/mock-menu.service.ts
510
- import {
511
- localizeItem as localizeItem3
512
- } from "@websolutespa/bom-core";
513
-
514
- // src/mock/mock.service.ts
515
- import { JsonService as JsonService2, localizeItem as localizeItem2 } from "@websolutespa/bom-core";
516
- var MockService = class extends JsonService2 {
517
- constructor(items, store) {
518
- super(items);
519
- this.store = store;
520
- }
521
- // !!! todo handle relations
612
+ var MAX_INT = 1e12;
613
+ var UID = 0;
614
+ var MockMenuService = class extends MockService {
522
615
  /*
523
- override async findOne<B extends T = T>(id: IEquatable, params: QueryParams = {}): Promise<B | undefined> {
524
- console.log('MockService.findOne', id, params);
616
+ async findOne<B extends T = T>(id: IEquatable, params: QueryParams = {}): Promise<B | undefined> {
617
+ // console.log('MockMenuService.findOne', id, params);
525
618
  let item = await super.findOne<B>(id, params);
526
- // relations
527
- if (item) {
528
- if (params.depth !== 0) {
529
- item = await this.relatedItems_(item);
530
- }
619
+ if (item && params.market && params.locale) {
620
+ item = await decorateMenu_(this.store, (item as any), {
621
+ market: params.market,
622
+ locale: params.locale,
623
+ }) as any;
531
624
  }
532
625
  return item;
533
626
  }
534
627
 
535
- override async findMany<B extends T = T>(params: QueryParams = {}): Promise<B[]> {
536
- // console.log('MockService.findMany', params);
628
+ async findMany<B extends T = T>(params: QueryParams = {}): Promise<B[]> {
629
+ // console.log('MockMenuService.findMany', params);
537
630
  let items = await super.findMany<B>(params);
538
- // relations
539
- if (params.depth !== 0) {
540
- items = await Promise.all(items.map(x => this.relatedItems_(x)));
631
+ if (params.market && params.locale) {
632
+ items = await decorateMenus_(this.store, (items as any[]), {
633
+ market: params.market,
634
+ locale: params.locale,
635
+ }) as any[];
541
636
  }
542
637
  return items;
543
638
  }
544
639
 
545
- override async findPaged<B extends T = T>(params: QueryParams = {}): Promise<{ docs: B[]; } & Pagination> {
546
- // console.log('MockService.findPaged', params);
640
+ async findPaged<B extends T = T>(params: QueryParams = {}): Promise<{ docs: B[]; } & Pagination> {
641
+ // console.log('MockMenuService.findPaged', params);
547
642
  const pagination = await super.findPaged<B>(params);
548
- // relations
549
- if (params.depth !== 0) {
550
- pagination.docs = await Promise.all(pagination.docs.map(x => this.relatedItems_(x)));
643
+ if (params.market && params.locale) {
644
+ pagination.docs = await decorateMenus_(this.store, (pagination.docs as any[]), {
645
+ market: params.market,
646
+ locale: params.locale,
647
+ }) as any[];
551
648
  }
552
649
  return pagination;
553
650
  }
554
-
555
- protected async relatedItems_<B extends T = T>(item: B): Promise<B> {
556
- const x = { ...item };
557
- Object.entries(item).forEach(([k, v]) => {
558
- if (isRelation(v)) {
559
- console.log(k, v);
560
- }
561
- });
562
- return x;
563
- }
564
651
  */
565
- decorator_(item, params = {}) {
566
- if (params.locale) {
567
- return localizeItem2(item, params.locale);
568
- } else {
569
- return item;
570
- }
571
- }
572
- };
573
- function isObject(item) {
574
- return item !== null && typeof item === "object";
575
- }
576
- function isRelation(item) {
577
- return isObject(item) && typeof item.relationTo === "string" && item.value !== void 0;
578
- }
579
-
580
- // src/mock/mock-menu.service.ts
581
- var MAX_INT = 1e12;
582
- var UID = 0;
583
- var MockMenuService = class extends MockService {
584
- async findOne(id, params = {}) {
585
- let item = await super.findOne(id, params);
586
- if (item && params.market && params.locale) {
587
- item = await decorateMenu(this.store, item, params.market, params.locale);
588
- }
589
- return item;
590
- }
591
- async findMany(params = {}) {
592
- let items = await super.findMany(params);
652
+ async decorateOne_(item, params = {}) {
653
+ let decoratedItem = await localizeItem_(item, params);
593
654
  if (params.market && params.locale) {
594
- items = await decorateMenus(this.store, items, params.market, params.locale);
655
+ decoratedItem = await decorateMenu_(this.store, decoratedItem, {
656
+ market: params.market,
657
+ locale: params.locale
658
+ });
595
659
  }
596
- return items;
660
+ return decoratedItem;
597
661
  }
598
- async findPaged(params = {}) {
599
- const pagination = await super.findPaged(params);
662
+ async decorateMany_(items, params = {}) {
663
+ let decoratedItems = await localizeItems_(items, params);
600
664
  if (params.market && params.locale) {
601
- pagination.docs = await decorateMenus(this.store, pagination.docs, params.market, params.locale);
602
- }
603
- return pagination;
604
- }
605
- decorator_(item, params = {}) {
606
- if (params.locale) {
607
- return localizeItem3(item, params.locale);
608
- } else {
609
- return item;
665
+ decoratedItems = await decorateMenus_(this.store, decoratedItems, {
666
+ market: params.market,
667
+ locale: params.locale
668
+ });
610
669
  }
670
+ return decoratedItems;
611
671
  }
612
672
  };
613
673
  async function collectPages(store, items, params = {}) {
@@ -620,15 +680,15 @@ async function collectPages(store, items, params = {}) {
620
680
  if (value) {
621
681
  const routes = await store.route.findMany({
622
682
  where: {
683
+ ...params.market ? { market: { equals: params.market } } : {},
684
+ ...params.locale ? { locale: { equals: params.locale } } : {},
623
685
  page: {
624
686
  equals: item.page.value
625
687
  },
626
688
  schema: {
627
689
  equals: item.page.relationTo
628
690
  }
629
- },
630
- market: params.market,
631
- locale: params.locale
691
+ }
632
692
  });
633
693
  const page = {
634
694
  ...value,
@@ -646,31 +706,31 @@ async function collectPages(store, items, params = {}) {
646
706
  }
647
707
  }
648
708
  }
649
- async function decorateMenu(store, item, market = "ww", locale = "en") {
709
+ async function decorateMenu_(store, item, params) {
650
710
  const items = item.items || [];
651
711
  const decoratedItem = {
652
712
  id: item.id,
653
713
  items: []
654
714
  };
655
- const categories = await store.category.findMany({ market, locale });
715
+ const categories = await store.category.findMany(params);
656
716
  const routes = await store.route.findMany({
717
+ ...params,
657
718
  where: {
658
- market: {
659
- equals: market
660
- },
661
- locale: {
662
- equals: locale
663
- }
664
- },
665
- market,
666
- locale
719
+ ...params.market ? { market: { equals: params.market } } : {},
720
+ ...params.locale ? { locale: { equals: params.locale } } : {}
721
+ }
667
722
  });
668
- await collectPages(store, items, { market, locale });
669
- decoratedItem.items = items.filter((x) => hasMarket(x, market)).map((x) => decorateMenuItem(x, categories, routes, market));
723
+ await collectPages(store, items, params);
724
+ decoratedItem.items = items.filter((x) => hasMarket(x, params.market)).map((x) => decorateMenuItem(x, categories, routes, params.market));
670
725
  return decoratedItem;
671
726
  }
672
- async function decorateMenus(store, items, market = "ww", locale = "en") {
673
- return await Promise.all(items.map((x) => decorateMenu(store, x, market, locale)));
727
+ async function decorateMenus_(store, items, params) {
728
+ const decoratedItems = [];
729
+ for (const item of items) {
730
+ const decoratedItem = await decorateMenu_(store, item, params);
731
+ decoratedItems.push(decoratedItem);
732
+ }
733
+ return decoratedItems;
674
734
  }
675
735
  function decorateMenuCategory(item, categories, routes, market, depth = 0) {
676
736
  const decoratedItem = {
@@ -762,7 +822,9 @@ function decorateMenuLink(item, categories, routes, market) {
762
822
  }
763
823
  function decorateMenuPage(item, categories, routes, market) {
764
824
  const items = item.items || [];
765
- const route = routes.find((x) => x.schema === item.page.relationTo && x.page === item.page.value.id);
825
+ const route = routes.find(
826
+ (x) => x.schema === item.page.relationTo && x.page === item.page.value.id
827
+ );
766
828
  const decoratedItem = {
767
829
  id: item.id || "",
768
830
  type: item.type,
@@ -807,66 +869,144 @@ function hasMarket(item, market) {
807
869
  }
808
870
 
809
871
  // src/mock/mock-page.service.ts
810
- import { localizeItem as localizeItem4 } from "@websolutespa/bom-core";
872
+ import { isArray as isArray2, isObject as isObject2, isUndecoratedNav } from "@websolutespa/bom-core";
811
873
  var MockPageService = class extends MockService {
812
- async findOne(id, params = {}) {
813
- let item = await super.findOne(id, params);
814
- if (item && params.market && params.locale) {
815
- item = await decorateHref(this.store, item, params.market, params.locale);
816
- }
874
+ async decorateOne_(item, params = {}) {
875
+ let decoratedItem = await localizeItem_(item, params);
876
+ decoratedItem = await decorateHref_(this.store, decoratedItem, params);
877
+ decoratedItem = await decorateNav_(this.store, decoratedItem, params);
878
+ decoratedItem = await decorateRelation_(this.store, decoratedItem, {
879
+ market: params.market,
880
+ locale: params.locale,
881
+ depth: params.depth
882
+ });
883
+ return decoratedItem;
884
+ }
885
+ async decorateMany_(items, params = {}) {
886
+ let decoratedItems = await localizeItems_(items, params);
887
+ decoratedItems = await decorateHrefs_(this.store, decoratedItems, params);
888
+ decoratedItems = await decorateNavs_(this.store, decoratedItems, params);
889
+ decoratedItems = await decorateRelations_(this.store, decoratedItems, {
890
+ market: params.market,
891
+ locale: params.locale,
892
+ depth: params.depth
893
+ });
894
+ return decoratedItems;
895
+ }
896
+ };
897
+ async function decorateHref_(store, item, params = {}) {
898
+ if (params.market && params.locale) {
899
+ const routes = await store.route.findMany({
900
+ where: {
901
+ market: {
902
+ equals: params.market
903
+ },
904
+ locale: {
905
+ equals: params.locale
906
+ },
907
+ schema: {
908
+ equals: item.schema
909
+ },
910
+ page: {
911
+ equals: item.id
912
+ }
913
+ }
914
+ });
915
+ const href = routes.length ? routes[0].id : null;
916
+ return { ...item, href };
917
+ } else {
817
918
  return item;
818
919
  }
819
- async findMany(params = {}) {
820
- let items = await super.findMany(params);
821
- if (params.market && params.locale) {
822
- items = await decorateHrefs(this.store, items, params.market, params.locale);
823
- }
920
+ }
921
+ async function decorateHrefs_(store, items, params = {}) {
922
+ if (params.market && params.locale) {
923
+ const routes = await store.route.findMany({
924
+ where: {
925
+ market: {
926
+ equals: params.market
927
+ },
928
+ locale: {
929
+ equals: params.locale
930
+ }
931
+ /*
932
+ ...(params.market ? { market: { equals: params.market } } : {}),
933
+ ...(params.locale ? { locale: { equals: params.locale } } : {}),
934
+ */
935
+ }
936
+ });
937
+ return items.map((item) => {
938
+ const route = routes.find(
939
+ (x) => x.schema === item.schema && x.page === item.id
940
+ );
941
+ const href = route ? route.id : null;
942
+ return { ...item, href };
943
+ });
944
+ } else {
824
945
  return items;
825
946
  }
826
- async findPaged(params = {}) {
827
- const pagination = await super.findPaged(params);
828
- if (params.market && params.locale) {
829
- pagination.docs = await decorateHrefs(this.store, pagination.docs, params.market, params.locale);
830
- }
831
- return pagination;
947
+ }
948
+ async function decorateNav_(store, item, params = {}, routes) {
949
+ if (!routes) {
950
+ routes = await store.route.findMany({
951
+ where: {
952
+ ...params.market ? { market: { equals: params.market } } : {},
953
+ ...params.locale ? { locale: { equals: params.locale } } : {}
954
+ }
955
+ });
832
956
  }
833
- decorator_(item, params = {}) {
834
- if (params.locale) {
835
- return localizeItem4(item, params.locale);
836
- } else {
837
- return item;
838
- }
957
+ const navs = collectNavs_(item);
958
+ for (const nav of navs) {
959
+ const decoratedNav = decorateNav__(nav, routes);
960
+ nav.nav = decoratedNav.nav;
839
961
  }
840
- };
841
- async function decorateHref(store, item, market = "ww", locale = "en") {
962
+ return item;
963
+ }
964
+ async function decorateNavs_(store, items, params = {}) {
842
965
  const routes = await store.route.findMany({
966
+ ...params,
843
967
  where: {
844
- schema: {
845
- equals: item.schema
846
- },
847
- page: {
848
- equals: item.id
849
- },
850
- market: {
851
- equals: market
852
- },
853
- locale: {
854
- equals: locale
855
- }
968
+ ...params.market ? { market: { equals: params.market } } : {},
969
+ ...params.locale ? { locale: { equals: params.locale } } : {}
856
970
  }
857
971
  });
858
- const href = routes.length ? routes[0].id : null;
859
- return { ...item, href };
972
+ for (const item of items) {
973
+ await decorateNav_(store, item, params, routes);
974
+ }
975
+ return items;
976
+ }
977
+ function collectNavs_(item, navs = []) {
978
+ if (isUndecoratedNav(item)) {
979
+ navs.push(item);
980
+ }
981
+ if (isArray2(item)) {
982
+ item.forEach((x) => collectNavs_(x, navs));
983
+ } else if (isObject2(item)) {
984
+ Object.values(item).forEach((value) => {
985
+ collectNavs_(value, navs);
986
+ });
987
+ }
988
+ return navs;
860
989
  }
861
- async function decorateHrefs(store, items, market = "ww", locale = "en") {
862
- const routes = await store.route.findMany();
863
- return items.map((item) => {
990
+ function decorateNav__(item, routes) {
991
+ const { nav, ...undecorated } = item;
992
+ if (nav !== void 0) {
993
+ const decorated = { ...undecorated };
864
994
  const route = routes.find(
865
- (x) => x.schema === item.schema && x.page === item.id && x.market === market && x.locale === locale
995
+ (x) => x.page === nav.page.value && x.schema === nav.page.relationTo
866
996
  );
867
- const href = route ? route.id : null;
868
- return { ...item, href };
869
- });
997
+ if (route) {
998
+ decorated.nav = {
999
+ type: "page",
1000
+ id: route.id,
1001
+ href: route.id,
1002
+ title: route.title,
1003
+ page: nav.page.value,
1004
+ schema: nav.page.relationTo
1005
+ };
1006
+ }
1007
+ return decorated;
1008
+ }
1009
+ return undecorated;
870
1010
  }
871
1011
 
872
1012
  // src/mock/mock.store.ts
@@ -979,7 +1119,7 @@ var RemoteService = class {
979
1119
  const url = `/${this.key}/${encodeURIComponent(id)}${search}`;
980
1120
  const item = await remoteApiGet(url);
981
1121
  if (item) {
982
- return this.decorator_(item, params);
1122
+ return await this.decorateOne_(item, params);
983
1123
  }
984
1124
  return;
985
1125
  }
@@ -991,7 +1131,7 @@ var RemoteService = class {
991
1131
  const url = `/${this.key}${search}`;
992
1132
  const response = await remoteApiGet(url);
993
1133
  const items = Array.isArray(response.docs) ? response.docs : response;
994
- return items.map((x) => this.decorator_(x, params));
1134
+ return await this.decorateMany_(items, params);
995
1135
  }
996
1136
  async findPaged(params = {}) {
997
1137
  params.richText = String(params.richText) === "true" ? true : false;
@@ -1001,19 +1141,22 @@ var RemoteService = class {
1001
1141
  const url = `/${this.key}${search}`;
1002
1142
  const response = await remoteApiGet(url);
1003
1143
  let items = response.docs;
1004
- items = items.map((x) => this.decorator_(x, params));
1144
+ items = await this.decorateMany_(items, params);
1005
1145
  return { ...response, docs: items };
1006
1146
  }
1147
+ // !!! todo params
1007
1148
  async create(payload) {
1008
1149
  const url = `/${this.key}`;
1009
1150
  const item = await remoteApiPost(url, payload);
1010
- return this.decorator_(item);
1151
+ return await this.decorateOne_(item, {});
1011
1152
  }
1153
+ // !!! todo params
1012
1154
  async update(payload) {
1013
1155
  const url = `/${this.key}`;
1014
1156
  const item = await remoteApiPut(url, payload);
1015
- return this.decorator_(item);
1157
+ return await this.decorateOne_(item, {});
1016
1158
  }
1159
+ // !!! todo params
1017
1160
  async delete(id) {
1018
1161
  const params = {
1019
1162
  where: {
@@ -1026,12 +1169,14 @@ var RemoteService = class {
1026
1169
  const search = query ? `?${query}` : "";
1027
1170
  const url = `/${this.key}${search}`;
1028
1171
  const item = await remoteApiDelete(url);
1029
- return this.decorator_(item);
1172
+ return await this.decorateOne_(item, {});
1030
1173
  }
1031
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1032
- decorator_(item, params = {}) {
1174
+ async decorateOne_(item, params = {}) {
1033
1175
  return item;
1034
1176
  }
1177
+ async decorateMany_(items, params = {}) {
1178
+ return items;
1179
+ }
1035
1180
  };
1036
1181
 
1037
1182
  // src/remote/remote.store.ts
@@ -1179,7 +1324,6 @@ function collectionPatch(storePromise) {
1179
1324
  return response.status(405).send("method not allowed");
1180
1325
  }
1181
1326
  const collection = collections[0];
1182
- const id = collections[1];
1183
1327
  const store = await storePromise();
1184
1328
  const service = store[collection];
1185
1329
  if (!service) {
@@ -1309,6 +1453,135 @@ async function routePost(store, request, response) {
1309
1453
  return response.status(400).send("bad request");
1310
1454
  }
1311
1455
  }
1456
+ function storeIndexHandler() {
1457
+ return apiHandler({
1458
+ get: async (request, response) => {
1459
+ try {
1460
+ if (!Array.isArray(COLLECTIONS) || COLLECTIONS?.length === 0) {
1461
+ console.error("apiHome.collectionGet", "collections not found", COLLECTIONS);
1462
+ return response.status(405).send("method not allowed");
1463
+ }
1464
+ response.setHeader("Content-Type", "text/html; charset=UTF-8");
1465
+ response.setHeader("X-Frame-Options", "SAMEORIGIN");
1466
+ response.setHeader("X-Robots-Tag", "noindex, follow");
1467
+ return response.status(200).send(`
1468
+ <html>
1469
+ <head>
1470
+ <title>REST Api</title>
1471
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1472
+ <style type="text/css">
1473
+ html {
1474
+ padding: 0;
1475
+ background: #09090A;
1476
+ color: #fefefe;
1477
+ }
1478
+ body {
1479
+ padding: 15px;
1480
+ font-family: Inter,-apple-system,'Helvetica Neue','Segoe UI',Roboto,Arial,'Noto Sans',sans-serif;
1481
+ font-size: 13px;
1482
+ background: #09090A;
1483
+ color: #fefefe;
1484
+ }
1485
+ .container {
1486
+ margin: 0 auto;
1487
+ max-width: 1280px;
1488
+ }
1489
+ a {
1490
+ color: #fefefe;
1491
+ text-decoration: none;
1492
+ }
1493
+ a:visited {
1494
+ color: #9e9e9e;
1495
+ }
1496
+ a:hover {
1497
+ text-decoration: underline;
1498
+ }
1499
+ table {
1500
+ width: 100%;
1501
+ margin: 10px 0;
1502
+ border: none;
1503
+ border-collapse: collapse;
1504
+ }
1505
+ td,
1506
+ th {
1507
+ text-align: left;
1508
+ font-size: 12px;
1509
+ padding: 3px;
1510
+ }
1511
+ th:not(:last-child),
1512
+ td:not(:last-child) {
1513
+ padding-right: 30px;
1514
+ }
1515
+ thead th {
1516
+ border-bottom: 1px solid #0e0e0f;
1517
+ }
1518
+ #table tr:nth-child(odd) td {
1519
+ background-color: #0e0e0f;
1520
+ }
1521
+ #table tbody tr:hover td {
1522
+ background-color: #1A1A1B;
1523
+ }
1524
+ #table tbody tr:hover td,
1525
+ #table tbody tr:hover td a {
1526
+ color: #fefefe;
1527
+ }
1528
+ .wysiwyg {
1529
+ margin: 0;
1530
+ padding: 0 0 10px 0;
1531
+ line-height: 1.2em;
1532
+ }
1533
+ .wysiwyg a {
1534
+ color: #00ea4e;
1535
+ font-weight: 600;
1536
+ }
1537
+ .wysiwyg a:visited {
1538
+ color: #00ea4e;
1539
+ }
1540
+ </style>
1541
+ </head>
1542
+ <body>
1543
+ <div class="container">
1544
+ <h1>REST API</h1>
1545
+ <p class="wysiwyg">
1546
+ This is the REST Api generated by <a href="https://github.com/websolutespa/bom" target="_blank" rel="noopener">Mixer</a>.
1547
+ </p>
1548
+ <p class="wysiwyg">
1549
+ It contains a list of all the generic local api CRUD handlers of Mixer app. <br />
1550
+ All methods should be called with market and locale parameters.
1551
+ </p>
1552
+ <table id="table" cellpadding="3">
1553
+ <thead>
1554
+ <tr>
1555
+ <th width="150px">Method</th>
1556
+ <th width="150px">Collection</th>
1557
+ <th>Endpoint</th>
1558
+ </tr>
1559
+ </thead>
1560
+ <tbody>
1561
+ ${COLLECTIONS.map((c) => `
1562
+ <tr>
1563
+ <td>GET, POST, PATCH</td>
1564
+ <td>${c}</td>
1565
+ <td><a href="/api/${c}?market={market}&locale={locale}">/api/${c}</a></td>
1566
+ </tr>
1567
+ <tr>
1568
+ <td>GET, DELETE</td>
1569
+ <td>${c}</td>
1570
+ <td><a href="/api/${c}/{id}?market={market}&locale={locale}">/api/${c}/{id}</a></td>
1571
+ </tr>
1572
+ `).join("\n")}
1573
+ </tbody>
1574
+ </table>
1575
+ </div>
1576
+ </body>
1577
+ `);
1578
+ } catch (error) {
1579
+ console.error("storeHandler.collectionGet.error", "500", error);
1580
+ throw error;
1581
+ }
1582
+ }
1583
+ });
1584
+ }
1312
1585
 
1313
1586
  // src/mock/mock.handler.ts
1314
1587
  function mockHandler() {
@@ -1336,6 +1609,7 @@ export {
1336
1609
  COLLECTIONS,
1337
1610
  KNOWN_COLLECTIONS,
1338
1611
  MOCK_COLLECTIONS,
1612
+ MOCK_SERVICE_DEFAULT_DEPTH,
1339
1613
  MockService,
1340
1614
  RemoteService,
1341
1615
  STATIC_COLLECTIONS,
@@ -1346,6 +1620,10 @@ export {
1346
1620
  collectionGet,
1347
1621
  collectionPatch,
1348
1622
  collectionPost,
1623
+ decorateRelation_,
1624
+ decorateRelations_,
1625
+ decorateStaticRelation_,
1626
+ decorateStaticRelations_,
1349
1627
  defaultApiRequestOptions,
1350
1628
  errorHandler,
1351
1629
  fromCache,
@@ -1356,8 +1634,6 @@ export {
1356
1634
  getStore,
1357
1635
  isApiRequest,
1358
1636
  isNextRequest,
1359
- isObject,
1360
- isRelation,
1361
1637
  isStaticRequest,
1362
1638
  localApiDelete,
1363
1639
  localApiFetch,
@@ -1365,6 +1641,8 @@ export {
1365
1641
  localApiPatch,
1366
1642
  localApiPost,
1367
1643
  localApiPut,
1644
+ localizeItem_,
1645
+ localizeItems_,
1368
1646
  mockApiDelete,
1369
1647
  mockApiFetch,
1370
1648
  mockApiGet,
@@ -1386,5 +1664,6 @@ export {
1386
1664
  storeApiPost,
1387
1665
  storeApiPut,
1388
1666
  storeHandler,
1667
+ storeIndexHandler,
1389
1668
  storeStrategy
1390
1669
  };