@websolutespa/bom-mixer-store 0.2.0 → 0.3.1

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 CHANGED
@@ -1,25 +1,37 @@
1
- # @websolutespa/bom-mixer-store
2
-
3
- ## 0.2.0
4
-
5
- ### Minor Changes
6
-
7
- - Added: @websolutespa/bom-core.
8
-
9
- ## 0.1.1
10
-
11
- ### Patch Changes
12
-
13
- - Modified: store service.
14
-
15
- ## 0.1.0
16
-
17
- ### Minor Changes
18
-
19
- - mock refactor.
20
-
21
- ## 0.0.2
22
-
23
- ### Patch Changes
24
-
25
- - Added: first release.
1
+ # @websolutespa/bom-mixer-store
2
+
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Added: source files.
8
+
9
+ ## 0.3.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Added: splat routes.
14
+
15
+ ## 0.2.0
16
+
17
+ ### Minor Changes
18
+
19
+ - Added: @websolutespa/bom-core.
20
+
21
+ ## 0.1.1
22
+
23
+ ### Patch Changes
24
+
25
+ - Modified: store service.
26
+
27
+ ## 0.1.0
28
+
29
+ ### Minor Changes
30
+
31
+ - mock refactor.
32
+
33
+ ## 0.0.2
34
+
35
+ ### Patch Changes
36
+
37
+ - Added: first release.
package/dist/index.js CHANGED
@@ -1194,6 +1194,26 @@ function storeHandler(storePromise = async () => await getStore()) {
1194
1194
  }
1195
1195
  }
1196
1196
  });
1197
+ if (routes.length === 0) {
1198
+ const splatRoutes = await store.route.findMany({
1199
+ where: {
1200
+ useSplat: {
1201
+ equals: true
1202
+ }
1203
+ }
1204
+ });
1205
+ const route = splatRoutes.reduce((p, c) => {
1206
+ const match = pathname.indexOf(c.id) === 0;
1207
+ if (match && (!p || p.id.length < c.id.length)) {
1208
+ return { ...c, splat: pathname.substring(c.id.length, pathname.length) };
1209
+ } else {
1210
+ return p;
1211
+ }
1212
+ }, void 0);
1213
+ if (route) {
1214
+ return response.status(200).json(route);
1215
+ }
1216
+ }
1197
1217
  if (routes.length > 0) {
1198
1218
  return response.status(200).json(routes[0]);
1199
1219
  } else {
package/dist/index.mjs CHANGED
@@ -1146,6 +1146,26 @@ function storeHandler(storePromise = async () => await getStore()) {
1146
1146
  }
1147
1147
  }
1148
1148
  });
1149
+ if (routes.length === 0) {
1150
+ const splatRoutes = await store.route.findMany({
1151
+ where: {
1152
+ useSplat: {
1153
+ equals: true
1154
+ }
1155
+ }
1156
+ });
1157
+ const route = splatRoutes.reduce((p, c) => {
1158
+ const match = pathname.indexOf(c.id) === 0;
1159
+ if (match && (!p || p.id.length < c.id.length)) {
1160
+ return { ...c, splat: pathname.substring(c.id.length, pathname.length) };
1161
+ } else {
1162
+ return p;
1163
+ }
1164
+ }, void 0);
1165
+ if (route) {
1166
+ return response.status(200).json(route);
1167
+ }
1168
+ }
1149
1169
  if (routes.length > 0) {
1150
1170
  return response.status(200).json(routes[0]);
1151
1171
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websolutespa/bom-mixer-store",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Mixer Store module of the BOM Repository",
5
5
  "keywords": [
6
6
  "bom",
@@ -22,11 +22,10 @@
22
22
  "prepack": "bom prepack",
23
23
  "postpack": "bom postpack"
24
24
  },
25
- "dependencies": {
26
- "@websolutespa/bom-core": "*",
27
- "iron-session": "^6.2.1"
28
- },
25
+ "dependencies": {},
29
26
  "peerDependencies": {
27
+ "@websolutespa/bom-core": "*",
28
+ "iron-session": ">= 6.2.1",
30
29
  "next": ">= 12.3.2"
31
30
  },
32
31
  "devDependencies": {
@@ -46,12 +45,14 @@
46
45
  "sideEffects": false,
47
46
  "prepack": {
48
47
  "types": "./dist/index.d.ts",
49
- "main": "./dist/index.js"
48
+ "main": "./dist/index.js",
49
+ "source": "./src/index.ts"
50
50
  },
51
51
  "postpack": {
52
52
  "types": "./src/index.ts",
53
53
  "main": "./src/index.ts"
54
54
  },
55
55
  "types": "./dist/index.d.ts",
56
- "main": "./dist/index.js"
56
+ "main": "./dist/index.js",
57
+ "source": "./src/index.ts"
57
58
  }
@@ -0,0 +1,8 @@
1
+ import '@testing-library/jest-dom';
2
+
3
+ describe('Example', () => {
4
+ it('passes', async () => {
5
+ const value = 'test';
6
+ expect(value).toEqual(value);
7
+ });
8
+ });
@@ -0,0 +1,43 @@
1
+ import { NextApiRequest, NextApiResponse } from 'next';
2
+
3
+ export type ICrudMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | string;
4
+
5
+ export type IHandler = (request: NextApiRequest, response: NextApiResponse) => Promise<any>;
6
+
7
+ export type IApiHandler = Record<ICrudMethod, IHandler>;
8
+
9
+ export function apiHandler(handler: IApiHandler): any {
10
+ return async (request: NextApiRequest, response: NextApiResponse): Promise<any> => {
11
+ const method: ICrudMethod = (request.method || 'GET').toLowerCase() as ICrudMethod;
12
+ // check handler supports HTTP method
13
+ if (!handler[method]) {
14
+ return response.status(405).end(`Method ${method} Not Allowed`);
15
+ }
16
+ try {
17
+ // global middleware
18
+ // await jwtMiddleware(request, response);
19
+ // route handler
20
+ await handler[method](request, response);
21
+ } catch (error) {
22
+ // console.log('error', error);
23
+ // global error handler
24
+ return errorHandler(error, response);
25
+ }
26
+ };
27
+ }
28
+
29
+ export function errorHandler(error: any, response: NextApiResponse): Promise<any> | void {
30
+ if (typeof (error) === 'string') {
31
+ // custom application error
32
+ const is404 = error.toLowerCase().endsWith('not found');
33
+ const statusCode = is404 ? 404 : 400;
34
+ return response.status(statusCode).json({ message: error });
35
+ }
36
+ if (error.name === 'UnauthorizedError') {
37
+ // jwt authentication error
38
+ return response.status(401).json({ message: 'Invalid Token' });
39
+ }
40
+ // default to 500 server error
41
+ console.error(error);
42
+ return response.status(500).json({ message: error.message });
43
+ }
@@ -0,0 +1,52 @@
1
+ import { FetchRequestOptions, httpFetch, merge } from '@websolutespa/bom-core';
2
+
3
+ const defaultApiOptions: FetchRequestOptions = {
4
+ // mode: 'cors',
5
+ headers: {
6
+ // Authorization: `Bearer ${BEARER}`,
7
+ },
8
+ };
9
+
10
+ // typeof eval === 'function' ? defaultApiOptions.mode = 'cors' : null;
11
+ // const BEARER = process.env.STORE_BEARER || '7584f15d12972fb1e7695e998dd5e4c754f46c74d06a08e8d76f556adcd045e48cd52bed6faac098784471ac273ee40243194b9cff7eba3c4a768f8f41d2d51959a7f767b943c7f0170f6e5f632db523803c357083bf7a7bf03ee8e0df2d8ce5cd52e0211283b34d7781313da775018a9e950433d2b6faf711c20e5a63b25243';
12
+
13
+ export function getApiUrl(pathname: string): string {
14
+ const localUrl = process.env.NEXT_PUBLIC_URL === 'https://' ?
15
+ process.env.NEXT_PUBLIC_MOCK_FALLBACK_URL :
16
+ process.env.NEXT_PUBLIC_URL;
17
+ const apiBase = process.env.NEXT_PUBLIC_API || '/api';
18
+ const url = `${localUrl}${apiBase}${pathname}`;
19
+ return url;
20
+ }
21
+
22
+ export async function apiFetch<T = any>(pathname: string, options: FetchRequestOptions = {}, serviceOptions?: { locale: string, market: string }): Promise<T> {
23
+ const url = new URL(getApiUrl(pathname));
24
+ if (serviceOptions) {
25
+ url.searchParams.append('locale', serviceOptions.locale);
26
+ url.searchParams.append('market', serviceOptions.market);
27
+ }
28
+ const apiOptions = merge({ ...defaultApiOptions }, options);
29
+ // console.log('apiFetch', url.href, apiOptions);
30
+ const apiResponse = await httpFetch(url.href, apiOptions);
31
+ return apiResponse;
32
+ }
33
+
34
+ export async function apiGet<T = any>(url: string, options: FetchRequestOptions = {}, serviceOptions?: { locale: string, market: string }): Promise<T> {
35
+ return await apiFetch<T>(url, { ...options, method: 'GET' }, serviceOptions);
36
+ }
37
+
38
+ export async function apiPost<T = any>(url: string, payload?: unknown, options: FetchRequestOptions = {}, serviceOptions?: { locale: string, market: string }): Promise<T> {
39
+ return await apiFetch<T>(url, { ...options, method: 'POST', body: payload ? JSON.stringify(payload) : undefined }, serviceOptions);
40
+ }
41
+
42
+ export async function apiPut<T = any>(url: string, payload?: unknown, options: FetchRequestOptions = {}, serviceOptions?: { locale: string, market: string }): Promise<T> {
43
+ return await apiFetch<T>(url, { ...options, method: 'PUT', body: payload ? JSON.stringify(payload) : undefined }, serviceOptions);
44
+ }
45
+
46
+ export async function apiPatch<T = any>(url: string, payload?: unknown, options: FetchRequestOptions = {}, serviceOptions?: { locale: string, market: string }): Promise<T> {
47
+ return await apiFetch<T>(url, { ...options, method: 'PATCH', body: payload ? JSON.stringify(payload) : undefined }, serviceOptions);
48
+ }
49
+
50
+ export async function apiDelete<T = any>(url: string, options: FetchRequestOptions = {}, serviceOptions?: { locale: string, market: string }): Promise<T> {
51
+ return await apiFetch<T>(url, { ...options, method: 'DELETE' }, serviceOptions);
52
+ }
@@ -0,0 +1,127 @@
1
+ /* eslint-disable @typescript-eslint/no-var-requires */
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ export async function fsExists(pathname: string): Promise<boolean> {
6
+ try {
7
+ await fs.promises.access(pathname);
8
+ return true;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+
14
+ export async function fsRead(pathname: string, encoding = 'utf8'): Promise<any> {
15
+ try {
16
+ const data = await fs.promises.readFile(pathname, encoding);
17
+ return data || null;
18
+ } catch (error) {
19
+ console.log('fsRead', error, pathname);
20
+ return null;
21
+ }
22
+ }
23
+
24
+ export async function fsReadJson(pathname: string): Promise<any> {
25
+ try {
26
+ const data = await fsRead(pathname);
27
+ if (data) {
28
+ return JSON.parse(data);
29
+ } else {
30
+ return null;
31
+ }
32
+ } catch (error) {
33
+ console.log('fsReadJson', error, pathname);
34
+ // throw (error);
35
+ return null;
36
+ }
37
+ }
38
+
39
+ export async function fsWrite(pathname: string, data: string, encoding = 'utf8'): Promise<void> {
40
+ try {
41
+ await fs.promises.mkdir(path.dirname(pathname), { recursive: true });
42
+ await fs.promises.writeFile(pathname, data, encoding);
43
+ } catch (error) {
44
+ console.log('fsWrite', error, pathname);
45
+ }
46
+ }
47
+
48
+ export async function fsWriteJson(pathname: string, data: any): Promise<void> {
49
+ try {
50
+ await fsWrite(pathname, JSON.stringify(data, null, 2));
51
+ } catch (error) {
52
+ console.log('fsWriteJson', error, pathname);
53
+ }
54
+ }
55
+
56
+ export async function fsExistOrCreateFolder(pathname: string): Promise<void> {
57
+ try {
58
+ const exists = fs.existsSync(pathname);
59
+ if (!exists) {
60
+ await fs.promises.mkdir(pathname);
61
+ }
62
+ } catch (error) {
63
+ console.log('fsExistOrCreateFolder', error, pathname);
64
+ }
65
+ }
66
+
67
+ export async function fsReadDirectory(pathname: string, extension?: string): Promise<{ name: string, data: string }[]> {
68
+ const files = await fs.promises.readdir(pathname);
69
+ const items = files.flatMap(async (file: string) => {
70
+ const filePath = path.join(pathname, file);
71
+ const stat = await fs.promises.stat(filePath);
72
+ if (stat.isDirectory()) {
73
+ return;
74
+ }
75
+ if (extension && path.parse(file).ext !== extension) {
76
+ return;
77
+ }
78
+ const data = await fs.promises.readFile(filePath);
79
+ if (!data) {
80
+ return;
81
+ }
82
+ return {
83
+ name: path.parse(file).name,
84
+ data: data.toString(),
85
+ };
86
+ }) as Promise<{ name: string, data: string }>[];
87
+ const items2 = (await Promise.all(items)).filter(Boolean);
88
+ return items2;
89
+ }
90
+
91
+ export async function fsReadJsonDirectory(pathname: string): Promise<{ name: string, data: any }[]> {
92
+ try {
93
+ const datas = await fsReadDirectory(pathname, '.json');
94
+ return datas.filter(Boolean).map(x => {
95
+ x.data = JSON.parse(x.data);
96
+ return x;
97
+ });
98
+ } catch (error) {
99
+ console.log('fsReadJsonDirectory', error, pathname);
100
+ // throw (error);
101
+ return [];
102
+ }
103
+ }
104
+
105
+ export function fsWatch(pathname: string, callback: (eventType: any, fileName: string) => void, options?: { interval: 2000 }): void {
106
+ const debounced = debounce(callback);
107
+ return fs.watch(pathname, options, debounced);
108
+ }
109
+
110
+ export function fsWatchFile(pathname: string, callback: (eventType: any, fileName: string) => void, options?: { interval: 2000 }): void {
111
+ const debounced = debounce(callback);
112
+ return fs.watchFile(pathname, options, debounced);
113
+ }
114
+
115
+ export function pathJoin(...paths: string[]): string {
116
+ return path.join(process.cwd(), ...paths);
117
+ }
118
+
119
+ export function debounce(callback: (...args: any[]) => void, timeout: number = 300) {
120
+ let timer: NodeJS.Timeout;
121
+ return (...args: any[]) => {
122
+ clearTimeout(timer);
123
+ timer = setTimeout(() => {
124
+ callback(...args);
125
+ }, timeout);
126
+ };
127
+ }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ export * from './api/api.handler';
2
+ export * from './api/api.service';
3
+ export * from './middleware/middleware.service';
4
+ export * from './mock/mock.handler';
5
+ export * from './mock/mock.service';
6
+ export * from './mock/mock.store';
7
+ // export * from './session/session.handler';
8
+ export * from './static/static';
9
+ export * from './static/static.service';
10
+ export * from './store/store';
11
+ export * from './store/store.handler';
12
+ export * from './store/store.service';
13
+ export * from './storeApi/storeApi.service';
14
+ export * from './storeApi/storeApi.store';
15
+
@@ -0,0 +1,79 @@
1
+ import { NextRequest } from 'next/server';
2
+
3
+ const API_BASE = process.env.NEXT_PUBLIC_API || '/api';
4
+
5
+ export function isStaticRequest(request: NextRequest) {
6
+ const url = request.nextUrl;
7
+ const isStatic = url.pathname.indexOf('.') !== -1;
8
+ return isStatic;
9
+ }
10
+
11
+ export function isNextRequest(request: NextRequest) {
12
+ const url = request.nextUrl;
13
+ const isNext = url.pathname.indexOf('/_next/') === 0;
14
+ return isNext;
15
+ }
16
+
17
+ export function isApiRequest(request: NextRequest) {
18
+ const url = request.nextUrl;
19
+ const isApi = url.pathname.indexOf(API_BASE) === 0;
20
+ return isApi;
21
+ }
22
+
23
+ /*
24
+ import { NextApiRequest, NextApiResponse } from 'next';
25
+
26
+ export type RouteMiddleware = (request: NextRequest, event: NextFetchEvent) => Promise<Response | undefined> | Response | undefined;
27
+
28
+ export type ApiMiddleware = (request: NextApiRequest, response: NextApiResponse) => unknown;
29
+
30
+ // Helper method to wait for a middleware to execute before continuing
31
+ // And to throw an error when an error happens in a middleware
32
+ export default function useApiMiddleware(middleware) {
33
+ return (request, response) => new Promise((resolve, reject) => {
34
+ middleware(request, response, (result) => {
35
+ if (result instanceof Error) {
36
+ return reject(result);
37
+ }
38
+ return resolve(result);
39
+ });
40
+ })
41
+ }
42
+
43
+ * @name withMiddleware
44
+ * @description combine multiple middleware before handling your API endpoint
45
+ * @param middlewares
46
+ export function withApiMiddleware(...middlewares: ApiMiddleware[]) {
47
+
48
+ return async function withMiddlewareHandler(request: NextApiRequest, response: NextApiResponse) {
49
+
50
+ async function evaluateHandler(middleware: ApiMiddleware, innerMiddleware?: ApiMiddleware | undefined) {
51
+ // return early when the request has
52
+ // been ended by a previous middleware
53
+ if (response.headersSent) {
54
+ return;
55
+ }
56
+ if (typeof middleware === 'function') {
57
+ const handler = await middleware(request, response);
58
+ if (typeof handler === 'function') {
59
+ if (innerMiddleware) {
60
+ await handler(innerMiddleware);
61
+ const index = middlewares.indexOf(innerMiddleware);
62
+ // remove inner middleware
63
+ if (index >= 0) {
64
+ middlewares.splice(index, 1);
65
+ }
66
+ } else {
67
+ await handler();
68
+ }
69
+ }
70
+ }
71
+ }
72
+ for (let index = 0; index < middlewares.length; index++) {
73
+ const middleware = middlewares[index];
74
+ const nextMiddleware = middlewares[index + 1];
75
+ await evaluateHandler(middleware, nextMiddleware);
76
+ }
77
+ };
78
+ }
79
+ */