@opengis/fastify-table 1.1.70 → 1.1.72
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/README.md +26 -26
- package/config.js +10 -10
- package/index.js +3 -36
- package/package.json +2 -2
- package/server/plugins/hook/funcs/applyHookSync.js +9 -0
- package/server/plugins/logger/createFileStream.js +17 -2
- package/server/plugins/logger/errorMessage.js +25 -0
- package/server/plugins/logger/errorStatus.js +19 -0
- package/server/plugins/logger/getHooks.js +4 -0
- package/server/plugins/logger/getLogger.js +0 -6
- package/server/plugins/logger/index.js +21 -0
- package/server/routes/crud/controllers/deleteCrud.js +1 -1
- package/server/routes/crud/controllers/insert.js +5 -7
- package/server/routes/logger/controllers/logger.file.js +1 -1
- package/server/routes/logger/index.js +1 -1
- package/server/routes/table/controllers/data.js +2 -2
- package/utils.js +2 -0
package/README.md
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
# fastify-table
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@opengis/fastify-table)
|
|
4
|
-
[](http://standardjs.com/)
|
|
5
|
-
|
|
6
|
-
It standardizes the entire form building process, while taking care of everything from rendering to validation and processing:
|
|
7
|
-
|
|
8
|
-
- pg
|
|
9
|
-
- redis
|
|
10
|
-
- crud
|
|
11
|
-
|
|
12
|
-
## Install
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm i @opengis/fastify-table
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Usage
|
|
19
|
-
|
|
20
|
-
```js
|
|
21
|
-
fastify.register(import('@opengis/fastify-table'), config);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Documenation
|
|
25
|
-
|
|
26
|
-
For a detailed understanding fastify-table, its features, and how to use them, refer to our [Documentation](https://apidocs.softpro.ua/gis.storage/).
|
|
1
|
+
# fastify-table
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@opengis/fastify-table)
|
|
4
|
+
[](http://standardjs.com/)
|
|
5
|
+
|
|
6
|
+
It standardizes the entire form building process, while taking care of everything from rendering to validation and processing:
|
|
7
|
+
|
|
8
|
+
- pg
|
|
9
|
+
- redis
|
|
10
|
+
- crud
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm i @opengis/fastify-table
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
fastify.register(import('@opengis/fastify-table'), config);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Documenation
|
|
25
|
+
|
|
26
|
+
For a detailed understanding fastify-table, its features, and how to use them, refer to our [Documentation](https://apidocs.softpro.ua/gis.storage/).
|
package/config.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
|
|
3
|
-
const fileName = ['config.json', '/data/local/config.json'].find(el => (fs.existsSync(el) ? el : null));
|
|
4
|
-
const config = fileName ? JSON.parse(fs.readFileSync(fileName)) : {};
|
|
5
|
-
|
|
6
|
-
Object.assign(config, {
|
|
7
|
-
allTemplates: config?.allTemplates || {},
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
export default config;
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
|
|
3
|
+
const fileName = ['config.json', '/data/local/config.json'].find(el => (fs.existsSync(el) ? el : null));
|
|
4
|
+
const config = fileName ? JSON.parse(fs.readFileSync(fileName)) : {};
|
|
5
|
+
|
|
6
|
+
Object.assign(config, {
|
|
7
|
+
allTemplates: config?.allTemplates || {},
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default config;
|
package/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import policyPlugin from './server/plugins/policy/index.js';
|
|
|
13
13
|
import redisPlugin from './server/plugins/redis/index.js';
|
|
14
14
|
import tablePlugin from './server/plugins/table/index.js';
|
|
15
15
|
import utilPlugin from './server/plugins/util/index.js';
|
|
16
|
+
import loggerPlugin from './server/plugins/logger/index.js';
|
|
16
17
|
|
|
17
18
|
// routes
|
|
18
19
|
import cronRoutes from './server/routes/cron/index.js';
|
|
@@ -23,7 +24,7 @@ import tableRoutes from './server/routes/table/index.js';
|
|
|
23
24
|
import utilRoutes from './server/routes/util/index.js';
|
|
24
25
|
|
|
25
26
|
import {
|
|
26
|
-
addTemplateDir, execMigrations,
|
|
27
|
+
addTemplateDir, execMigrations,
|
|
27
28
|
} from './utils.js';
|
|
28
29
|
|
|
29
30
|
async function plugin(fastify, opt) {
|
|
@@ -32,10 +33,6 @@ async function plugin(fastify, opt) {
|
|
|
32
33
|
config.root = opt.root;
|
|
33
34
|
config.mapServerRoot = opt.mapServerRoot;
|
|
34
35
|
|
|
35
|
-
/* const d = await handlebars.compile('hb async: {{id}}')({ id: 1 });
|
|
36
|
-
console.log(d);
|
|
37
|
-
console.log(handlebarsSync.compile('hb sync: {{id}}')({ id: 1 })); */
|
|
38
|
-
|
|
39
36
|
// independent npm start / unit test
|
|
40
37
|
if (!fastify.config) {
|
|
41
38
|
fastify.decorate('config', config);
|
|
@@ -50,40 +47,9 @@ async function plugin(fastify, opt) {
|
|
|
50
47
|
});
|
|
51
48
|
|
|
52
49
|
fastify.register(import('@opengis/fastify-hb'));
|
|
53
|
-
fastify.decorate('getFolder', (req, type = 'server') => {
|
|
54
|
-
if (!['server', 'local'].includes(type)) throw new Error('params type is invalid');
|
|
55
|
-
const types = { local: req.root || config.root, server: req.mapServerRoot || config.mapServerRoot };
|
|
56
|
-
const filepath = path.posix.join(types[type] || `/data/local/${req.pg?.options?.database || ''}`, req.folder || config.folder || '');
|
|
57
|
-
return filepath;
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
fastify.setErrorHandler((error, request, reply) => {
|
|
61
|
-
if (error.validation) {
|
|
62
|
-
request.log.warn(request, { code: error?.code, status: 422, error: error.toString() });
|
|
63
|
-
return reply.status(422).send(error.toString());
|
|
64
|
-
}
|
|
65
|
-
if (error.stack?.startsWith('Error: unhandled exception')) {
|
|
66
|
-
request.log.fatal(request, { status: 501, error: error.toString() });
|
|
67
|
-
return reply.status(500).send('ServerError');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
request.log.error(error, request);
|
|
71
|
-
return reply.status(error.statusCode || 500).send(config.local ? error.toString() : 'ServerError');
|
|
72
|
-
});
|
|
73
50
|
|
|
74
51
|
execMigrations().catch(err => console.log(err));
|
|
75
52
|
|
|
76
|
-
if (!fastify.funcs) {
|
|
77
|
-
fastify.addHook('onRequest', async (req) => {
|
|
78
|
-
// req.funcs = fastify;
|
|
79
|
-
if (!req.user && req.session?.passport?.user) {
|
|
80
|
-
const { user } = req.session?.passport || {};
|
|
81
|
-
req.user = user;
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
// fastify.decorateRequest('funcs', fastify);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
53
|
// plugins / utils / funcs
|
|
88
54
|
policyPlugin(fastify);
|
|
89
55
|
redisPlugin(fastify);
|
|
@@ -92,6 +58,7 @@ async function plugin(fastify, opt) {
|
|
|
92
58
|
crudPlugin(fastify, opt);
|
|
93
59
|
utilPlugin(fastify, opt);
|
|
94
60
|
cronPlugin(fastify, opt);
|
|
61
|
+
loggerPlugin(fastify, opt);
|
|
95
62
|
|
|
96
63
|
// routes / api
|
|
97
64
|
cronRoutes(fastify, opt);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/fastify-table",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.72",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "core-plugins",
|
|
6
6
|
"main": "index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@fastify/sensible": "^5.0.0",
|
|
22
22
|
"@fastify/url-data": "^5.4.0",
|
|
23
|
-
"@opengis/fastify-hb": "^1.4.
|
|
23
|
+
"@opengis/fastify-hb": "^1.4.8",
|
|
24
24
|
"fastify": "^4.26.1",
|
|
25
25
|
"fastify-plugin": "^4.0.0",
|
|
26
26
|
"ioredis": "^5.3.2",
|
|
@@ -20,7 +20,7 @@ const generator = () => () => {
|
|
|
20
20
|
const {
|
|
21
21
|
dir = 'log', interval = '1d', compress = 'gzip', // maxFiles = 90, local: teeToStdout,
|
|
22
22
|
} = config?.log || {};
|
|
23
|
-
function createFileStream({ level }) {
|
|
23
|
+
function createFileStream({ level, status }) {
|
|
24
24
|
console.log(dir, level, generator({ interval })(), interval, compress);
|
|
25
25
|
/* const params = {
|
|
26
26
|
maxFiles, // logs to save limit
|
|
@@ -36,7 +36,7 @@ function createFileStream({ level }) {
|
|
|
36
36
|
return createStream(generator({ interval }), params); */
|
|
37
37
|
const dt = new Date().toISOString().split('T')[0];
|
|
38
38
|
|
|
39
|
-
const fileName = `${dir}/${level}/${dt}.log`;
|
|
39
|
+
const fileName = `${dir}/${level}/${dt}${status ? `_${status}` : ''}.log`;
|
|
40
40
|
|
|
41
41
|
fs.mkdirSync(`${dir}/${level}`, { recursive: true });
|
|
42
42
|
|
|
@@ -60,12 +60,27 @@ export default function transportTarget() {
|
|
|
60
60
|
const dt = new Date().toISOString().split('T')[0];
|
|
61
61
|
source.on('data', (obj) => {
|
|
62
62
|
if (['incoming request', 'request completed'].includes(obj.msg)) return;
|
|
63
|
+
|
|
63
64
|
// console.log(obj)
|
|
64
65
|
const file = obj.msg?.logfolder || obj.logfolder;
|
|
65
66
|
|
|
66
67
|
const level = file || labels[obj.level];
|
|
67
68
|
const lvl = level + dt;
|
|
68
69
|
|
|
70
|
+
// write error status
|
|
71
|
+
if (obj.err?.status) {
|
|
72
|
+
const status = obj.err?.status;
|
|
73
|
+
streams[status] = streams[status] || createFileStream({ level, status });
|
|
74
|
+
streams[status].write(`${JSON.stringify({ ...obj, level: labels[obj.level] })}\n`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// write error type
|
|
78
|
+
if (obj.err?.type) {
|
|
79
|
+
const status = obj.err?.type;
|
|
80
|
+
streams[status] = streams[status] || createFileStream({ level, status });
|
|
81
|
+
streams[status].write(`${JSON.stringify({ ...obj, level: labels[obj.level] })}\n`);
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
if (streams[lvl]?.closed) { streams[lvl].destroy(); }
|
|
70
85
|
if (streams[lvl]?.destroyed) { delete streams[lvl]; }
|
|
71
86
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import config from '../../../config.js';
|
|
2
|
+
import applyHookSync from '../hook/funcs/applyHookSync.js';
|
|
3
|
+
import errorStatus from './errorStatus.js';
|
|
4
|
+
|
|
5
|
+
const defaultMessage = {
|
|
6
|
+
602: 'Порушення цілісності бази даних',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function errorMessage(error) {
|
|
10
|
+
const hook = applyHookSync('errorMessage', error);
|
|
11
|
+
if (hook) return hook;
|
|
12
|
+
|
|
13
|
+
if (error.routine === 'exec_stmt_raise' && error.file === 'pl_exec.c') {
|
|
14
|
+
return error.message;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// messgae status
|
|
18
|
+
const status = errorStatus(error);
|
|
19
|
+
if (config.errorMessage?.[status]) return config.errorMessage[status.toString()];
|
|
20
|
+
if (defaultMessage[status]) return defaultMessage[status];
|
|
21
|
+
|
|
22
|
+
return config.local ? error.toString() : (config.errorMessage?.[500] || 'ServerError');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default errorMessage;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import applyHookSync from '../hook/funcs/applyHookSync.js';
|
|
2
|
+
|
|
3
|
+
function errorStatus(error) {
|
|
4
|
+
const hook = applyHookSync('errorStatus', error);
|
|
5
|
+
if (hook) return hook;
|
|
6
|
+
|
|
7
|
+
if (error.routine === 'exec_stmt_raise' && error.file === 'pl_exec.c') {
|
|
8
|
+
return 601;
|
|
9
|
+
}
|
|
10
|
+
if (error.routine === 'ExecConstraints') {
|
|
11
|
+
return 602;
|
|
12
|
+
}
|
|
13
|
+
if (error.type === 'DatabaseError') {
|
|
14
|
+
return 600;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return 500;
|
|
18
|
+
}
|
|
19
|
+
export default errorStatus;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import errorStatus from './errorStatus.js';
|
|
2
|
+
|
|
1
3
|
function getHooks() {
|
|
2
4
|
return {
|
|
3
5
|
logMethod(inputArgs, method) {
|
|
@@ -6,6 +8,8 @@ function getHooks() {
|
|
|
6
8
|
if (inputArgs?.length === 2 && inputArgs[1]?.originalUrl) {
|
|
7
9
|
const req = inputArgs[1];
|
|
8
10
|
const err = inputArgs[0]?.stack ? inputArgs[0] : undefined;
|
|
11
|
+
if (err) err.status = errorStatus(err);
|
|
12
|
+
|
|
9
13
|
return method.apply(this, [{ req, err }, err ? inputArgs[0].toString() : inputArgs[0]]);
|
|
10
14
|
}
|
|
11
15
|
|
|
@@ -19,12 +19,6 @@ const options = {
|
|
|
19
19
|
transport: {
|
|
20
20
|
targets: [{
|
|
21
21
|
target: './createFileStream.js', // path.resolve('utils/createFileStream.js')
|
|
22
|
-
}, {
|
|
23
|
-
// Use target: 'pino/file' with STDOUT descriptor 1 to write
|
|
24
|
-
// logs without any change.
|
|
25
|
-
level: 'error',
|
|
26
|
-
target: 'pino/file',
|
|
27
|
-
options: { destination: 1 },
|
|
28
22
|
}],
|
|
29
23
|
},
|
|
30
24
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import errorMessage from './errorMessage.js';
|
|
2
|
+
|
|
3
|
+
async function plugin(fastify) {
|
|
4
|
+
fastify.setErrorHandler(async (error, request, reply) => {
|
|
5
|
+
// validation not error
|
|
6
|
+
if (error.validation) {
|
|
7
|
+
request.log.warn(request, { code: error?.code, status: 422, error: error.toString() });
|
|
8
|
+
return reply.status(422).send(error.toString());
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// logger
|
|
12
|
+
request.log.error(error, request);
|
|
13
|
+
console.error({ msg: error.message, where: error.where, stack: error.stack });
|
|
14
|
+
|
|
15
|
+
// errorMessage
|
|
16
|
+
const msg = errorMessage(error);
|
|
17
|
+
|
|
18
|
+
return reply.status(error.statusCode || 500).send(msg);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export default plugin;
|
|
@@ -23,7 +23,7 @@ export default async function deleteCrud(req) {
|
|
|
23
23
|
}
|
|
24
24
|
const loadTemplate = await getTemplate('table', del);
|
|
25
25
|
|
|
26
|
-
const { table } = loadTemplate || hookData || req.params || {};
|
|
26
|
+
const { table } = loadTemplate || hookData || tokenData || req.params || {};
|
|
27
27
|
|
|
28
28
|
if (!table) return { status: 404, message: 'table is required' };
|
|
29
29
|
if (!id) return { status: 404, message: 'id is required' };
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
|
|
5
5
|
export default async function insert(req) {
|
|
6
6
|
const {
|
|
7
|
-
user, params = {}, body = {},
|
|
7
|
+
user = {}, params = {}, body = {},
|
|
8
8
|
} = req || {};
|
|
9
9
|
if (!user) return { message: 'access restricted', status: 403 };
|
|
10
10
|
const hookData = await applyHook('preInsert', { table: params?.table, user });
|
|
@@ -12,7 +12,7 @@ export default async function insert(req) {
|
|
|
12
12
|
return { message: hookData?.message, status: hookData?.status };
|
|
13
13
|
}
|
|
14
14
|
const tokenData = await getToken({
|
|
15
|
-
uid: user
|
|
15
|
+
uid: user?.uid, token: params.table, mode: 'a', json: 1,
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
const { form, table: add } = hookData || tokenData || (config.auth?.disable ? req.params : {});
|
|
@@ -42,10 +42,8 @@ export default async function insert(req) {
|
|
|
42
42
|
return { message: 'Дані містять заборонені символи. Приберіть їх та спробуйте ще раз', status: 409 };
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const uid = user?.uid;
|
|
46
|
-
|
|
47
45
|
if (![add, table].includes('admin.users')) {
|
|
48
|
-
Object.assign(body, { uid, editor_id: uid });
|
|
46
|
+
Object.assign(body, { uid: user?.uid, editor_id: user?.uid });
|
|
49
47
|
}
|
|
50
48
|
if (tokenData?.obj) {
|
|
51
49
|
const objData = tokenData.obj?.split('#').reduce((p, el) => ({ ...p, [el.split('=')[0]]: el.split('=')[1] }), {}) || {};
|
|
@@ -53,7 +51,7 @@ export default async function insert(req) {
|
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
const res = await dataInsert({
|
|
56
|
-
table: loadTemplate?.table || table, data: body, uid,
|
|
54
|
+
table: loadTemplate?.table || table, data: body, uid: user?.uid,
|
|
57
55
|
});
|
|
58
56
|
if (!res) return { message: 'nothing added ' };
|
|
59
57
|
|
|
@@ -69,7 +67,7 @@ export default async function insert(req) {
|
|
|
69
67
|
const objId = body[formData[key].parent_id] || req.body?.id;
|
|
70
68
|
const extraRows = await Promise.all(body[key].map(async (row) => {
|
|
71
69
|
const extraRes = await dataInsert({
|
|
72
|
-
table: formData[key].table, data: { ...row, [formData[key].parent_id]: objId }, uid,
|
|
70
|
+
table: formData[key].table, data: { ...row, [formData[key].parent_id]: objId }, uid: user?.uid,
|
|
73
71
|
});
|
|
74
72
|
return extraRes?.rows?.[0];
|
|
75
73
|
}));
|
|
@@ -64,7 +64,7 @@ export default async function loggerFile({
|
|
|
64
64
|
return buffer;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
reply.headers({ 'Content-type': 'text/plain' });
|
|
67
|
+
reply.headers({ 'Content-type': 'text/plain; charset=UTF-8' });
|
|
68
68
|
return stat.size > limit && lines.length > 1
|
|
69
69
|
? lines.reverse().slice(0, -1).join('\n')
|
|
70
70
|
: lines.reverse().join('\n');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import loggerFile from './controllers/logger.file.js';
|
|
2
|
+
|
|
2
3
|
// import loggerTest from './controllers/logger.test.api.js';
|
|
3
4
|
|
|
4
5
|
const loggerSchema = {
|
|
@@ -11,7 +12,6 @@ const loggerSchema = {
|
|
|
11
12
|
|
|
12
13
|
async function plugin(fastify) {
|
|
13
14
|
fastify.get('/logger-file/*', { schema: loggerSchema }, loggerFile);
|
|
14
|
-
// fastify.get('/logger-test', {}, loggerTest);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export default plugin;
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
const maxLimit = 100;
|
|
7
7
|
export default async function dataAPI(req) {
|
|
8
8
|
const {
|
|
9
|
-
pg, params, query = {}, user,
|
|
9
|
+
pg, params, query = {}, user = {},
|
|
10
10
|
} = req;
|
|
11
11
|
|
|
12
12
|
const time = Date.now();
|
|
13
13
|
|
|
14
|
-
const uid =
|
|
14
|
+
const { uid } = user;
|
|
15
15
|
|
|
16
16
|
const hookData = await applyHook('preData', {
|
|
17
17
|
table: params?.table, id: params?.id, user,
|
package/utils.js
CHANGED
|
@@ -46,6 +46,7 @@ import checkXSS from './server/plugins/policy/funcs/checkXSS.js';
|
|
|
46
46
|
|
|
47
47
|
// hook
|
|
48
48
|
import applyHook from './server/plugins/hook/funcs/applyHook.js';
|
|
49
|
+
import applyHookSync from './server/plugins/hook/funcs/applyHookSync.js';
|
|
49
50
|
import addHook from './server/plugins/hook/funcs/addHook.js';
|
|
50
51
|
import execMigrations from './server/plugins/migration/funcs/exec.migrations.js';
|
|
51
52
|
|
|
@@ -79,6 +80,7 @@ export {
|
|
|
79
80
|
// hook
|
|
80
81
|
addHook,
|
|
81
82
|
applyHook,
|
|
83
|
+
applyHookSync,
|
|
82
84
|
|
|
83
85
|
// template
|
|
84
86
|
getTemplate,
|