@grandlinex/kernel 0.32.10 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,57 +1,69 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [v0.32.10] - 2023-10-06
4
+ ## [1.0.0] - 2024-07-30
5
+ ### Added
6
+ - Add EntitySchemaExtender
7
+ - Add BaseUserAgent
8
+ ### Changed
9
+ - Update Deps
10
+
11
+ ## [0.32.11] - 2024-07-13
12
+ ### Changed
13
+ - Update Deps
14
+ - Error Handling for BaseApiAction
15
+
16
+ ## [0.32.10] - 2023-10-06
5
17
  ### Changed
6
18
  - Breaking Change: BaseApiAction now use XActionEvent
7
19
 
8
- ## [v0.31.1] - 2023-07-07
20
+ ## [0.31.1] - 2023-07-07
9
21
  ### Added
10
22
  - @/token pass the token body to jwt generator function
11
23
  ### Fixed
12
24
  - Deal with code smells
13
25
 
14
- ## [v0.31.0] - 2023-07-06
26
+ ## [0.31.0] - 2023-07-06
15
27
  ### Added
16
28
  - JTW Token now can be extended with custom payload
17
29
  - Update to core 0.31.0
18
30
  - Add forceDebug flag for BaseAction to force Server-Timing in production mode
19
31
 
20
- ## [v0.30.0] - 2023-04-03
32
+ ## [0.30.0] - 2023-04-03
21
33
  ### Added
22
34
  - Switch to ESM
23
35
  - Update to core 0.30.0
24
36
 
25
- ## [v0.27.1] - 2023-01-26
37
+ ## [0.27.1] - 2023-01-26
26
38
  ### Added
27
39
  - Add raw body field for express calls
28
40
  - change BaseEndpoint variables from private to protected
29
41
 
30
- ## [v0.25.2] - 2022-08-07
42
+ ## [0.25.2] - 2022-08-07
31
43
  ### Added
32
44
  - Add express timing api in dev mode
33
45
 
34
- ## [v0.25.0] - 2022-07-23
46
+ ## [0.25.0] - 2022-07-23
35
47
  ### Changed
36
48
  - Update to core 0.25.0
37
49
 
38
50
 
39
- ## [v0.18.0] - 2022-01-10
51
+ ## [0.18.0] - 2022-01-10
40
52
  ### Changed
41
53
  - Update to core 0.18.0
42
54
 
43
- ## [v0.17.0] - 2022-01-03
55
+ ## [0.17.0] - 2022-01-03
44
56
  ### Changed
45
57
  - Update to core 0.17.1
46
58
  - Using db prefab for kernel db
47
59
 
48
- ## [v0.16.2] - 2021-12-17
60
+ ## [0.16.2] - 2021-12-17
49
61
 
50
62
  ### Changed
51
63
  - Update Db Bundles with search bug
52
64
 
53
65
 
54
- ## [v0.16.1] - 2021-12-07
66
+ ## [0.16.1] - 2021-12-07
55
67
 
56
68
  ### Changed
57
69
  - Update to core 0.16.2
@@ -18,7 +18,7 @@ class KernelModule extends BaseKernelModule_js_1.default {
18
18
  this.addService(new core_1.OfflineService(this));
19
19
  const endpoint = new KernelEndpoint_js_1.default('api', this, this.getKernel().getAppServerPort());
20
20
  this.setPresenter(endpoint);
21
- await this.getKernel().triggerFunction('load');
21
+ await this.getKernel().triggerEvent('load');
22
22
  }
23
23
  }
24
24
  exports.default = KernelModule;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ActionMode = void 0;
4
4
  const core_1 = require("@grandlinex/core");
5
5
  const index_js_1 = require("./timing/index.js");
6
+ const BaseUserAgent_js_1 = require("./BaseUserAgent.js");
6
7
  var ActionMode;
7
8
  (function (ActionMode) {
8
9
  ActionMode[ActionMode["DEFAULT"] = 0] = "DEFAULT";
@@ -32,34 +33,64 @@ class BaseAction extends core_1.CoreAction {
32
33
  }
33
34
  if (this.mode === ActionMode.DMZ) {
34
35
  auth.stop();
35
- await this.handler({
36
- res,
37
- req,
38
- next,
39
- data: null,
40
- extension,
41
- });
36
+ try {
37
+ await this.handler({
38
+ res,
39
+ req,
40
+ next,
41
+ data: null,
42
+ extension,
43
+ agent: new BaseUserAgent_js_1.BaseUserAgent(req),
44
+ });
45
+ }
46
+ catch (e) {
47
+ this.error(e);
48
+ this.error(e?.message);
49
+ if (!res.headersSent) {
50
+ res.sendStatus(500);
51
+ }
52
+ }
42
53
  return;
43
54
  }
44
55
  const dat = await cc.bearerTokenValidation(req);
45
56
  auth.stop();
46
57
  if (dat && typeof dat !== 'number') {
47
- await this.handler({
48
- res,
49
- req,
50
- next,
51
- data: dat,
52
- extension,
53
- });
58
+ try {
59
+ await this.handler({
60
+ res,
61
+ req,
62
+ next,
63
+ data: dat,
64
+ extension,
65
+ agent: new BaseUserAgent_js_1.BaseUserAgent(req),
66
+ });
67
+ }
68
+ catch (e) {
69
+ this.error(e);
70
+ this.error(e?.message);
71
+ if (!res.headersSent) {
72
+ res.sendStatus(500);
73
+ }
74
+ }
54
75
  }
55
76
  else if (this.mode === ActionMode.DMZ_WITH_USER) {
56
- await this.handler({
57
- res,
58
- req,
59
- next,
60
- data: null,
61
- extension,
62
- });
77
+ try {
78
+ await this.handler({
79
+ res,
80
+ req,
81
+ next,
82
+ data: null,
83
+ extension,
84
+ agent: new BaseUserAgent_js_1.BaseUserAgent(req),
85
+ });
86
+ }
87
+ catch (e) {
88
+ this.error(e);
89
+ this.error(e?.message);
90
+ if (!res.headersSent) {
91
+ res.sendStatus(500);
92
+ }
93
+ }
63
94
  }
64
95
  else if (dat) {
65
96
  res.sendStatus(dat);
@@ -1,5 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  import express, { Express } from 'express';
4
2
  import http from 'http';
5
3
  import { CorePresenter, IDataBase } from '@grandlinex/core';
@@ -11,6 +9,7 @@ export default abstract class BaseEndpoint<K extends IKernel = IKernel, T extend
11
9
  protected httpServer: http.Server;
12
10
  protected port: number;
13
11
  constructor(chanel: string, module: IBaseKernelModule<any, any, any, any>, port: number);
12
+ private setAppHeader;
14
13
  appServerOverride(app: Express): void;
15
14
  start(): Promise<boolean>;
16
15
  stop(): Promise<boolean>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.keepRawBody = void 0;
6
+ exports.keepRawBody = keepRawBody;
7
7
  const express_1 = __importDefault(require("express"));
8
8
  const http_1 = __importDefault(require("http"));
9
9
  const body_parser_1 = __importDefault(require("body-parser"));
@@ -20,7 +20,6 @@ function keepRawBody(req, res, buf, encoding) {
20
20
  }
21
21
  }
22
22
  }
23
- exports.keepRawBody = keepRawBody;
24
23
  class BaseEndpoint extends core_1.CorePresenter {
25
24
  constructor(chanel, module, port) {
26
25
  super(`endpoint-${chanel}`, module);
@@ -28,10 +27,18 @@ class BaseEndpoint extends core_1.CorePresenter {
28
27
  this.appServer = (0, express_1.default)();
29
28
  this.appServer.use(body_parser_1.default.json({ verify: keepRawBody }));
30
29
  this.httpServer = http_1.default.createServer(this.appServer);
30
+ this.setAppHeader();
31
+ }
32
+ setAppHeader() {
33
+ this.appServer.use((req, res, next) => {
34
+ res.setHeader('X-Powered-By', 'GrandLineX');
35
+ next();
36
+ });
31
37
  }
32
38
  appServerOverride(app) {
33
39
  this.appServer = app;
34
40
  this.httpServer = http_1.default.createServer(this.appServer);
41
+ this.setAppHeader();
35
42
  }
36
43
  start() {
37
44
  return new Promise((resolve) => {
@@ -0,0 +1,30 @@
1
+ import { XRequest } from '../lib/express.js';
2
+ export declare enum BrowserENUM {
3
+ Edge = "edg",
4
+ Opera = "opr",
5
+ Chrome = "chrome",
6
+ Firefox = "firefox",
7
+ Safari = "safari",
8
+ Mozilla = "mozilla",
9
+ Gecko = "gecko",
10
+ OculusBrowser = "oculusbrowser"
11
+ }
12
+ /**
13
+ * UserAgent
14
+ */
15
+ export declare class BaseUserAgent {
16
+ private readonly raw;
17
+ private readonly version;
18
+ constructor(req: XRequest);
19
+ getBrowser(): "Opera" | "Edge" | "Firefox" | "OculusBrowser" | "Chrome" | "Safari" | "Mozilla" | "Gecko" | "Unknown";
20
+ getChromeVersion(): number;
21
+ getEdgeVersion(): number;
22
+ getFirefoxVersion(): number;
23
+ getGeckoVersion(): number;
24
+ getMozillaVersion(): number;
25
+ getOculusVersion(): number;
26
+ getOperaVersion(): number;
27
+ getSafariVersion(): number;
28
+ getXVersion(x: string): number;
29
+ getRaw(): string;
30
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseUserAgent = exports.BrowserENUM = void 0;
4
+ var BrowserENUM;
5
+ (function (BrowserENUM) {
6
+ BrowserENUM["Edge"] = "edg";
7
+ BrowserENUM["Opera"] = "opr";
8
+ BrowserENUM["Chrome"] = "chrome";
9
+ BrowserENUM["Firefox"] = "firefox";
10
+ BrowserENUM["Safari"] = "safari";
11
+ BrowserENUM["Mozilla"] = "mozilla";
12
+ BrowserENUM["Gecko"] = "gecko";
13
+ BrowserENUM["OculusBrowser"] = "oculusbrowser";
14
+ })(BrowserENUM || (exports.BrowserENUM = BrowserENUM = {}));
15
+ /**
16
+ * UserAgent
17
+ */
18
+ class BaseUserAgent {
19
+ constructor(req) {
20
+ this.raw = req.headers['user-agent'] || '';
21
+ this.version = new Map();
22
+ const parts = this.raw.matchAll(/[A-Za-z]*\/[0-9.]*/gm);
23
+ for (const part of parts) {
24
+ const [name, version] = part[0].split('/');
25
+ const [release] = version.split('.');
26
+ this.version.set(name.toLowerCase(), parseInt(release, 10));
27
+ }
28
+ }
29
+ getBrowser() {
30
+ if (this.version.has(BrowserENUM.Opera)) {
31
+ return 'Opera';
32
+ }
33
+ if (this.version.has(BrowserENUM.Edge)) {
34
+ return 'Edge';
35
+ }
36
+ if (this.version.has(BrowserENUM.Firefox)) {
37
+ return 'Firefox';
38
+ }
39
+ if (this.version.has(BrowserENUM.OculusBrowser)) {
40
+ return 'OculusBrowser';
41
+ }
42
+ if (this.version.has(BrowserENUM.Chrome)) {
43
+ return 'Chrome';
44
+ }
45
+ if (this.version.has(BrowserENUM.Safari)) {
46
+ return 'Safari';
47
+ }
48
+ if (this.version.has(BrowserENUM.Mozilla)) {
49
+ return 'Mozilla';
50
+ }
51
+ if (this.version.has(BrowserENUM.Gecko)) {
52
+ return 'Gecko';
53
+ }
54
+ return 'Unknown';
55
+ }
56
+ getChromeVersion() {
57
+ return this.version.get(BrowserENUM.Chrome) || 0;
58
+ }
59
+ getEdgeVersion() {
60
+ return this.version.get(BrowserENUM.Edge) || 0;
61
+ }
62
+ getFirefoxVersion() {
63
+ return this.version.get(BrowserENUM.Firefox) || 0;
64
+ }
65
+ getGeckoVersion() {
66
+ return this.version.get(BrowserENUM.Gecko) || 0;
67
+ }
68
+ getMozillaVersion() {
69
+ return this.version.get(BrowserENUM.Mozilla) || 0;
70
+ }
71
+ getOculusVersion() {
72
+ return this.version.get(BrowserENUM.OculusBrowser) || 0;
73
+ }
74
+ getOperaVersion() {
75
+ return this.version.get(BrowserENUM.Opera) || 0;
76
+ }
77
+ getSafariVersion() {
78
+ return this.version.get(BrowserENUM.Safari) || 0;
79
+ }
80
+ getXVersion(x) {
81
+ return this.version.get(x) || 0;
82
+ }
83
+ getRaw() {
84
+ return this.raw;
85
+ }
86
+ }
87
+ exports.BaseUserAgent = BaseUserAgent;
@@ -5,6 +5,7 @@ import BaseKernelModule from './BaseKernelModule.js';
5
5
  import BaseApiAction from './BaseApiAction.js';
6
6
  import BaseAuthProvider from './BaseAuthProvider.js';
7
7
  export * from './BaseAction.js';
8
+ export * from './BaseUserAgent.js';
8
9
  export * from './BaseAuthProvider.js';
9
10
  export * from './timing/index.js';
10
11
  export { BaseLoopService, BaseAuthProvider, BaseKernelModule, BaseService, BaseApiAction, BaseEndpoint, BaseElement, BaseCache, BaseAction, BaseClient, BaseBridge, keepRawBody, ActionMode, };
@@ -50,5 +50,6 @@ exports.BaseApiAction = BaseApiAction_js_1.default;
50
50
  const BaseAuthProvider_js_1 = __importDefault(require("./BaseAuthProvider.js"));
51
51
  exports.BaseAuthProvider = BaseAuthProvider_js_1.default;
52
52
  __exportStar(require("./BaseAction.js"), exports);
53
+ __exportStar(require("./BaseUserAgent.js"), exports);
53
54
  __exportStar(require("./BaseAuthProvider.js"), exports);
54
55
  __exportStar(require("./timing/index.js"), exports);
@@ -0,0 +1,11 @@
1
+ import { CoreEntity } from '@grandlinex/core';
2
+ import { SKey, SSchemaEl } from '@grandlinex/swagger-mate';
3
+ export default class EntitySchemaExtender {
4
+ static extendEntitySchema(entity: CoreEntity, ...options: {
5
+ key: string;
6
+ list?: boolean;
7
+ entity?: CoreEntity;
8
+ schema?: SSchemaEl;
9
+ required?: boolean;
10
+ }[]): SKey<SSchemaEl>;
11
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@grandlinex/core");
4
+ const swagger_mate_1 = require("@grandlinex/swagger-mate");
5
+ class EntitySchemaExtender {
6
+ static extendEntitySchema(entity, ...options) {
7
+ const meta = (0, core_1.getEntityMeta)(entity);
8
+ if (meta) {
9
+ const schema = swagger_mate_1.SPathUtil.schemaEntryGen(entity)[meta.name];
10
+ if (schema && !(0, swagger_mate_1.isSwaggerRef)(schema) && schema.properties) {
11
+ for (const option of options) {
12
+ if (option.schema) {
13
+ if (option.list) {
14
+ schema.properties[option.key] = {
15
+ type: 'array',
16
+ items: option.schema,
17
+ };
18
+ }
19
+ else {
20
+ schema.properties[option.key] = option.schema;
21
+ }
22
+ }
23
+ else if (option.entity) {
24
+ const eMeta = (0, core_1.getEntityMeta)(option.entity);
25
+ if (eMeta) {
26
+ const scheme = swagger_mate_1.SPathUtil.schemaEntryGen(option.entity)[eMeta.name];
27
+ if (option.list) {
28
+ schema.properties[option.key] = {
29
+ type: 'array',
30
+ items: scheme,
31
+ };
32
+ }
33
+ else {
34
+ schema.properties[option.key] = scheme;
35
+ }
36
+ }
37
+ }
38
+ if (option.required) {
39
+ schema.required = [...(schema.required || []), option.key];
40
+ }
41
+ }
42
+ }
43
+ return {
44
+ [meta.name]: schema,
45
+ };
46
+ }
47
+ return {};
48
+ }
49
+ }
50
+ exports.default = EntitySchemaExtender;
@@ -1,5 +1,5 @@
1
1
  import express from 'express';
2
- import { IExtensionInterface, JwtToken } from '../classes/index.js';
2
+ import { BaseUserAgent, IExtensionInterface, JwtToken } from '../classes/index.js';
3
3
  export type XRequest = express.Request & {
4
4
  rawBody?: string | null;
5
5
  };
@@ -11,4 +11,5 @@ export type XActionEvent<G = JwtToken | null> = {
11
11
  next: XNextFc;
12
12
  data: G;
13
13
  extension: IExtensionInterface;
14
+ agent: BaseUserAgent;
14
15
  };
@@ -2,7 +2,9 @@ import { ICoreAction, ICoreBridge, ICoreCache, ICoreCClient, ICoreClient, ICoreE
2
2
  import express from 'express';
3
3
  import * as jwt from 'jsonwebtoken';
4
4
  import { IAuthProvider, JwtExtend, JwtToken } from '../classes/index.js';
5
+ import EntitySchemaExtender from './EntitySchemaExtender.js';
5
6
  import { XActionEvent, XRequest } from './express.js';
7
+ export { EntitySchemaExtender };
6
8
  export type ActionTypes = 'POST' | 'GET' | 'USE' | 'PATCH' | 'DELETE';
7
9
  export interface ICClient<T extends JwtExtend = JwtExtend> extends ICoreCClient {
8
10
  setAuthProvider(provider: IAuthProvider<T>): boolean;
@@ -1,2 +1,8 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EntitySchemaExtender = void 0;
7
+ const EntitySchemaExtender_js_1 = __importDefault(require("./EntitySchemaExtender.js"));
8
+ exports.EntitySchemaExtender = EntitySchemaExtender_js_1.default;
@@ -13,6 +13,6 @@ export default class KernelModule extends BaseKernelModule {
13
13
  this.addService(new OfflineService(this));
14
14
  const endpoint = new KernelEndpoint('api', this, this.getKernel().getAppServerPort());
15
15
  this.setPresenter(endpoint);
16
- await this.getKernel().triggerFunction('load');
16
+ await this.getKernel().triggerEvent('load');
17
17
  }
18
18
  }
@@ -1,5 +1,6 @@
1
1
  import { CoreAction } from '@grandlinex/core';
2
2
  import { ExpressServerTiming } from './timing/index.js';
3
+ import { BaseUserAgent } from './BaseUserAgent.js';
3
4
  export var ActionMode;
4
5
  (function (ActionMode) {
5
6
  ActionMode[ActionMode["DEFAULT"] = 0] = "DEFAULT";
@@ -29,34 +30,64 @@ export default class BaseAction extends CoreAction {
29
30
  }
30
31
  if (this.mode === ActionMode.DMZ) {
31
32
  auth.stop();
32
- await this.handler({
33
- res,
34
- req,
35
- next,
36
- data: null,
37
- extension,
38
- });
33
+ try {
34
+ await this.handler({
35
+ res,
36
+ req,
37
+ next,
38
+ data: null,
39
+ extension,
40
+ agent: new BaseUserAgent(req),
41
+ });
42
+ }
43
+ catch (e) {
44
+ this.error(e);
45
+ this.error(e?.message);
46
+ if (!res.headersSent) {
47
+ res.sendStatus(500);
48
+ }
49
+ }
39
50
  return;
40
51
  }
41
52
  const dat = await cc.bearerTokenValidation(req);
42
53
  auth.stop();
43
54
  if (dat && typeof dat !== 'number') {
44
- await this.handler({
45
- res,
46
- req,
47
- next,
48
- data: dat,
49
- extension,
50
- });
55
+ try {
56
+ await this.handler({
57
+ res,
58
+ req,
59
+ next,
60
+ data: dat,
61
+ extension,
62
+ agent: new BaseUserAgent(req),
63
+ });
64
+ }
65
+ catch (e) {
66
+ this.error(e);
67
+ this.error(e?.message);
68
+ if (!res.headersSent) {
69
+ res.sendStatus(500);
70
+ }
71
+ }
51
72
  }
52
73
  else if (this.mode === ActionMode.DMZ_WITH_USER) {
53
- await this.handler({
54
- res,
55
- req,
56
- next,
57
- data: null,
58
- extension,
59
- });
74
+ try {
75
+ await this.handler({
76
+ res,
77
+ req,
78
+ next,
79
+ data: null,
80
+ extension,
81
+ agent: new BaseUserAgent(req),
82
+ });
83
+ }
84
+ catch (e) {
85
+ this.error(e);
86
+ this.error(e?.message);
87
+ if (!res.headersSent) {
88
+ res.sendStatus(500);
89
+ }
90
+ }
60
91
  }
61
92
  else if (dat) {
62
93
  res.sendStatus(dat);
@@ -1,5 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
1
  import express, { Express } from 'express';
4
2
  import http from 'http';
5
3
  import { CorePresenter, IDataBase } from '@grandlinex/core';
@@ -11,6 +9,7 @@ export default abstract class BaseEndpoint<K extends IKernel = IKernel, T extend
11
9
  protected httpServer: http.Server;
12
10
  protected port: number;
13
11
  constructor(chanel: string, module: IBaseKernelModule<any, any, any, any>, port: number);
12
+ private setAppHeader;
14
13
  appServerOverride(app: Express): void;
15
14
  start(): Promise<boolean>;
16
15
  stop(): Promise<boolean>;
@@ -21,10 +21,18 @@ export default class BaseEndpoint extends CorePresenter {
21
21
  this.appServer = express();
22
22
  this.appServer.use(parser.json({ verify: keepRawBody }));
23
23
  this.httpServer = http.createServer(this.appServer);
24
+ this.setAppHeader();
25
+ }
26
+ setAppHeader() {
27
+ this.appServer.use((req, res, next) => {
28
+ res.setHeader('X-Powered-By', 'GrandLineX');
29
+ next();
30
+ });
24
31
  }
25
32
  appServerOverride(app) {
26
33
  this.appServer = app;
27
34
  this.httpServer = http.createServer(this.appServer);
35
+ this.setAppHeader();
28
36
  }
29
37
  start() {
30
38
  return new Promise((resolve) => {
@@ -0,0 +1,30 @@
1
+ import { XRequest } from '../lib/express.js';
2
+ export declare enum BrowserENUM {
3
+ Edge = "edg",
4
+ Opera = "opr",
5
+ Chrome = "chrome",
6
+ Firefox = "firefox",
7
+ Safari = "safari",
8
+ Mozilla = "mozilla",
9
+ Gecko = "gecko",
10
+ OculusBrowser = "oculusbrowser"
11
+ }
12
+ /**
13
+ * UserAgent
14
+ */
15
+ export declare class BaseUserAgent {
16
+ private readonly raw;
17
+ private readonly version;
18
+ constructor(req: XRequest);
19
+ getBrowser(): "Opera" | "Edge" | "Firefox" | "OculusBrowser" | "Chrome" | "Safari" | "Mozilla" | "Gecko" | "Unknown";
20
+ getChromeVersion(): number;
21
+ getEdgeVersion(): number;
22
+ getFirefoxVersion(): number;
23
+ getGeckoVersion(): number;
24
+ getMozillaVersion(): number;
25
+ getOculusVersion(): number;
26
+ getOperaVersion(): number;
27
+ getSafariVersion(): number;
28
+ getXVersion(x: string): number;
29
+ getRaw(): string;
30
+ }
@@ -0,0 +1,83 @@
1
+ export var BrowserENUM;
2
+ (function (BrowserENUM) {
3
+ BrowserENUM["Edge"] = "edg";
4
+ BrowserENUM["Opera"] = "opr";
5
+ BrowserENUM["Chrome"] = "chrome";
6
+ BrowserENUM["Firefox"] = "firefox";
7
+ BrowserENUM["Safari"] = "safari";
8
+ BrowserENUM["Mozilla"] = "mozilla";
9
+ BrowserENUM["Gecko"] = "gecko";
10
+ BrowserENUM["OculusBrowser"] = "oculusbrowser";
11
+ })(BrowserENUM || (BrowserENUM = {}));
12
+ /**
13
+ * UserAgent
14
+ */
15
+ export class BaseUserAgent {
16
+ constructor(req) {
17
+ this.raw = req.headers['user-agent'] || '';
18
+ this.version = new Map();
19
+ const parts = this.raw.matchAll(/[A-Za-z]*\/[0-9.]*/gm);
20
+ for (const part of parts) {
21
+ const [name, version] = part[0].split('/');
22
+ const [release] = version.split('.');
23
+ this.version.set(name.toLowerCase(), parseInt(release, 10));
24
+ }
25
+ }
26
+ getBrowser() {
27
+ if (this.version.has(BrowserENUM.Opera)) {
28
+ return 'Opera';
29
+ }
30
+ if (this.version.has(BrowserENUM.Edge)) {
31
+ return 'Edge';
32
+ }
33
+ if (this.version.has(BrowserENUM.Firefox)) {
34
+ return 'Firefox';
35
+ }
36
+ if (this.version.has(BrowserENUM.OculusBrowser)) {
37
+ return 'OculusBrowser';
38
+ }
39
+ if (this.version.has(BrowserENUM.Chrome)) {
40
+ return 'Chrome';
41
+ }
42
+ if (this.version.has(BrowserENUM.Safari)) {
43
+ return 'Safari';
44
+ }
45
+ if (this.version.has(BrowserENUM.Mozilla)) {
46
+ return 'Mozilla';
47
+ }
48
+ if (this.version.has(BrowserENUM.Gecko)) {
49
+ return 'Gecko';
50
+ }
51
+ return 'Unknown';
52
+ }
53
+ getChromeVersion() {
54
+ return this.version.get(BrowserENUM.Chrome) || 0;
55
+ }
56
+ getEdgeVersion() {
57
+ return this.version.get(BrowserENUM.Edge) || 0;
58
+ }
59
+ getFirefoxVersion() {
60
+ return this.version.get(BrowserENUM.Firefox) || 0;
61
+ }
62
+ getGeckoVersion() {
63
+ return this.version.get(BrowserENUM.Gecko) || 0;
64
+ }
65
+ getMozillaVersion() {
66
+ return this.version.get(BrowserENUM.Mozilla) || 0;
67
+ }
68
+ getOculusVersion() {
69
+ return this.version.get(BrowserENUM.OculusBrowser) || 0;
70
+ }
71
+ getOperaVersion() {
72
+ return this.version.get(BrowserENUM.Opera) || 0;
73
+ }
74
+ getSafariVersion() {
75
+ return this.version.get(BrowserENUM.Safari) || 0;
76
+ }
77
+ getXVersion(x) {
78
+ return this.version.get(x) || 0;
79
+ }
80
+ getRaw() {
81
+ return this.raw;
82
+ }
83
+ }
@@ -5,6 +5,7 @@ import BaseKernelModule from './BaseKernelModule.js';
5
5
  import BaseApiAction from './BaseApiAction.js';
6
6
  import BaseAuthProvider from './BaseAuthProvider.js';
7
7
  export * from './BaseAction.js';
8
+ export * from './BaseUserAgent.js';
8
9
  export * from './BaseAuthProvider.js';
9
10
  export * from './timing/index.js';
10
11
  export { BaseLoopService, BaseAuthProvider, BaseKernelModule, BaseService, BaseApiAction, BaseEndpoint, BaseElement, BaseCache, BaseAction, BaseClient, BaseBridge, keepRawBody, ActionMode, };
@@ -5,6 +5,7 @@ import BaseKernelModule from './BaseKernelModule.js';
5
5
  import BaseApiAction from './BaseApiAction.js';
6
6
  import BaseAuthProvider from './BaseAuthProvider.js';
7
7
  export * from './BaseAction.js';
8
+ export * from './BaseUserAgent.js';
8
9
  export * from './BaseAuthProvider.js';
9
10
  export * from './timing/index.js';
10
11
  export { BaseLoopService, BaseAuthProvider, BaseKernelModule, BaseService, BaseApiAction, BaseEndpoint, BaseElement, BaseCache, BaseAction, BaseClient, BaseBridge, keepRawBody, ActionMode, };
@@ -0,0 +1,11 @@
1
+ import { CoreEntity } from '@grandlinex/core';
2
+ import { SKey, SSchemaEl } from '@grandlinex/swagger-mate';
3
+ export default class EntitySchemaExtender {
4
+ static extendEntitySchema(entity: CoreEntity, ...options: {
5
+ key: string;
6
+ list?: boolean;
7
+ entity?: CoreEntity;
8
+ schema?: SSchemaEl;
9
+ required?: boolean;
10
+ }[]): SKey<SSchemaEl>;
11
+ }
@@ -0,0 +1,47 @@
1
+ import { getEntityMeta } from '@grandlinex/core';
2
+ import { isSwaggerRef, SPathUtil, } from '@grandlinex/swagger-mate';
3
+ export default class EntitySchemaExtender {
4
+ static extendEntitySchema(entity, ...options) {
5
+ const meta = getEntityMeta(entity);
6
+ if (meta) {
7
+ const schema = SPathUtil.schemaEntryGen(entity)[meta.name];
8
+ if (schema && !isSwaggerRef(schema) && schema.properties) {
9
+ for (const option of options) {
10
+ if (option.schema) {
11
+ if (option.list) {
12
+ schema.properties[option.key] = {
13
+ type: 'array',
14
+ items: option.schema,
15
+ };
16
+ }
17
+ else {
18
+ schema.properties[option.key] = option.schema;
19
+ }
20
+ }
21
+ else if (option.entity) {
22
+ const eMeta = getEntityMeta(option.entity);
23
+ if (eMeta) {
24
+ const scheme = SPathUtil.schemaEntryGen(option.entity)[eMeta.name];
25
+ if (option.list) {
26
+ schema.properties[option.key] = {
27
+ type: 'array',
28
+ items: scheme,
29
+ };
30
+ }
31
+ else {
32
+ schema.properties[option.key] = scheme;
33
+ }
34
+ }
35
+ }
36
+ if (option.required) {
37
+ schema.required = [...(schema.required || []), option.key];
38
+ }
39
+ }
40
+ }
41
+ return {
42
+ [meta.name]: schema,
43
+ };
44
+ }
45
+ return {};
46
+ }
47
+ }
@@ -1,5 +1,5 @@
1
1
  import express from 'express';
2
- import { IExtensionInterface, JwtToken } from '../classes/index.js';
2
+ import { BaseUserAgent, IExtensionInterface, JwtToken } from '../classes/index.js';
3
3
  export type XRequest = express.Request & {
4
4
  rawBody?: string | null;
5
5
  };
@@ -11,4 +11,5 @@ export type XActionEvent<G = JwtToken | null> = {
11
11
  next: XNextFc;
12
12
  data: G;
13
13
  extension: IExtensionInterface;
14
+ agent: BaseUserAgent;
14
15
  };
@@ -2,7 +2,9 @@ import { ICoreAction, ICoreBridge, ICoreCache, ICoreCClient, ICoreClient, ICoreE
2
2
  import express from 'express';
3
3
  import * as jwt from 'jsonwebtoken';
4
4
  import { IAuthProvider, JwtExtend, JwtToken } from '../classes/index.js';
5
+ import EntitySchemaExtender from './EntitySchemaExtender.js';
5
6
  import { XActionEvent, XRequest } from './express.js';
7
+ export { EntitySchemaExtender };
6
8
  export type ActionTypes = 'POST' | 'GET' | 'USE' | 'PATCH' | 'DELETE';
7
9
  export interface ICClient<T extends JwtExtend = JwtExtend> extends ICoreCClient {
8
10
  setAuthProvider(provider: IAuthProvider<T>): boolean;
@@ -1 +1,2 @@
1
- export {};
1
+ import EntitySchemaExtender from './EntitySchemaExtender.js';
2
+ export { EntitySchemaExtender };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grandlinex/kernel",
3
- "version": "0.32.10",
3
+ "version": "1.0.0",
4
4
  "description": "GrandLineX is an out-of-the-box server framework on top of ExpressJs.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -25,7 +25,7 @@
25
25
  "build-fix": "node ./node_modules/@grandlinex/core/fix.js",
26
26
  "lint": "eslint src",
27
27
  "test": "jest --runInBand ",
28
- "run": "ts-node tests/run.ts",
28
+ "run": "node --no-warnings=ExperimentalWarning --loader ts-node/esm src/tests/run.ts",
29
29
  "pack-dev": "npm version -no-git-tag-version prerelease && npm run buildprep && npm pack",
30
30
  "test-converage": "jest --runInBand --ci --collectCoverage --coverageDirectory=\"./coverage\" --reporters=default --reporters=jest-junit",
31
31
  "doc-converage": "jest --runInBand --ci --collectCoverage --coverageDirectory=\"./docs/coverage\" --reporters=default --reporters=jest-junit",
@@ -46,37 +46,37 @@
46
46
  },
47
47
  "license": "BSD-3-Clause",
48
48
  "dependencies": {
49
- "@grandlinex/core": "0.32.0",
50
- "@grandlinex/swagger-mate": "0.32.1",
51
- "axios": "1.5.1",
49
+ "@grandlinex/core": "1.0.0",
50
+ "@grandlinex/swagger-mate": "1.0.0",
51
+ "axios": "1.7.2",
52
52
  "body-parser": "1.20.2",
53
- "express": "4.18.2",
53
+ "express": "4.19.2",
54
54
  "jsonwebtoken": "9.0.2",
55
- "@types/express": "^4.17.18",
56
- "@types/jsonwebtoken": "^9.0.3"
55
+ "@types/express": "4.17.21",
56
+ "@types/jsonwebtoken": "9.0.6"
57
57
  },
58
58
  "devDependencies": {
59
- "@types/jest": "^29.5.5",
60
- "@types/node": "^20.8.2",
61
- "@typescript-eslint/eslint-plugin": "^6.7.4",
62
- "@typescript-eslint/parser": "^6.7.4",
63
- "cross-env": "^7.0.3",
64
- "eslint": "^8.50.0",
65
- "eslint-config-airbnb": "^19.0.4",
66
- "eslint-config-airbnb-typescript": "^17.1.0",
67
- "eslint-config-prettier": "^9.0.0",
68
- "eslint-plugin-import": "^2.28.1",
69
- "eslint-plugin-jest": "^27.4.2",
70
- "eslint-plugin-jsx-a11y": "^6.7.1",
71
- "eslint-plugin-prettier": "^5.0.0",
72
- "jest": "^29.7.0",
73
- "jest-junit": "^16.0.0",
74
- "prettier": "3.0.3",
75
- "ts-jest": "^29.1.1",
76
- "ts-loader": "^9.4.4",
77
- "ts-node": "^10.9.1",
78
- "typedoc": "^0.25.1",
79
- "typescript": "^5.2.2"
59
+ "@types/jest": "29.5.12",
60
+ "@types/node": "22.0.0",
61
+ "@typescript-eslint/eslint-plugin": "7.18.0",
62
+ "@typescript-eslint/parser": "7.18.0",
63
+ "cross-env": "7.0.3",
64
+ "eslint": "8.57.0",
65
+ "eslint-config-airbnb": "19.0.4",
66
+ "eslint-config-airbnb-typescript": "18.0.0",
67
+ "eslint-config-prettier": "9.1.0",
68
+ "eslint-plugin-import": "2.29.1",
69
+ "eslint-plugin-jest": "28.6.0",
70
+ "eslint-plugin-jsx-a11y": "6.9.0",
71
+ "eslint-plugin-prettier": "5.2.1",
72
+ "jest": "29.7.0",
73
+ "jest-junit": "16.0.0",
74
+ "prettier": "3.3.3",
75
+ "ts-jest": "29.1.5",
76
+ "ts-loader": "9.5.1",
77
+ "ts-node": "10.9.2",
78
+ "typedoc": "0.26.5",
79
+ "typescript": "5.5.4"
80
80
  },
81
81
  "repository": {
82
82
  "type": "git",