@aeriajs/server 0.0.279 → 0.0.280
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/constants.js +1 -4
- package/dist/getToken.js +14 -19
- package/dist/handler.js +22 -28
- package/dist/index.js +4 -20
- package/dist/init.js +25 -29
- package/dist/loader.js +2 -7
- package/dist/routes.js +14 -18
- package/dist/warmup.js +16 -20
- package/package.json +12 -16
- package/dist/constants.mjs +0 -37
- package/dist/getToken.mjs +0 -44
- package/dist/handler.mjs +0 -99
- package/dist/index.mjs +0 -5
- package/dist/init.mjs +0 -95
- package/dist/loader.mjs +0 -7
- package/dist/routes.mjs +0 -38
- package/dist/warmup.mjs +0 -52
package/dist/constants.js
CHANGED
package/dist/getToken.js
CHANGED
|
@@ -1,32 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const common_1 = require("@aeriajs/common");
|
|
6
|
-
const core_1 = require("@aeriajs/core");
|
|
7
|
-
const authenticationGuard = (decodedToken) => {
|
|
1
|
+
import { Result, ACError } from '@aeriajs/types';
|
|
2
|
+
import { throwIfError } from '@aeriajs/common';
|
|
3
|
+
import { getDatabaseCollection, decodeToken, traverseDocument, ObjectId } from '@aeriajs/core';
|
|
4
|
+
export const authenticationGuard = (decodedToken) => {
|
|
8
5
|
decodedToken.authenticated = true;
|
|
9
6
|
return true;
|
|
10
7
|
};
|
|
11
|
-
|
|
12
|
-
const getToken = async (request, context) => {
|
|
8
|
+
export const getToken = async (request, context) => {
|
|
13
9
|
if (!request.headers.authorization) {
|
|
14
|
-
return
|
|
10
|
+
return Result.result({
|
|
15
11
|
authenticated: false,
|
|
16
12
|
sub: null,
|
|
17
13
|
});
|
|
18
14
|
}
|
|
19
|
-
const decodedToken = await
|
|
15
|
+
const decodedToken = await decodeToken(typeof request.headers.authorization === 'string'
|
|
20
16
|
? request.headers.authorization.split('Bearer ').at(-1)
|
|
21
17
|
: '');
|
|
22
|
-
if (
|
|
18
|
+
if (authenticationGuard(decodedToken)) {
|
|
23
19
|
if (typeof decodedToken.sub === 'string') {
|
|
24
|
-
decodedToken.sub = new
|
|
25
|
-
Object.assign(decodedToken.userinfo,
|
|
20
|
+
decodedToken.sub = new ObjectId(decodedToken.sub);
|
|
21
|
+
Object.assign(decodedToken.userinfo, throwIfError(await traverseDocument(decodedToken.userinfo, context.collections.user.description, {
|
|
26
22
|
autoCast: true,
|
|
27
23
|
})));
|
|
28
24
|
if (context.config.security.revalidateToken) {
|
|
29
|
-
const userCollection =
|
|
25
|
+
const userCollection = getDatabaseCollection('user');
|
|
30
26
|
const user = await userCollection.findOne({
|
|
31
27
|
_id: decodedToken.sub,
|
|
32
28
|
active: true,
|
|
@@ -36,15 +32,14 @@ const getToken = async (request, context) => {
|
|
|
36
32
|
},
|
|
37
33
|
});
|
|
38
34
|
if (!user) {
|
|
39
|
-
return
|
|
35
|
+
return Result.error(ACError.InvalidToken);
|
|
40
36
|
}
|
|
41
37
|
const rolesMatch = decodedToken.roles.every((role) => user.roles.includes(role));
|
|
42
38
|
if (!rolesMatch) {
|
|
43
|
-
return
|
|
39
|
+
return Result.error(ACError.InvalidToken);
|
|
44
40
|
}
|
|
45
41
|
}
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
|
-
return
|
|
44
|
+
return Result.result(decodedToken);
|
|
49
45
|
};
|
|
50
|
-
exports.getToken = getToken;
|
package/dist/handler.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const core_1 = require("@aeriajs/core");
|
|
5
|
-
const entrypoint_1 = require("@aeriajs/entrypoint");
|
|
6
|
-
const types_1 = require("@aeriajs/types");
|
|
1
|
+
import { createContext, getFunction } from '@aeriajs/core';
|
|
2
|
+
import { getCollection } from '@aeriajs/entrypoint';
|
|
3
|
+
import { ACError, HTTPStatus, Result } from '@aeriajs/types';
|
|
7
4
|
const getACErrorHttpCode = (code) => {
|
|
8
5
|
switch (code) {
|
|
9
|
-
case
|
|
10
|
-
case
|
|
11
|
-
case
|
|
12
|
-
case
|
|
13
|
-
case
|
|
14
|
-
default: return
|
|
6
|
+
case ACError.FunctionNotFound: return HTTPStatus.NotFound;
|
|
7
|
+
case ACError.FunctionNotExposed: return HTTPStatus.Forbidden;
|
|
8
|
+
case ACError.AuthorizationError: return HTTPStatus.Unauthorized;
|
|
9
|
+
case ACError.InvalidToken: return HTTPStatus.Unauthorized;
|
|
10
|
+
case ACError.AuthenticationError: return HTTPStatus.Forbidden;
|
|
11
|
+
default: return HTTPStatus.InternalServerError;
|
|
15
12
|
}
|
|
16
13
|
};
|
|
17
|
-
const safeHandle = (fn, context) => async () => {
|
|
14
|
+
export const safeHandle = (fn, context) => async () => {
|
|
18
15
|
try {
|
|
19
16
|
const response = await fn(context);
|
|
20
17
|
return response;
|
|
@@ -25,30 +22,29 @@ const safeHandle = (fn, context) => async () => {
|
|
|
25
22
|
}
|
|
26
23
|
console.trace(error);
|
|
27
24
|
if (context.request.headers['sec-fetch-mode'] === 'cors') {
|
|
28
|
-
return
|
|
29
|
-
code:
|
|
25
|
+
return Result.error({
|
|
26
|
+
code: ACError.UnknownError,
|
|
30
27
|
message: String(error),
|
|
31
28
|
});
|
|
32
29
|
}
|
|
33
|
-
return context.error(
|
|
34
|
-
code:
|
|
30
|
+
return context.error(HTTPStatus.InternalServerError, {
|
|
31
|
+
code: ACError.UnknownError,
|
|
35
32
|
message: String(error),
|
|
36
33
|
});
|
|
37
34
|
}
|
|
38
35
|
};
|
|
39
|
-
|
|
40
|
-
const customVerbs = () => async (parentContext) => {
|
|
36
|
+
export const customVerbs = () => async (parentContext) => {
|
|
41
37
|
const { fragments: [collectionName, functionName] } = parentContext.request;
|
|
42
|
-
const collection = await
|
|
38
|
+
const collection = await getCollection(collectionName);
|
|
43
39
|
if (!collection) {
|
|
44
40
|
return;
|
|
45
41
|
}
|
|
46
|
-
const context = await
|
|
42
|
+
const context = await createContext({
|
|
47
43
|
collectionName: collectionName,
|
|
48
44
|
calledFunction: functionName,
|
|
49
45
|
parentContext,
|
|
50
46
|
});
|
|
51
|
-
const { error, result: fn } = await
|
|
47
|
+
const { error, result: fn } = await getFunction(collectionName, functionName, context.token, {
|
|
52
48
|
exposedOnly: true,
|
|
53
49
|
});
|
|
54
50
|
if (error) {
|
|
@@ -59,14 +55,13 @@ const customVerbs = () => async (parentContext) => {
|
|
|
59
55
|
const result = await fn(context.request.payload, context);
|
|
60
56
|
return result;
|
|
61
57
|
};
|
|
62
|
-
|
|
63
|
-
const regularVerb = (functionName) => async (parentContext) => {
|
|
58
|
+
export const regularVerb = (functionName) => async (parentContext) => {
|
|
64
59
|
const { fragments: [collectionName, id] } = parentContext.request;
|
|
65
|
-
const collection = await
|
|
60
|
+
const collection = await getCollection(collectionName);
|
|
66
61
|
if (!collection) {
|
|
67
62
|
return;
|
|
68
63
|
}
|
|
69
|
-
const context = await
|
|
64
|
+
const context = await createContext({
|
|
70
65
|
collectionName: collectionName,
|
|
71
66
|
calledFunction: functionName,
|
|
72
67
|
parentContext,
|
|
@@ -85,7 +80,7 @@ const regularVerb = (functionName) => async (parentContext) => {
|
|
|
85
80
|
});
|
|
86
81
|
}
|
|
87
82
|
}
|
|
88
|
-
const { error, result: fn } = await
|
|
83
|
+
const { error, result: fn } = await getFunction(collectionName, functionName, context.token, {
|
|
89
84
|
exposedOnly: true,
|
|
90
85
|
});
|
|
91
86
|
if (error) {
|
|
@@ -96,4 +91,3 @@ const regularVerb = (functionName) => async (parentContext) => {
|
|
|
96
91
|
const result = await fn(requestCopy.payload, context);
|
|
97
92
|
return result;
|
|
98
93
|
};
|
|
99
|
-
exports.regularVerb = regularVerb;
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./init.js"), exports);
|
|
18
|
-
__exportStar(require("./warmup.js"), exports);
|
|
19
|
-
__exportStar(require("./loader.js"), exports);
|
|
20
|
-
__exportStar(require("./getToken.js"), exports);
|
|
1
|
+
export * from './init.js';
|
|
2
|
+
export * from './warmup.js';
|
|
3
|
+
export * from './loader.js';
|
|
4
|
+
export * from './getToken.js';
|
package/dist/init.js
CHANGED
|
@@ -1,46 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const routes_js_1 = require("./routes.js");
|
|
12
|
-
const getToken_js_1 = require("./getToken.js");
|
|
13
|
-
const init = (_options = {}) => {
|
|
1
|
+
import { ACError, HTTPStatus, Result } from '@aeriajs/types';
|
|
2
|
+
import { deepMerge, endpointError } from '@aeriajs/common';
|
|
3
|
+
import { cors, wrapRouteExecution } from '@aeriajs/http';
|
|
4
|
+
import { registerServer } from '@aeriajs/node-http';
|
|
5
|
+
import { createContext, getDatabase } from '@aeriajs/core';
|
|
6
|
+
import { DEFAULT_API_CONFIG } from './constants.js';
|
|
7
|
+
import { warmup } from './warmup.js';
|
|
8
|
+
import { registerRoutes } from './routes.js';
|
|
9
|
+
import { getToken } from './getToken.js';
|
|
10
|
+
export const init = (_options = {}) => {
|
|
14
11
|
const options = Object.assign({
|
|
15
12
|
config: {},
|
|
16
13
|
}, _options);
|
|
17
|
-
const config = Object.assign(options.config,
|
|
14
|
+
const config = Object.assign(options.config, deepMerge(DEFAULT_API_CONFIG, options.config));
|
|
18
15
|
return {
|
|
19
16
|
options,
|
|
20
17
|
listen: async () => {
|
|
21
18
|
if (!config.server) {
|
|
22
19
|
throw new Error;
|
|
23
20
|
}
|
|
24
|
-
const parentContext = await
|
|
21
|
+
const parentContext = await createContext({
|
|
25
22
|
config,
|
|
26
23
|
});
|
|
27
24
|
if (options.setup) {
|
|
28
25
|
await options.setup(parentContext);
|
|
29
26
|
}
|
|
30
27
|
if (!config.server.noWarmup) {
|
|
31
|
-
await
|
|
28
|
+
await warmup();
|
|
32
29
|
}
|
|
33
|
-
const apiRouter =
|
|
34
|
-
const server =
|
|
30
|
+
const apiRouter = registerRoutes();
|
|
31
|
+
const server = registerServer(config.server, async (request, response) => {
|
|
35
32
|
if (config.server && config.server.cors) {
|
|
36
33
|
let result;
|
|
37
34
|
switch (typeof config.server.cors) {
|
|
38
35
|
case 'function': {
|
|
39
|
-
result = await config.server.cors(request, response,
|
|
36
|
+
result = await config.server.cors(request, response, DEFAULT_API_CONFIG.server.cors);
|
|
40
37
|
break;
|
|
41
38
|
}
|
|
42
39
|
case 'object': {
|
|
43
|
-
result = await
|
|
40
|
+
result = await cors(request, response, config.server.cors);
|
|
44
41
|
break;
|
|
45
42
|
}
|
|
46
43
|
}
|
|
@@ -48,15 +45,15 @@ const init = (_options = {}) => {
|
|
|
48
45
|
return;
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
|
-
await
|
|
48
|
+
await wrapRouteExecution(response, async () => {
|
|
52
49
|
const getTokenFn = config.server?.getToken
|
|
53
50
|
? config.server.getToken
|
|
54
|
-
:
|
|
51
|
+
: getToken;
|
|
55
52
|
let token;
|
|
56
53
|
try {
|
|
57
54
|
const { error, result } = await getTokenFn(request, parentContext);
|
|
58
55
|
if (error) {
|
|
59
|
-
return
|
|
56
|
+
return Result.error(error);
|
|
60
57
|
}
|
|
61
58
|
token = result;
|
|
62
59
|
}
|
|
@@ -64,12 +61,12 @@ const init = (_options = {}) => {
|
|
|
64
61
|
if (process.env.NODE_ENV === 'development') {
|
|
65
62
|
console.trace(err);
|
|
66
63
|
}
|
|
67
|
-
return
|
|
68
|
-
httpStatus:
|
|
69
|
-
code:
|
|
64
|
+
return endpointError({
|
|
65
|
+
httpStatus: HTTPStatus.Unauthorized,
|
|
66
|
+
code: ACError.AuthenticationError,
|
|
70
67
|
});
|
|
71
68
|
}
|
|
72
|
-
const context = await
|
|
69
|
+
const context = await createContext({
|
|
73
70
|
parentContext,
|
|
74
71
|
token,
|
|
75
72
|
request,
|
|
@@ -91,11 +88,10 @@ const init = (_options = {}) => {
|
|
|
91
88
|
});
|
|
92
89
|
});
|
|
93
90
|
if (!config.database?.noDatabase) {
|
|
94
|
-
await
|
|
91
|
+
await getDatabase();
|
|
95
92
|
}
|
|
96
93
|
server.listen();
|
|
97
94
|
return server;
|
|
98
95
|
},
|
|
99
96
|
};
|
|
100
97
|
};
|
|
101
|
-
exports.init = init;
|
package/dist/loader.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.loader = void 0;
|
|
4
|
-
const common_1 = require("@aeriajs/common");
|
|
5
|
-
const loader = async () => {
|
|
6
|
-
const entrypoint = await (0, common_1.dynamicImport)(process.argv[1]);
|
|
1
|
+
export const loader = async () => {
|
|
2
|
+
const entrypoint = await import(process.argv[1]);
|
|
7
3
|
const entrypointMain = entrypoint.default
|
|
8
4
|
? entrypoint.default
|
|
9
5
|
: entrypoint;
|
|
10
6
|
entrypointMain.listen();
|
|
11
7
|
};
|
|
12
|
-
exports.loader = loader;
|
package/dist/routes.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const builtins_1 = require("@aeriajs/builtins");
|
|
7
|
-
const handler_js_1 = require("./handler.js");
|
|
8
|
-
const registerRoutes = () => {
|
|
1
|
+
import { createRouter } from '@aeriajs/http';
|
|
2
|
+
import { createContext } from '@aeriajs/core';
|
|
3
|
+
import { builtinFunctions } from '@aeriajs/builtins';
|
|
4
|
+
import { safeHandle, regularVerb, customVerbs } from './handler.js';
|
|
5
|
+
export const registerRoutes = () => {
|
|
9
6
|
const defaultHandler = (fn) => {
|
|
10
|
-
return (context) =>
|
|
7
|
+
return (context) => safeHandle(fn, context)();
|
|
11
8
|
};
|
|
12
|
-
const router =
|
|
9
|
+
const router = createRouter({
|
|
13
10
|
exhaust: true,
|
|
14
11
|
});
|
|
15
12
|
router.route([
|
|
16
13
|
'POST',
|
|
17
14
|
'GET',
|
|
18
|
-
], '/describe',
|
|
15
|
+
], '/describe', builtinFunctions.describe);
|
|
19
16
|
router.GET('/file/(\\w+)((/(\\w+))*)', defaultHandler(async (parentContext) => {
|
|
20
|
-
const context = await
|
|
17
|
+
const context = await createContext({
|
|
21
18
|
collectionName: 'file',
|
|
22
19
|
parentContext,
|
|
23
20
|
});
|
|
@@ -28,14 +25,13 @@ const registerRoutes = () => {
|
|
|
28
25
|
options,
|
|
29
26
|
});
|
|
30
27
|
}));
|
|
31
|
-
router.GET('/(\\w+)/id/(\\w+)', defaultHandler(
|
|
32
|
-
router.GET('/(\\w+)', defaultHandler(
|
|
33
|
-
router.POST('/(\\w+)', defaultHandler(
|
|
34
|
-
router.DELETE('/(\\w+)/(\\w+)', defaultHandler(
|
|
28
|
+
router.GET('/(\\w+)/id/(\\w+)', defaultHandler(regularVerb('get')));
|
|
29
|
+
router.GET('/(\\w+)', defaultHandler(regularVerb('getAll')));
|
|
30
|
+
router.POST('/(\\w+)', defaultHandler(regularVerb('insert')));
|
|
31
|
+
router.DELETE('/(\\w+)/(\\w+)', defaultHandler(regularVerb('remove')));
|
|
35
32
|
router.route([
|
|
36
33
|
'POST',
|
|
37
34
|
'GET',
|
|
38
|
-
], '/(\\w+)/(\\w+)', defaultHandler(
|
|
35
|
+
], '/(\\w+)/(\\w+)', defaultHandler(customVerbs()));
|
|
39
36
|
return router;
|
|
40
37
|
};
|
|
41
|
-
exports.registerRoutes = registerRoutes;
|
package/dist/warmup.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const core_1 = require("@aeriajs/core");
|
|
6
|
-
const entrypoint_1 = require("@aeriajs/entrypoint");
|
|
7
|
-
const node_util_1 = require("node:util");
|
|
1
|
+
import { METHOD_COLORS } from '@aeriajs/types';
|
|
2
|
+
import { getEndpoints } from '@aeriajs/core';
|
|
3
|
+
import { getConfig, getAvailableRoles } from '@aeriajs/entrypoint';
|
|
4
|
+
import { styleText } from 'node:util';
|
|
8
5
|
const colorizedRoute = async (method, endpointUri, endpoint) => {
|
|
9
|
-
const config = await
|
|
10
|
-
const color = method in
|
|
11
|
-
?
|
|
6
|
+
const config = await getConfig();
|
|
7
|
+
const color = method in METHOD_COLORS
|
|
8
|
+
? METHOD_COLORS[method]
|
|
12
9
|
: 'white';
|
|
13
|
-
let rolesLine = '', hasContractLine =
|
|
10
|
+
let rolesLine = '', hasContractLine = styleText(['yellow'], 'x');
|
|
14
11
|
if (endpoint) {
|
|
15
12
|
if ('roles' in endpoint) {
|
|
16
13
|
const roles = await (async () => {
|
|
17
|
-
const availableRoles = await
|
|
14
|
+
const availableRoles = await getAvailableRoles();
|
|
18
15
|
switch (endpoint.roles) {
|
|
19
16
|
case false:
|
|
20
17
|
case undefined:
|
|
@@ -25,26 +22,26 @@ const colorizedRoute = async (method, endpointUri, endpoint) => {
|
|
|
25
22
|
}
|
|
26
23
|
return endpoint.roles;
|
|
27
24
|
})();
|
|
28
|
-
rolesLine = ` ${
|
|
25
|
+
rolesLine = ` ${styleText(['grey'], `[${roles.join('|')}]`)}`;
|
|
29
26
|
}
|
|
30
27
|
if ('response' in endpoint || endpoint.builtin) {
|
|
31
|
-
hasContractLine =
|
|
28
|
+
hasContractLine = styleText(['green'], '✓');
|
|
32
29
|
}
|
|
33
30
|
}
|
|
34
|
-
let line =
|
|
31
|
+
let line = styleText([
|
|
35
32
|
'bold',
|
|
36
33
|
color,
|
|
37
34
|
], method) + '\t';
|
|
38
35
|
line += hasContractLine;
|
|
39
|
-
line +=
|
|
36
|
+
line += styleText(['grey'], ` ${config.baseUrl === '/'
|
|
40
37
|
? ''
|
|
41
38
|
: config.baseUrl}`);
|
|
42
|
-
line +=
|
|
39
|
+
line += styleText(['bold'], endpointUri);
|
|
43
40
|
line += rolesLine;
|
|
44
41
|
return line;
|
|
45
42
|
};
|
|
46
|
-
const warmup = async () => {
|
|
47
|
-
const endpoints = await
|
|
43
|
+
export const warmup = async () => {
|
|
44
|
+
const endpoints = await getEndpoints();
|
|
48
45
|
for (const endpointUri in endpoints) {
|
|
49
46
|
const endpoint = endpoints[endpointUri];
|
|
50
47
|
for (const method in endpoint) {
|
|
@@ -53,4 +50,3 @@ const warmup = async () => {
|
|
|
53
50
|
}
|
|
54
51
|
}
|
|
55
52
|
};
|
|
56
|
-
exports.warmup = warmup;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeriajs/server",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.280",
|
|
4
5
|
"description": "",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
|
-
"
|
|
18
|
-
"require": "./dist/index.js"
|
|
17
|
+
"default": "./dist/index.js"
|
|
19
18
|
}
|
|
20
19
|
},
|
|
21
20
|
"files": [
|
|
@@ -33,23 +32,20 @@
|
|
|
33
32
|
"mongodb": "^6.17.0"
|
|
34
33
|
},
|
|
35
34
|
"peerDependencies": {
|
|
36
|
-
"@aeriajs/core": "^0.0.
|
|
37
|
-
"@aeriajs/builtins": "^0.0.
|
|
38
|
-
"@aeriajs/common": "^0.0.
|
|
39
|
-
"@aeriajs/entrypoint": "^0.0.
|
|
40
|
-
"@aeriajs/http": "^0.0.
|
|
41
|
-
"@aeriajs/node-http": "^0.0.
|
|
42
|
-
"@aeriajs/server": "^0.0.
|
|
43
|
-
"@aeriajs/types": "^0.0.
|
|
35
|
+
"@aeriajs/core": "^0.0.278",
|
|
36
|
+
"@aeriajs/builtins": "^0.0.278",
|
|
37
|
+
"@aeriajs/common": "^0.0.158",
|
|
38
|
+
"@aeriajs/entrypoint": "^0.0.164",
|
|
39
|
+
"@aeriajs/http": "^0.0.194",
|
|
40
|
+
"@aeriajs/node-http": "^0.0.194",
|
|
41
|
+
"@aeriajs/server": "^0.0.280",
|
|
42
|
+
"@aeriajs/types": "^0.0.136",
|
|
44
43
|
"mongodb": "^6.17.0"
|
|
45
44
|
},
|
|
46
45
|
"scripts": {
|
|
47
46
|
"test": "echo skipping",
|
|
48
47
|
"lint": "eslint .",
|
|
49
48
|
"lint:fix": "eslint . --fix",
|
|
50
|
-
"build": "
|
|
51
|
-
"build:cjs": "tsc",
|
|
52
|
-
"build:esm": "esbuild './src/**/*.ts' --outdir=dist --out-extension:.js=.mjs && pnpm build:esm-transform",
|
|
53
|
-
"build:esm-transform": "pnpm -w esm-transform $PWD/dist"
|
|
49
|
+
"build": "tsc"
|
|
54
50
|
}
|
|
55
51
|
}
|
package/dist/constants.mjs
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
export const DEFAULT_API_CONFIG = {
|
|
3
|
-
baseUrl: "/",
|
|
4
|
-
defaultPaginationLimit: 10,
|
|
5
|
-
server: {
|
|
6
|
-
port: 3e3,
|
|
7
|
-
cors: {
|
|
8
|
-
allowOrigin: ["*"],
|
|
9
|
-
allowMethods: ["*"],
|
|
10
|
-
allowHeaders: [
|
|
11
|
-
"Accept",
|
|
12
|
-
"Accept-Version",
|
|
13
|
-
"Authorization",
|
|
14
|
-
"Content-Length",
|
|
15
|
-
"Content-MD5",
|
|
16
|
-
"Content-Type",
|
|
17
|
-
"Date",
|
|
18
|
-
"X-Api-Version",
|
|
19
|
-
"X-Stream-Request"
|
|
20
|
-
],
|
|
21
|
-
maxAge: "2592000"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
security: {
|
|
25
|
-
tokenExpiration: 36e3,
|
|
26
|
-
linkTokenExpiration: 36e3,
|
|
27
|
-
paginationLimit: 100,
|
|
28
|
-
mutableUserProperties: [
|
|
29
|
-
"email",
|
|
30
|
-
"name",
|
|
31
|
-
"password",
|
|
32
|
-
"phone_number",
|
|
33
|
-
"picture_file"
|
|
34
|
-
],
|
|
35
|
-
revalidateToken: true
|
|
36
|
-
}
|
|
37
|
-
};
|
package/dist/getToken.mjs
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { Result, ACError } from "@aeriajs/types";
|
|
3
|
-
import { throwIfError } from "@aeriajs/common";
|
|
4
|
-
import { getDatabaseCollection, decodeToken, traverseDocument, ObjectId } from "@aeriajs/core";
|
|
5
|
-
export const authenticationGuard = (decodedToken) => {
|
|
6
|
-
decodedToken.authenticated = true;
|
|
7
|
-
return true;
|
|
8
|
-
};
|
|
9
|
-
export const getToken = async (request, context) => {
|
|
10
|
-
if (!request.headers.authorization) {
|
|
11
|
-
return Result.result({
|
|
12
|
-
authenticated: false,
|
|
13
|
-
sub: null
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
const decodedToken = await decodeToken(typeof request.headers.authorization === "string" ? request.headers.authorization.split("Bearer ").at(-1) : "");
|
|
17
|
-
if (authenticationGuard(decodedToken)) {
|
|
18
|
-
if (typeof decodedToken.sub === "string") {
|
|
19
|
-
decodedToken.sub = new ObjectId(decodedToken.sub);
|
|
20
|
-
Object.assign(decodedToken.userinfo, throwIfError(await traverseDocument(decodedToken.userinfo, context.collections.user.description, {
|
|
21
|
-
autoCast: true
|
|
22
|
-
})));
|
|
23
|
-
if (context.config.security.revalidateToken) {
|
|
24
|
-
const userCollection = getDatabaseCollection("user");
|
|
25
|
-
const user = await userCollection.findOne({
|
|
26
|
-
_id: decodedToken.sub,
|
|
27
|
-
active: true
|
|
28
|
-
}, {
|
|
29
|
-
projection: {
|
|
30
|
-
roles: 1
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
if (!user) {
|
|
34
|
-
return Result.error(ACError.InvalidToken);
|
|
35
|
-
}
|
|
36
|
-
const rolesMatch = decodedToken.roles.every((role) => user.roles.includes(role));
|
|
37
|
-
if (!rolesMatch) {
|
|
38
|
-
return Result.error(ACError.InvalidToken);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return Result.result(decodedToken);
|
|
44
|
-
};
|
package/dist/handler.mjs
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { createContext, getFunction } from "@aeriajs/core";
|
|
3
|
-
import { getCollection } from "@aeriajs/entrypoint";
|
|
4
|
-
import { ACError, HTTPStatus, Result } from "@aeriajs/types";
|
|
5
|
-
const getACErrorHttpCode = (code) => {
|
|
6
|
-
switch (code) {
|
|
7
|
-
case ACError.FunctionNotFound:
|
|
8
|
-
return HTTPStatus.NotFound;
|
|
9
|
-
case ACError.FunctionNotExposed:
|
|
10
|
-
return HTTPStatus.Forbidden;
|
|
11
|
-
case ACError.AuthorizationError:
|
|
12
|
-
return HTTPStatus.Unauthorized;
|
|
13
|
-
case ACError.InvalidToken:
|
|
14
|
-
return HTTPStatus.Unauthorized;
|
|
15
|
-
case ACError.AuthenticationError:
|
|
16
|
-
return HTTPStatus.Forbidden;
|
|
17
|
-
default:
|
|
18
|
-
return HTTPStatus.InternalServerError;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
export const safeHandle = (fn, context) => async () => {
|
|
22
|
-
try {
|
|
23
|
-
const response = await fn(context);
|
|
24
|
-
return response;
|
|
25
|
-
} catch (error) {
|
|
26
|
-
if (context.config.errorHandler) {
|
|
27
|
-
return context.config.errorHandler(context, error);
|
|
28
|
-
}
|
|
29
|
-
console.trace(error);
|
|
30
|
-
if (context.request.headers["sec-fetch-mode"] === "cors") {
|
|
31
|
-
return Result.error({
|
|
32
|
-
code: ACError.UnknownError,
|
|
33
|
-
message: String(error)
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
return context.error(HTTPStatus.InternalServerError, {
|
|
37
|
-
code: ACError.UnknownError,
|
|
38
|
-
message: String(error)
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
export const customVerbs = () => async (parentContext) => {
|
|
43
|
-
const { fragments: [collectionName, functionName] } = parentContext.request;
|
|
44
|
-
const collection = await getCollection(collectionName);
|
|
45
|
-
if (!collection) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const context = await createContext({
|
|
49
|
-
collectionName,
|
|
50
|
-
calledFunction: functionName,
|
|
51
|
-
parentContext
|
|
52
|
-
});
|
|
53
|
-
const { error, result: fn } = await getFunction(collectionName, functionName, context.token, {
|
|
54
|
-
exposedOnly: true
|
|
55
|
-
});
|
|
56
|
-
if (error) {
|
|
57
|
-
return context.error(getACErrorHttpCode(error), {
|
|
58
|
-
code: error
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
const result = await fn(context.request.payload, context);
|
|
62
|
-
return result;
|
|
63
|
-
};
|
|
64
|
-
export const regularVerb = (functionName) => async (parentContext) => {
|
|
65
|
-
const { fragments: [collectionName, id] } = parentContext.request;
|
|
66
|
-
const collection = await getCollection(collectionName);
|
|
67
|
-
if (!collection) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const context = await createContext({
|
|
71
|
-
collectionName,
|
|
72
|
-
calledFunction: functionName,
|
|
73
|
-
parentContext
|
|
74
|
-
});
|
|
75
|
-
const requestCopy = Object.assign({}, context.request);
|
|
76
|
-
if (id) {
|
|
77
|
-
requestCopy.payload.filters ??= {};
|
|
78
|
-
if (requestCopy.payload.filters && typeof requestCopy.payload.filters === "object") {
|
|
79
|
-
Object.assign(requestCopy.payload.filters, {
|
|
80
|
-
_id: id
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
if (requestCopy.payload.what && typeof requestCopy.payload.what === "object") {
|
|
84
|
-
Object.assign(requestCopy.payload.what, {
|
|
85
|
-
_id: id
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const { error, result: fn } = await getFunction(collectionName, functionName, context.token, {
|
|
90
|
-
exposedOnly: true
|
|
91
|
-
});
|
|
92
|
-
if (error) {
|
|
93
|
-
return context.error(getACErrorHttpCode(error), {
|
|
94
|
-
code: error
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
const result = await fn(requestCopy.payload, context);
|
|
98
|
-
return result;
|
|
99
|
-
};
|
package/dist/index.mjs
DELETED
package/dist/init.mjs
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { ACError, HTTPStatus, Result } from "@aeriajs/types";
|
|
3
|
-
import { deepMerge, endpointError } from "@aeriajs/common";
|
|
4
|
-
import { cors, wrapRouteExecution } from "@aeriajs/http";
|
|
5
|
-
import { registerServer } from "@aeriajs/node-http";
|
|
6
|
-
import { createContext, getDatabase } from "@aeriajs/core";
|
|
7
|
-
import { DEFAULT_API_CONFIG } from "./constants.mjs";
|
|
8
|
-
import { warmup } from "./warmup.mjs";
|
|
9
|
-
import { registerRoutes } from "./routes.mjs";
|
|
10
|
-
import { getToken } from "./getToken.mjs";
|
|
11
|
-
export const init = (_options = {}) => {
|
|
12
|
-
const options = Object.assign({
|
|
13
|
-
config: {}
|
|
14
|
-
}, _options);
|
|
15
|
-
const config = Object.assign(options.config, deepMerge(DEFAULT_API_CONFIG, options.config));
|
|
16
|
-
return {
|
|
17
|
-
options,
|
|
18
|
-
listen: async () => {
|
|
19
|
-
if (!config.server) {
|
|
20
|
-
throw new Error();
|
|
21
|
-
}
|
|
22
|
-
const parentContext = await createContext({
|
|
23
|
-
config
|
|
24
|
-
});
|
|
25
|
-
if (options.setup) {
|
|
26
|
-
await options.setup(parentContext);
|
|
27
|
-
}
|
|
28
|
-
if (!config.server.noWarmup) {
|
|
29
|
-
await warmup();
|
|
30
|
-
}
|
|
31
|
-
const apiRouter = registerRoutes();
|
|
32
|
-
const server = registerServer(config.server, async (request, response) => {
|
|
33
|
-
if (config.server && config.server.cors) {
|
|
34
|
-
let result;
|
|
35
|
-
switch (typeof config.server.cors) {
|
|
36
|
-
case "function": {
|
|
37
|
-
result = await config.server.cors(request, response, DEFAULT_API_CONFIG.server.cors);
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
case "object": {
|
|
41
|
-
result = await cors(request, response, config.server.cors);
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (result === null) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
await wrapRouteExecution(response, async () => {
|
|
50
|
-
const getTokenFn = config.server?.getToken ? config.server.getToken : getToken;
|
|
51
|
-
let token;
|
|
52
|
-
try {
|
|
53
|
-
const { error, result } = await getTokenFn(request, parentContext);
|
|
54
|
-
if (error) {
|
|
55
|
-
return Result.error(error);
|
|
56
|
-
}
|
|
57
|
-
token = result;
|
|
58
|
-
} catch (err) {
|
|
59
|
-
if (true) {
|
|
60
|
-
console.trace(err);
|
|
61
|
-
}
|
|
62
|
-
return endpointError({
|
|
63
|
-
httpStatus: HTTPStatus.Unauthorized,
|
|
64
|
-
code: ACError.AuthenticationError
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
const context = await createContext({
|
|
68
|
-
parentContext,
|
|
69
|
-
token,
|
|
70
|
-
request,
|
|
71
|
-
response
|
|
72
|
-
});
|
|
73
|
-
if (options.callback) {
|
|
74
|
-
const result = await options.callback(context);
|
|
75
|
-
if (result !== void 0) {
|
|
76
|
-
return result;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (options.router) {
|
|
80
|
-
const result = await options.router.handle(request, response, context);
|
|
81
|
-
if (result !== void 0) {
|
|
82
|
-
return result;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return apiRouter.handle(request, response, context);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
if (!config.database?.noDatabase) {
|
|
89
|
-
await getDatabase();
|
|
90
|
-
}
|
|
91
|
-
server.listen();
|
|
92
|
-
return server;
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
};
|
package/dist/loader.mjs
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { dynamicImport } from "@aeriajs/common";
|
|
3
|
-
export const loader = async () => {
|
|
4
|
-
const entrypoint = await dynamicImport(process.argv[1]);
|
|
5
|
-
const entrypointMain = entrypoint.default ? entrypoint.default : entrypoint;
|
|
6
|
-
entrypointMain.listen();
|
|
7
|
-
};
|
package/dist/routes.mjs
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { createRouter } from "@aeriajs/http";
|
|
3
|
-
import { createContext } from "@aeriajs/core";
|
|
4
|
-
import { builtinFunctions } from "@aeriajs/builtins";
|
|
5
|
-
import { safeHandle, regularVerb, customVerbs } from "./handler.mjs";
|
|
6
|
-
export const registerRoutes = () => {
|
|
7
|
-
const defaultHandler = (fn) => {
|
|
8
|
-
return (context) => safeHandle(fn, context)();
|
|
9
|
-
};
|
|
10
|
-
const router = createRouter({
|
|
11
|
-
exhaust: true
|
|
12
|
-
});
|
|
13
|
-
router.route([
|
|
14
|
-
"POST",
|
|
15
|
-
"GET"
|
|
16
|
-
], "/describe", builtinFunctions.describe);
|
|
17
|
-
router.GET("/file/(\\w+)((/(\\w+))*)", defaultHandler(async (parentContext) => {
|
|
18
|
-
const context = await createContext({
|
|
19
|
-
collectionName: "file",
|
|
20
|
-
parentContext
|
|
21
|
-
});
|
|
22
|
-
const [fileId, optionsString] = context.request.fragments;
|
|
23
|
-
const options = optionsString.split("/").filter((option) => option === "picture" || option === "download");
|
|
24
|
-
return context.collections.file.functions.download({
|
|
25
|
-
fileId,
|
|
26
|
-
options
|
|
27
|
-
});
|
|
28
|
-
}));
|
|
29
|
-
router.GET("/(\\w+)/id/(\\w+)", defaultHandler(regularVerb("get")));
|
|
30
|
-
router.GET("/(\\w+)", defaultHandler(regularVerb("getAll")));
|
|
31
|
-
router.POST("/(\\w+)", defaultHandler(regularVerb("insert")));
|
|
32
|
-
router.DELETE("/(\\w+)/(\\w+)", defaultHandler(regularVerb("remove")));
|
|
33
|
-
router.route([
|
|
34
|
-
"POST",
|
|
35
|
-
"GET"
|
|
36
|
-
], "/(\\w+)/(\\w+)", defaultHandler(customVerbs()));
|
|
37
|
-
return router;
|
|
38
|
-
};
|
package/dist/warmup.mjs
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { METHOD_COLORS } from "@aeriajs/types";
|
|
3
|
-
import { getEndpoints } from "@aeriajs/core";
|
|
4
|
-
import { getConfig, getAvailableRoles } from "@aeriajs/entrypoint";
|
|
5
|
-
import { styleText } from "node:util";
|
|
6
|
-
const colorizedRoute = async (method, endpointUri, endpoint) => {
|
|
7
|
-
const config = await getConfig();
|
|
8
|
-
const color = method in METHOD_COLORS ? METHOD_COLORS[method] : "white";
|
|
9
|
-
let rolesLine = "", hasContractLine = styleText(["yellow"], "x");
|
|
10
|
-
if (endpoint) {
|
|
11
|
-
if ("roles" in endpoint) {
|
|
12
|
-
const roles = await (async () => {
|
|
13
|
-
const availableRoles = await getAvailableRoles();
|
|
14
|
-
switch (endpoint.roles) {
|
|
15
|
-
case false:
|
|
16
|
-
case void 0:
|
|
17
|
-
return [];
|
|
18
|
-
case true:
|
|
19
|
-
return [];
|
|
20
|
-
case "unauthenticated":
|
|
21
|
-
return availableRoles;
|
|
22
|
-
case "unauthenticated-only":
|
|
23
|
-
return ["unauthenticated"];
|
|
24
|
-
}
|
|
25
|
-
return endpoint.roles;
|
|
26
|
-
})();
|
|
27
|
-
rolesLine = ` ${styleText(["grey"], `[${roles.join("|")}]`)}`;
|
|
28
|
-
}
|
|
29
|
-
if ("response" in endpoint || endpoint.builtin) {
|
|
30
|
-
hasContractLine = styleText(["green"], "\u2713");
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
let line = styleText([
|
|
34
|
-
"bold",
|
|
35
|
-
color
|
|
36
|
-
], method) + " ";
|
|
37
|
-
line += hasContractLine;
|
|
38
|
-
line += styleText(["grey"], ` ${config.baseUrl === "/" ? "" : config.baseUrl}`);
|
|
39
|
-
line += styleText(["bold"], endpointUri);
|
|
40
|
-
line += rolesLine;
|
|
41
|
-
return line;
|
|
42
|
-
};
|
|
43
|
-
export const warmup = async () => {
|
|
44
|
-
const endpoints = await getEndpoints();
|
|
45
|
-
for (const endpointUri in endpoints) {
|
|
46
|
-
const endpoint = endpoints[endpointUri];
|
|
47
|
-
for (const method in endpoint) {
|
|
48
|
-
const line = await colorizedRoute(method, endpointUri, endpoint[method]);
|
|
49
|
-
console.log(line);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|