@websolutespa/bom-mixer-store 0.3.0 → 0.3.2
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/CHANGELOG.md +12 -0
- package/dist/index.js +37 -29
- package/dist/index.mjs +37 -29
- package/package.json +5 -3
- package/src/__tests/example.test.ts +8 -0
- package/src/api/api.handler.ts +43 -0
- package/src/api/api.service.ts +52 -0
- package/src/fs/fs.service.ts +127 -0
- package/src/index.ts +15 -0
- package/src/middleware/middleware.service.ts +79 -0
- package/src/mock/mock-menu.service.ts +286 -0
- package/src/mock/mock-page.service.ts +79 -0
- package/src/mock/mock.handler.ts +6 -0
- package/src/mock/mock.service.ts +73 -0
- package/src/mock/mock.store.ts +80 -0
- package/src/revalidate/revalidate.handler.ts +0 -0
- package/src/session/session.handler.ts +82 -0
- package/src/static/static.service.ts +102 -0
- package/src/static/static.ts +223 -0
- package/src/store/store.handler.ts +176 -0
- package/src/store/store.service.ts +34 -0
- package/src/store/store.ts +15 -0
- package/src/storeApi/storeApi.service.ts +191 -0
- package/src/storeApi/storeApi.store.ts +66 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ICategorized, ICategory, IEntity, IEquatable, IMenu, IMenuCategory, IMenuGroup, IMenuItem,
|
|
3
|
+
IMenuLink, IMenuPage, IMenuRoute, IRoute, IStore,
|
|
4
|
+
IUndecoratedMenu, IUndecoratedMenuCategory, IUndecoratedMenuGroup, IUndecoratedMenuItem,
|
|
5
|
+
IUndecoratedMenuLink, IUndecoratedMenuPage, Pagination, QueryParams, localizeItem
|
|
6
|
+
} from '@websolutespa/bom-core';
|
|
7
|
+
import { MockService } from './mock.service';
|
|
8
|
+
|
|
9
|
+
export const MAX_INT = 1000000000000; // 9007199254740991
|
|
10
|
+
|
|
11
|
+
let UID = 0;
|
|
12
|
+
|
|
13
|
+
export class MockMenuService<T extends IEntity = IEntity> extends MockService<T> {
|
|
14
|
+
|
|
15
|
+
async findOne<B extends T = T>(id: IEquatable, params: QueryParams = {}): Promise<B | undefined> {
|
|
16
|
+
// console.log('MockMenuService.findOne', id, params);
|
|
17
|
+
let item = await super.findOne<B>(id, params);
|
|
18
|
+
if (item && params.market && params.locale) {
|
|
19
|
+
item = await decorateMenu(this.store, (item as any), params.market, params.locale) as any;
|
|
20
|
+
}
|
|
21
|
+
return item;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async findMany<B extends T = T>(params: QueryParams = {}): Promise<B[]> {
|
|
25
|
+
// console.log('MockMenuService.findMany', params);
|
|
26
|
+
let items = await super.findMany<B>(params);
|
|
27
|
+
if (params.market && params.locale) {
|
|
28
|
+
items = await decorateMenus(this.store, (items as any[]), params.market, params.locale) as any[];
|
|
29
|
+
}
|
|
30
|
+
return items;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async findPaged<B extends T = T>(params: QueryParams = {}): Promise<{ docs: B[]; } & Pagination> {
|
|
34
|
+
// console.log('MockMenuService.findPaged', params);
|
|
35
|
+
const pagination = await super.findPaged<B>(params);
|
|
36
|
+
if (params.market && params.locale) {
|
|
37
|
+
pagination.docs = await decorateMenus(this.store, (pagination.docs as any[]), params.market, params.locale) as any[];
|
|
38
|
+
}
|
|
39
|
+
return pagination;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected override decorator_<B extends T = T>(item: B, params: QueryParams = {}): B {
|
|
43
|
+
if (params.locale) {
|
|
44
|
+
return localizeItem(item, params.locale);
|
|
45
|
+
} else {
|
|
46
|
+
return item;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async function collectPages(store: IStore, items?: IUndecoratedMenuItem[]) {
|
|
53
|
+
if (!items) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
for (const item of items) {
|
|
57
|
+
if (
|
|
58
|
+
item.type === 'page' &&
|
|
59
|
+
typeof item.page.value === 'number' &&
|
|
60
|
+
store[item.page.relationTo] !== undefined
|
|
61
|
+
) {
|
|
62
|
+
const value = await store[item.page.relationTo].findOne<ICategorized>(item.page.value);
|
|
63
|
+
if (value) {
|
|
64
|
+
item.page.value = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
switch (item.type) {
|
|
68
|
+
case 'group':
|
|
69
|
+
case 'link':
|
|
70
|
+
case 'page':
|
|
71
|
+
await collectPages(store, item.items);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function decorateMenu(store: IStore, item: IUndecoratedMenu, market: string = 'ww', locale: string = 'en'): Promise<IMenu> {
|
|
78
|
+
const items = item.items || [];
|
|
79
|
+
const decoratedItem: IMenu = {
|
|
80
|
+
id: item.id,
|
|
81
|
+
items: [],
|
|
82
|
+
};
|
|
83
|
+
const categories = await store.category.findMany<ICategory>({ market, locale });
|
|
84
|
+
const routes = await store.route.findMany<IRoute>({
|
|
85
|
+
where: {
|
|
86
|
+
market: {
|
|
87
|
+
equals: market,
|
|
88
|
+
},
|
|
89
|
+
locale: {
|
|
90
|
+
equals: locale,
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
await collectPages(store, items);
|
|
95
|
+
decoratedItem.items = items.filter(x => hasMarket(x, market)).map(x => decorateMenuItem(x, categories, routes, market));
|
|
96
|
+
return decoratedItem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function decorateMenus(store: IStore, items: IUndecoratedMenu[], market: string = 'ww', locale: string = 'en'): Promise<IMenu[]> {
|
|
100
|
+
return await Promise.all(items.map(x => decorateMenu(store, x, market, locale)));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function decorateMenuCategory(
|
|
104
|
+
item: IUndecoratedMenuCategory,
|
|
105
|
+
categories: ICategory[],
|
|
106
|
+
routes: IRoute[],
|
|
107
|
+
market: string,
|
|
108
|
+
depth: number = 0,
|
|
109
|
+
): IMenuItem {
|
|
110
|
+
const decoratedItem: IMenuCategory = {
|
|
111
|
+
abstract: item.abstract,
|
|
112
|
+
category: '',
|
|
113
|
+
customClass: item.customClass,
|
|
114
|
+
href: '',
|
|
115
|
+
id: item.id || '',
|
|
116
|
+
items: [],
|
|
117
|
+
title: '',
|
|
118
|
+
type: item.type,
|
|
119
|
+
};
|
|
120
|
+
const category = (typeof item.category === 'string' ? categories.find(x => x.id === item.category) : item.category) as ICategory;
|
|
121
|
+
if (category) {
|
|
122
|
+
// assigning category id
|
|
123
|
+
decoratedItem.category = category.id;
|
|
124
|
+
// assigning category title
|
|
125
|
+
decoratedItem.title = item.title || category.title || '';
|
|
126
|
+
// assigning current or category media
|
|
127
|
+
decoratedItem.media = decoratedItem.media || category.media;
|
|
128
|
+
// find category's index page route
|
|
129
|
+
const route = routes.find(x => x.isDefault && x.category === category.id);
|
|
130
|
+
if (route) {
|
|
131
|
+
// hasLink
|
|
132
|
+
decoratedItem.href = route.id;
|
|
133
|
+
} else {
|
|
134
|
+
// isGroup
|
|
135
|
+
}
|
|
136
|
+
// checking for max depth recursion
|
|
137
|
+
let maxDepth = item.maxDepth;
|
|
138
|
+
if (typeof maxDepth === 'number') {
|
|
139
|
+
if (depth > maxDepth) {
|
|
140
|
+
return decoratedItem;
|
|
141
|
+
}
|
|
142
|
+
maxDepth--;
|
|
143
|
+
}
|
|
144
|
+
// search child categories
|
|
145
|
+
const childCategories = categories.filter(x => (
|
|
146
|
+
x.category && (typeof x.category === 'object' ?
|
|
147
|
+
x.category.id === category.id :
|
|
148
|
+
x.category === category.id)
|
|
149
|
+
));
|
|
150
|
+
if (childCategories.length) {
|
|
151
|
+
// sort child categories
|
|
152
|
+
childCategories.sort((a, b) => {
|
|
153
|
+
return (a.order || MAX_INT) - (b.order || MAX_INT);
|
|
154
|
+
});
|
|
155
|
+
decoratedItem.items = childCategories.map(c => decorateMenuCategory({
|
|
156
|
+
id: c.id,
|
|
157
|
+
type: 'category',
|
|
158
|
+
category: c.id,
|
|
159
|
+
maxDepth,
|
|
160
|
+
items: [],
|
|
161
|
+
} as IUndecoratedMenuCategory, categories, routes, market, depth + 1));
|
|
162
|
+
} else {
|
|
163
|
+
// find child routes
|
|
164
|
+
const childRoutes = routes.filter(x => !x.isDefault && x.category === category.id);
|
|
165
|
+
// sort child routes
|
|
166
|
+
childRoutes.sort((a, b) => {
|
|
167
|
+
return (a.order || MAX_INT) - (b.order || MAX_INT);
|
|
168
|
+
});
|
|
169
|
+
decoratedItem.items = childRoutes.map(x => decorateMenuRoute(x));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return decoratedItem;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function decorateMenuRoute(
|
|
176
|
+
item: IRoute,
|
|
177
|
+
): IMenuItem {
|
|
178
|
+
const decoratedItem: IMenuRoute = {
|
|
179
|
+
id: item.page,
|
|
180
|
+
type: 'route',
|
|
181
|
+
title: item.title,
|
|
182
|
+
href: item.id,
|
|
183
|
+
page: item.page,
|
|
184
|
+
schema: item.schema,
|
|
185
|
+
items: [],
|
|
186
|
+
};
|
|
187
|
+
return decoratedItem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function decorateMenuGroup(
|
|
191
|
+
item: IUndecoratedMenuGroup,
|
|
192
|
+
categories: ICategory[],
|
|
193
|
+
routes: IRoute[],
|
|
194
|
+
market: string,
|
|
195
|
+
): IMenuItem {
|
|
196
|
+
const items = item.items || [];
|
|
197
|
+
const decoratedItem: IMenuGroup = {
|
|
198
|
+
abstract: item.abstract,
|
|
199
|
+
customClass: item.customClass,
|
|
200
|
+
id: item.id || '',
|
|
201
|
+
title: item.title,
|
|
202
|
+
type: item.type,
|
|
203
|
+
items: items.filter(x => hasMarket(x, market)).map(x => decorateMenuItem(x, categories, routes, market)),
|
|
204
|
+
};
|
|
205
|
+
return decoratedItem;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function decorateMenuLink(
|
|
209
|
+
item: IUndecoratedMenuLink,
|
|
210
|
+
categories: ICategory[],
|
|
211
|
+
routes: IRoute[],
|
|
212
|
+
market: string,
|
|
213
|
+
): IMenuItem {
|
|
214
|
+
const items = item.items || [];
|
|
215
|
+
const decoratedItem: IMenuLink = {
|
|
216
|
+
abstract: item.abstract,
|
|
217
|
+
customClass: item.customClass,
|
|
218
|
+
href: item.href,
|
|
219
|
+
id: item.id || '',
|
|
220
|
+
target: item.target || '',
|
|
221
|
+
title: item.title,
|
|
222
|
+
type: item.type,
|
|
223
|
+
items: items.filter(x => hasMarket(x, market)).map(x => decorateMenuItem(x, categories, routes, market)),
|
|
224
|
+
};
|
|
225
|
+
return decoratedItem;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function decorateMenuPage(
|
|
229
|
+
item: IUndecoratedMenuPage,
|
|
230
|
+
categories: ICategory[],
|
|
231
|
+
routes: IRoute[],
|
|
232
|
+
market: string,
|
|
233
|
+
): IMenuItem {
|
|
234
|
+
const items = item.items || [];
|
|
235
|
+
const route = routes.find(x => x.schema === item.page.relationTo && x.page === item.page.value.id);
|
|
236
|
+
const decoratedItem: IMenuPage = {
|
|
237
|
+
id: item.id || '',
|
|
238
|
+
type: item.type,
|
|
239
|
+
title: item.title || item.page.value.title || '',
|
|
240
|
+
abstract: item.abstract || item.page.value.abstract || '',
|
|
241
|
+
customClass: item.customClass,
|
|
242
|
+
href: route?.id || '',
|
|
243
|
+
media: item.page.value.media,
|
|
244
|
+
page: route?.page || '',
|
|
245
|
+
schema: route?.schema || '',
|
|
246
|
+
items: items.filter(x => hasMarket(x, market)).map(x => decorateMenuItem(x, categories, routes, market)),
|
|
247
|
+
};
|
|
248
|
+
return decoratedItem;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function decorateMenuItem(
|
|
252
|
+
item: IUndecoratedMenuItem,
|
|
253
|
+
categories: ICategory[],
|
|
254
|
+
routes: IRoute[],
|
|
255
|
+
market: string,
|
|
256
|
+
depth: number = 0,
|
|
257
|
+
): IMenuItem {
|
|
258
|
+
let decoratedItem: IMenuItem;
|
|
259
|
+
switch (item.type) {
|
|
260
|
+
case 'category':
|
|
261
|
+
decoratedItem = decorateMenuCategory(item, categories, routes, market, depth);
|
|
262
|
+
break;
|
|
263
|
+
case 'group':
|
|
264
|
+
decoratedItem = decorateMenuGroup(item, categories, routes, market);
|
|
265
|
+
break;
|
|
266
|
+
case 'link':
|
|
267
|
+
decoratedItem = decorateMenuLink(item, categories, routes, market);
|
|
268
|
+
break;
|
|
269
|
+
case 'page':
|
|
270
|
+
decoratedItem = decorateMenuPage(item, categories, routes, market);
|
|
271
|
+
break;
|
|
272
|
+
default:
|
|
273
|
+
// eslint-disable-next-line no-case-declarations
|
|
274
|
+
const { blockType, ...rest } = item;
|
|
275
|
+
decoratedItem = {
|
|
276
|
+
...rest,
|
|
277
|
+
type: blockType,
|
|
278
|
+
} as any;
|
|
279
|
+
}
|
|
280
|
+
decoratedItem.id = ++UID;
|
|
281
|
+
return decoratedItem;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function hasMarket(item: IUndecoratedMenuItem, market: string): boolean {
|
|
285
|
+
return Array.isArray(item.markets) ? item.markets.includes(market) : true;
|
|
286
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IEntity, IEquatable,
|
|
3
|
+
IRoute, ISchema, IStore, Pagination,
|
|
4
|
+
QueryParams, localizeItem
|
|
5
|
+
} from '@websolutespa/bom-core';
|
|
6
|
+
import { MockService } from './mock.service';
|
|
7
|
+
|
|
8
|
+
export class MockPageService<T extends IEntity = IEntity> extends MockService<T> {
|
|
9
|
+
|
|
10
|
+
async findOne<B extends T = T>(id: IEquatable, params: QueryParams = {}): Promise<B | undefined> {
|
|
11
|
+
// console.log('MockPageService.findOne', id, params);
|
|
12
|
+
let item = await super.findOne<B>(id, params);
|
|
13
|
+
if (item && params.market && params.locale) {
|
|
14
|
+
item = await decorateHref<B>(this.store, item, params.market, params.locale);
|
|
15
|
+
}
|
|
16
|
+
return item;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async findMany<B extends T = T>(params: QueryParams = {}): Promise<B[]> {
|
|
20
|
+
// console.log('MockPageService.findMany', params);
|
|
21
|
+
let items = await super.findMany<B>(params);
|
|
22
|
+
if (params.market && params.locale) {
|
|
23
|
+
items = await decorateHrefs<B>(this.store, items, params.market, params.locale);
|
|
24
|
+
}
|
|
25
|
+
return items;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async findPaged<B extends T = T>(params: QueryParams = {}): Promise<{ docs: B[]; } & Pagination> {
|
|
29
|
+
// console.log('MockPageService.findPaged', params);
|
|
30
|
+
const pagination = await super.findPaged<B>(params);
|
|
31
|
+
if (params.market && params.locale) {
|
|
32
|
+
pagination.docs = await decorateHrefs<B>(this.store, pagination.docs, params.market, params.locale);
|
|
33
|
+
}
|
|
34
|
+
return pagination;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected override decorator_<B extends T = T>(item: B, params: QueryParams = {}): B {
|
|
38
|
+
if (params.locale) {
|
|
39
|
+
return localizeItem(item, params.locale);
|
|
40
|
+
} else {
|
|
41
|
+
return item;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function decorateHref<T extends ISchema = ISchema>(store: IStore, item: T, market: string = 'ww', locale: string = 'en'): Promise<T & { href: string | null }> {
|
|
47
|
+
const routes = await store.route.findMany<IRoute>({
|
|
48
|
+
where: {
|
|
49
|
+
schema: {
|
|
50
|
+
equals: item.schema
|
|
51
|
+
},
|
|
52
|
+
page: {
|
|
53
|
+
equals: item.id
|
|
54
|
+
},
|
|
55
|
+
market: {
|
|
56
|
+
equals: market
|
|
57
|
+
},
|
|
58
|
+
locale: {
|
|
59
|
+
equals: locale
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const href = routes.length ? routes[0].id : null;
|
|
64
|
+
return { ...item, href };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function decorateHrefs<T extends ISchema = ISchema>(store: IStore, items: T[], market: string = 'ww', locale: string = 'en'): Promise<(T & { href: string | null })[]> {
|
|
68
|
+
const routes = await store.route.findMany<IRoute>();
|
|
69
|
+
return items.map(item => {
|
|
70
|
+
const route = routes.find(x =>
|
|
71
|
+
x.schema === item.schema &&
|
|
72
|
+
x.page === item.id &&
|
|
73
|
+
x.market === market &&
|
|
74
|
+
x.locale === locale
|
|
75
|
+
);
|
|
76
|
+
const href = route ? route.id : null;
|
|
77
|
+
return { ...item, href };
|
|
78
|
+
});
|
|
79
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { IEntity, IPageRelation, IStore, JsonService, localizeItem, QueryParams } from '@websolutespa/bom-core';
|
|
2
|
+
|
|
3
|
+
export class MockService<T extends IEntity = IEntity> extends JsonService<T> {
|
|
4
|
+
store: IStore;
|
|
5
|
+
|
|
6
|
+
constructor(items: T[], store: IStore) {
|
|
7
|
+
super(items);
|
|
8
|
+
this.store = store;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// !!! todo handle relations
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
override async findOne<B extends T = T>(id: IEquatable, params: QueryParams = {}): Promise<B | undefined> {
|
|
15
|
+
console.log('MockService.findOne', id, params);
|
|
16
|
+
let item = await super.findOne<B>(id, params);
|
|
17
|
+
// relations
|
|
18
|
+
if (item) {
|
|
19
|
+
if (params.depth !== 0) {
|
|
20
|
+
item = await this.relatedItems_(item);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return item;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override async findMany<B extends T = T>(params: QueryParams = {}): Promise<B[]> {
|
|
27
|
+
// console.log('MockService.findMany', params);
|
|
28
|
+
let items = await super.findMany<B>(params);
|
|
29
|
+
// relations
|
|
30
|
+
if (params.depth !== 0) {
|
|
31
|
+
items = await Promise.all(items.map(x => this.relatedItems_(x)));
|
|
32
|
+
}
|
|
33
|
+
return items;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override async findPaged<B extends T = T>(params: QueryParams = {}): Promise<{ docs: B[]; } & Pagination> {
|
|
37
|
+
// console.log('MockService.findPaged', params);
|
|
38
|
+
const pagination = await super.findPaged<B>(params);
|
|
39
|
+
// relations
|
|
40
|
+
if (params.depth !== 0) {
|
|
41
|
+
pagination.docs = await Promise.all(pagination.docs.map(x => this.relatedItems_(x)));
|
|
42
|
+
}
|
|
43
|
+
return pagination;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected async relatedItems_<B extends T = T>(item: B): Promise<B> {
|
|
47
|
+
const x = { ...item };
|
|
48
|
+
Object.entries(item).forEach(([k, v]) => {
|
|
49
|
+
if (isRelation(v)) {
|
|
50
|
+
console.log(k, v);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return x;
|
|
54
|
+
}
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
protected override decorator_<B extends T = T>(item: B, params: QueryParams = {}): B {
|
|
58
|
+
if (params.locale) {
|
|
59
|
+
return localizeItem(item, params.locale);
|
|
60
|
+
} else {
|
|
61
|
+
return item;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function isObject(item: unknown): item is Record<string, unknown> {
|
|
68
|
+
return item !== null && (typeof item === 'object');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function isRelation(item: unknown): item is IPageRelation {
|
|
72
|
+
return isObject(item) && typeof item.relationTo === 'string' && item.value !== undefined;
|
|
73
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { IMemoryStore, isDevelopment, IStore } from '@websolutespa/bom-core';
|
|
2
|
+
import { fsReadJson } from '../fs/fs.service';
|
|
3
|
+
import { staticCollections } from '../static/static';
|
|
4
|
+
import { StaticService } from '../static/static.service';
|
|
5
|
+
import { MockMenuService } from './mock-menu.service';
|
|
6
|
+
import { MockPageService } from './mock-page.service';
|
|
7
|
+
import { MockService } from './mock.service';
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const PAGES: string[] = process.env.PAGES ? process.env.PAGES.split(',') : [];
|
|
13
|
+
|
|
14
|
+
let STORE_: IStore;
|
|
15
|
+
|
|
16
|
+
export async function getMockStoreServer<T extends IStore>(): Promise<T> {
|
|
17
|
+
// console.log('getMockStore', STORE_ ? Object.keys(STORE_) : null);
|
|
18
|
+
// console.log('getMockStore.process.cwd', process.cwd());
|
|
19
|
+
if (STORE_) {
|
|
20
|
+
return STORE_ as T;
|
|
21
|
+
}
|
|
22
|
+
const pathname = path.join(process.cwd(), '.mixer', 'store.json');
|
|
23
|
+
// console.log('getMockStore.pathname', pathname);
|
|
24
|
+
const data: IMemoryStore = await fsReadJson(pathname);
|
|
25
|
+
const store = getMockStoreFromData(data);
|
|
26
|
+
if (!isDevelopment) {
|
|
27
|
+
STORE_ = store;
|
|
28
|
+
}
|
|
29
|
+
return store as T;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getMockStore<T extends IStore>(getJson: () => Promise<string>): Promise<T> {
|
|
33
|
+
// console.log('getMockStore', STORE_ ? Object.keys(STORE_) : null);
|
|
34
|
+
// console.log('getMockStore.process.cwd', process.cwd());
|
|
35
|
+
if (STORE_) {
|
|
36
|
+
return STORE_ as T;
|
|
37
|
+
}
|
|
38
|
+
const json = await getJson();
|
|
39
|
+
const data: IMemoryStore = JSON.parse(json);
|
|
40
|
+
const store = getMockStoreFromData(data);
|
|
41
|
+
if (!isDevelopment) {
|
|
42
|
+
STORE_ = store;
|
|
43
|
+
}
|
|
44
|
+
return store as T;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getMockStoreFromData<T extends IStore>(data: IMemoryStore): T {
|
|
48
|
+
const store: IStore = {};
|
|
49
|
+
for (const key in data) {
|
|
50
|
+
if (!PAGES.includes(key)) {
|
|
51
|
+
// new collection
|
|
52
|
+
const service = new MockService(data[key], store);
|
|
53
|
+
store[key] = service;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const category = store.category;
|
|
57
|
+
const route = store.route;
|
|
58
|
+
const menu = data.menu;
|
|
59
|
+
if (category && route && menu) {
|
|
60
|
+
store.menu = new MockMenuService(menu, store);
|
|
61
|
+
}
|
|
62
|
+
for (const key in data) {
|
|
63
|
+
if (PAGES.includes(key)) {
|
|
64
|
+
let service;
|
|
65
|
+
if (route) {
|
|
66
|
+
// new page
|
|
67
|
+
service = new MockPageService(data[key], store);
|
|
68
|
+
} else {
|
|
69
|
+
// !!! new collection should throw
|
|
70
|
+
service = new MockService(data[key], store);
|
|
71
|
+
}
|
|
72
|
+
store[key] = service;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
staticCollections.forEach(config => {
|
|
76
|
+
store[config.slug] = new StaticService(config, store);
|
|
77
|
+
});
|
|
78
|
+
return store as T;
|
|
79
|
+
}
|
|
80
|
+
|
|
File without changes
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { httpDelete, httpGet, httpPost } from '@websolutespa/bom-core';
|
|
2
|
+
import { apiHandler } from '@websolutespa/bom-mixer-store';
|
|
3
|
+
import { IronSessionOptions } from 'iron-session/edge';
|
|
4
|
+
import { withIronSessionApiRoute } from 'iron-session/next';
|
|
5
|
+
import { NextApiRequest, NextApiResponse } from 'next';
|
|
6
|
+
import { StateStorage } from 'zustand/middleware';
|
|
7
|
+
|
|
8
|
+
function sessionGet(request: NextApiRequest, response: NextApiResponse<string | null>) {
|
|
9
|
+
const { key } = request.query;
|
|
10
|
+
const session: { [key: string]: string | null } = request.session as any;
|
|
11
|
+
if (session[key as string]) {
|
|
12
|
+
response.status(200).json(session[key as string]);
|
|
13
|
+
} else {
|
|
14
|
+
response.status(200).json(null);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function sessionPost(request: NextApiRequest, response: NextApiResponse<null>) {
|
|
19
|
+
const { key } = request.query;
|
|
20
|
+
const body = request.body;
|
|
21
|
+
const session: { [key: string]: string | null } = request.session as any;
|
|
22
|
+
// console.log('body', body);
|
|
23
|
+
session[key as string] = body.value;
|
|
24
|
+
// console.log('session', session);
|
|
25
|
+
await request.session.save();
|
|
26
|
+
response.status(200).json(null);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function sessionDelete(request: NextApiRequest, response: NextApiResponse<null>) {
|
|
30
|
+
const { key } = request.query;
|
|
31
|
+
const session: { [key: string]: string | null } = request.session as any;
|
|
32
|
+
session[key as string] = null;
|
|
33
|
+
await request.session.save();
|
|
34
|
+
response.status(200).json(null);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type ISessionHandler = (request: NextApiRequest, response: NextApiResponse) => Promise<void>;
|
|
38
|
+
|
|
39
|
+
export function sessionHandler<T extends {}>(sessionOptions: IronSessionOptions) {
|
|
40
|
+
return apiHandler({
|
|
41
|
+
get: withIronSessionApiRoute(sessionGet, sessionOptions) as ISessionHandler,
|
|
42
|
+
post: withIronSessionApiRoute(sessionPost, sessionOptions) as ISessionHandler,
|
|
43
|
+
delete: withIronSessionApiRoute(sessionDelete, sessionOptions) as ISessionHandler,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const IronSessionStorage: StateStorage = {
|
|
48
|
+
getItem: async (name: string) => {
|
|
49
|
+
const value = await httpGet(`/api/__session/${name}`);
|
|
50
|
+
// console.log('IronSessionStorage.getItem', name, value);
|
|
51
|
+
return value;
|
|
52
|
+
},
|
|
53
|
+
setItem: async (name: string, value: string) => {
|
|
54
|
+
// console.log('IronSessionStorage.setItem', name, { cart: value });
|
|
55
|
+
await httpPost(`/api/__session/${name}`, { value });
|
|
56
|
+
},
|
|
57
|
+
removeItem: async (name: string) => {
|
|
58
|
+
// console.log('IronSessionStorage.removeItem', name);
|
|
59
|
+
await httpDelete(`/api/__session/${name}`);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
import { withIronSessionSsr } from 'iron-session/next';
|
|
65
|
+
|
|
66
|
+
type IronSessionCallback<P> = (context: GetServerSidePropsContext) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>
|
|
67
|
+
type IronSessionHandlerResult<P> = (context: GetServerSidePropsContext) => Promise<GetServerSidePropsResult<P>>;
|
|
68
|
+
|
|
69
|
+
export function withIronSession<P extends { [key: string]: unknown; } = { [key: string]: unknown; }>(
|
|
70
|
+
callback: IronSessionCallback<P>,
|
|
71
|
+
options: IronSessionOptions,
|
|
72
|
+
): IronSessionHandlerResult<P> {
|
|
73
|
+
return withIronSessionSsr(async function (context) {
|
|
74
|
+
// !!! hack for vercel lambdas
|
|
75
|
+
if (storeStrategy === StoreStrategy.Mock) {
|
|
76
|
+
const pathname = path.join(process.cwd(), '.mixer', 'store.json');
|
|
77
|
+
const data = await fs.readFile(pathname, 'utf8');
|
|
78
|
+
}
|
|
79
|
+
return callback(context);
|
|
80
|
+
}, options);
|
|
81
|
+
}
|
|
82
|
+
*/
|