node-server-engine 1.0.5 → 1.0.7
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/.env.example +3 -0
- package/README.md +10 -0
- package/dist/entities/Endpoint/Endpoint.types.d.ts +3 -3
- package/dist/entities/Endpoint/Endpoint.types.js.map +1 -1
- package/dist/middleware/authJwt/authJwt.types.d.ts +2 -14
- package/dist/middleware/authJwt/authJwt.types.js +4 -0
- package/dist/middleware/authJwt/authJwt.types.js.map +1 -1
- package/dist/middleware/geminiFileUploader/geminiFileUploader.d.ts +2 -0
- package/dist/middleware/geminiFileUploader/geminiFileUploader.js +108 -0
- package/dist/middleware/geminiFileUploader/geminiFileUploader.js.map +1 -0
- package/dist/middleware/geminiFileUploader/index.d.ts +1 -0
- package/dist/middleware/geminiFileUploader/index.js +17 -0
- package/dist/middleware/geminiFileUploader/index.js.map +1 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/userResolver/userResolver.js +1 -1
- package/dist/middleware/userResolver/userResolver.js.map +1 -1
- package/dist/utils/dbMigration/dbMigration.js +2 -1
- package/dist/utils/dbMigration/dbMigration.js.map +1 -1
- package/dist/utils/jwt/jwt.types.d.ts +1 -2
- package/dist/utils/jwt/jwt.types.js.map +1 -1
- package/package.json +7 -3
- package/src/entities/Endpoint/Endpoint.types.ts +3 -3
- package/src/middleware/authJwt/authJwt.types.ts +4 -15
- package/src/middleware/geminiFileUploader/geminiFileUploader.ts +117 -0
- package/src/middleware/geminiFileUploader/index.ts +1 -0
- package/src/middleware/index.ts +1 -0
- package/src/middleware/userResolver/userResolver.test.ts +4 -4
- package/src/middleware/userResolver/userResolver.ts +1 -2
- package/src/utils/dbMigration/dbMigration.ts +5 -2
- package/src/utils/jwt/jwt.types.ts +2 -2
package/.env.example
CHANGED
|
@@ -13,6 +13,9 @@ HOST_NAME=
|
|
|
13
13
|
# Timeout (in ms) for the websocket connections to close gracefully on server shutdown. After that, the connection is destroyed unilateraly
|
|
14
14
|
WEBSOCKET_CLOSE_TIMEOUT=
|
|
15
15
|
|
|
16
|
+
# Google Gemini AI key
|
|
17
|
+
GOOGLE_AI_KEY=
|
|
18
|
+
|
|
16
19
|
#######
|
|
17
20
|
# TLS #
|
|
18
21
|
#######
|
package/README.md
CHANGED
|
@@ -227,6 +227,16 @@ The following settings can be used on each object the Endpoint's `options.files`
|
|
|
227
227
|
|
|
228
228
|
---
|
|
229
229
|
|
|
230
|
+
#### Gemini File Upload
|
|
231
|
+
|
|
232
|
+
An endpoint can upload a file to a google gemini AI
|
|
233
|
+
|
|
234
|
+
The request must be made as `multipart/form-data`.
|
|
235
|
+
|
|
236
|
+
File should be uploaded under the key file.
|
|
237
|
+
|
|
238
|
+
The file's data will be available at `req.body.fileUri req.body.mimeType req.body.originalname`
|
|
239
|
+
|
|
230
240
|
### Socket Client
|
|
231
241
|
|
|
232
242
|
The socket server start if the [Server](#server)'s webSocket option is not undefined.
|
|
@@ -2,7 +2,7 @@ import { ErrorRequestHandler, Request, Response, NextFunction, RequestHandler }
|
|
|
2
2
|
import { ParamsDictionary } from 'express-serve-static-core';
|
|
3
3
|
import { Schema } from 'express-validator';
|
|
4
4
|
import { ParsedQs } from 'qs';
|
|
5
|
-
import { authJwt, authHmac, authTls, authStatic, authAdmin,
|
|
5
|
+
import { authJwt, authHmac, authTls, authStatic, authAdmin, FileUploaderConfig, RequestAdminProps } from '../../middleware';
|
|
6
6
|
export declare enum EndpointMethod {
|
|
7
7
|
GET = "get",
|
|
8
8
|
POST = "post",
|
|
@@ -23,7 +23,7 @@ export declare enum EndpointAuthType {
|
|
|
23
23
|
}
|
|
24
24
|
export declare const EndpointAuthTypes: EndpointAuthType[];
|
|
25
25
|
export type Middleware<T extends EndpointAuthType> = (request: EndpointRequestType[T], response: Response, next: NextFunction) => unknown | Promise<unknown>;
|
|
26
|
-
export type MiddlewareChainElement<T extends EndpointAuthType> = Array<Middleware<T>> | Middleware<T
|
|
26
|
+
export type MiddlewareChainElement<T extends EndpointAuthType> = Array<Middleware<T>> | Middleware<T> | any;
|
|
27
27
|
/** Auth related parameters used with Admin authentication */
|
|
28
28
|
interface EndpointAuthAdminParams {
|
|
29
29
|
/** [Admin] User permission required to use this endpoint */
|
|
@@ -102,7 +102,7 @@ export interface EndpointOptions<T extends EndpointAuthType> {
|
|
|
102
102
|
/** Request type when using JWT authentication */
|
|
103
103
|
export interface JwtRequest<P = ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = ParsedQs, Locals extends Record<string, any> = Record<string, any>> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {
|
|
104
104
|
/** User that identified using a JWT */
|
|
105
|
-
user:
|
|
105
|
+
user: Record<string, any> | any;
|
|
106
106
|
}
|
|
107
107
|
/** Request type when using mTLS authentication */
|
|
108
108
|
export interface TlsRequest<P = ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = ParsedQs, Locals extends Record<string, any> = Record<string, any>> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Endpoint.types.js","names":["_middleware","require","EndpointMethod","exports","EndpointMethods","Object","values","EndpointAuthType","EndpointAuthTypes","EndpointAuthHandlers","NONE","undefined","JWT","authJwt","TLS","authTls","HMAC","authHmac","STATIC","authStatic","ADMIN","authAdmin"],"sources":["../../../src/entities/Endpoint/Endpoint.types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n ErrorRequestHandler,\n Request,\n Response,\n NextFunction,\n RequestHandler\n} from 'express';\nimport { ParamsDictionary } from 'express-serve-static-core';\nimport { Schema } from 'express-validator';\nimport { ParsedQs } from 'qs';\n\nimport {\n authJwt,\n authHmac,\n authTls,\n authStatic,\n authAdmin,\n
|
|
1
|
+
{"version":3,"file":"Endpoint.types.js","names":["_middleware","require","EndpointMethod","exports","EndpointMethods","Object","values","EndpointAuthType","EndpointAuthTypes","EndpointAuthHandlers","NONE","undefined","JWT","authJwt","TLS","authTls","HMAC","authHmac","STATIC","authStatic","ADMIN","authAdmin"],"sources":["../../../src/entities/Endpoint/Endpoint.types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n ErrorRequestHandler,\n Request,\n Response,\n NextFunction,\n RequestHandler\n} from 'express';\nimport { ParamsDictionary } from 'express-serve-static-core';\nimport { Schema } from 'express-validator';\nimport { ParsedQs } from 'qs';\n\nimport {\n authJwt,\n authHmac,\n authTls,\n authStatic,\n authAdmin,\n FileUploaderConfig,\n RequestAdminProps\n} from 'middleware';\n\nexport enum EndpointMethod {\n GET = 'get',\n POST = 'post',\n PUT = 'put',\n PATCH = 'patch',\n DELETE = 'delete',\n HEAD = 'head',\n ALL = 'all'\n}\n\nexport const EndpointMethods = Object.values(EndpointMethod);\n\nexport enum EndpointAuthType {\n NONE = 'none',\n JWT = 'jwt',\n TLS = 'tls',\n HMAC = 'hmac',\n STATIC = 'static',\n ADMIN = 'admin'\n}\n\nexport const EndpointAuthTypes = Object.values(EndpointAuthType);\n\nexport type Middleware<T extends EndpointAuthType> = (\n request: EndpointRequestType[T],\n response: Response,\n next: NextFunction\n) => unknown | Promise<unknown>;\n\nexport type MiddlewareChainElement<T extends EndpointAuthType> =\n | Array<Middleware<T>>\n | Middleware<T>\n | any;\n\n/** Auth related parameters used with Admin authentication */\ninterface EndpointAuthAdminParams {\n /** [Admin] User permission required to use this endpoint */\n permission: string;\n}\n\n/** Auth related parameters used with HMAC authentication */\ninterface EndpointAuthHmacParams {\n /** [HMAC] Secret used for signature */\n secret?: string;\n /** [HMAC] For Github webhook, the standard differs slightly, so this option must be selected */\n isGithub?: boolean;\n}\n\n/** Auth related parameters used with mTLS authentication */\ninterface EndpointAuthTlsParams {\n /** [TLS] List oh hosts that are allowed to use the endpoint, this is compared to the claims in the certificate */\n whitelist?: Array<string>;\n}\n\n/** Mapping used to get auth specific parameters depending on the auth type used */\ninterface EndpointAuthSpecificParams {\n /** Auth parameters for no authentication */\n [EndpointAuthType.NONE]: any;\n /** Auth parameters for JWT authentication */\n [EndpointAuthType.JWT]: any;\n /** Auth parameters for mTLS authentication */\n [EndpointAuthType.TLS]: EndpointAuthTlsParams;\n /** Auth parameters for HMAC authentication */\n [EndpointAuthType.HMAC]: EndpointAuthHmacParams;\n /** Auth parameters for static authentication */\n [EndpointAuthType.STATIC]: any;\n /** Auth parameters for admin token authentication */\n [EndpointAuthType.ADMIN]: EndpointAuthAdminParams;\n}\n\nexport type EndpointAuthParams<T extends EndpointAuthType> =\n EndpointAuthSpecificParams[T] & {\n /** This will allow the business logic to run event if the authentication fails */\n acceptInvalid?: boolean;\n };\n\nexport type EndpointAuthHandler<T extends EndpointAuthType> = (\n options?: EndpointAuthParams<T>\n) => (\n request: Request,\n response: Response,\n next: NextFunction\n) => void | Promise<void>;\n\nexport const EndpointAuthHandlers = {\n /** Auth handler for no authentication */\n [EndpointAuthType.NONE]: undefined,\n /** Auth handler for JWT authentication */\n [EndpointAuthType.JWT]: authJwt,\n /** Auth handler for mTLS authentication */\n [EndpointAuthType.TLS]: authTls,\n /** Auth handler for HMAC authentication */\n [EndpointAuthType.HMAC]: authHmac,\n /** Auth handler for static authentication */\n [EndpointAuthType.STATIC]: authStatic,\n /** Auth handler for admin token authentication */\n [EndpointAuthType.ADMIN]: authAdmin\n};\n\nexport type EndpointHandler<T extends EndpointAuthType> = (\n request: EndpointRequestType[T],\n response: Response\n) => void | Promise<void>;\n\n/** Endpoint initialization options */\nexport interface EndpointOptions<T extends EndpointAuthType> {\n /** Path at which the endpoint is reachable */\n path: string;\n /** HTTP method of the endpoint */\n method: EndpointMethod;\n /** Function handling the endpoint's business logic */\n handler: EndpointHandler<T>;\n /** Validation schema that the request must pass before reaching the handler */\n validator: Schema;\n /** Authentication system required by this endpoint */\n authType: T;\n /** Authentication related options for this endpoint */\n authParams?: EndpointAuthParams<T>;\n /** @deprecated Setting to upload a file through this endpoint */\n file?: FileUploaderConfig;\n /** Settings to upload files through this endpoint (this will automatically switch the expected request to be a multipart) */\n files?: Array<FileUploaderConfig>;\n /** Express request handlers that should run on this endpoint before the business logic, they will run after the global middleware */\n middleware?: MiddlewareChainElement<T>;\n /** Express error handlers that should be registered for this endpoint. they will run before the global error handler */\n errorMiddleware?: ErrorRequestHandler | Array<ErrorRequestHandler>;\n}\n\n/** Request type when using JWT authentication */\nexport interface JwtRequest<\n P = ParamsDictionary,\n ResBody = any,\n ReqBody = any,\n ReqQuery = ParsedQs,\n Locals extends Record<string, any> = Record<string, any>\n> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {\n /** User that identified using a JWT */\n user: Record<string, any> | any;\n}\n\n/** Request type when using mTLS authentication */\nexport interface TlsRequest<\n P = ParamsDictionary,\n ResBody = any,\n ReqBody = any,\n ReqQuery = ParsedQs,\n Locals extends Record<string, any> = Record<string, any>\n> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {\n /** Host names provided by the mTLS authenticated client */\n hosts: Array<string>;\n}\n\n/** Request type when using HMAC authentication */\nexport interface AdminRequest<\n P = ParamsDictionary,\n ResBody = any,\n ReqBody = any,\n ReqQuery = ParsedQs,\n Locals extends Record<string, any> = Record<string, any>\n> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {\n /** User that identified using a JWT */\n admin: RequestAdminProps;\n}\n\n/** Mapping of request types in endpoints based on auth type used */\nexport interface EndpointRequestType {\n /** Request type for no authentication */\n [EndpointAuthType.NONE]: Request;\n /** Request type when using JWT authentication */\n [EndpointAuthType.JWT]: JwtRequest;\n /** Request type when using mTLS authentication */\n [EndpointAuthType.TLS]: TlsRequest;\n /** Request type when using HMAC authentication */\n [EndpointAuthType.HMAC]: Request;\n /** Auth handler for static authentication */\n [EndpointAuthType.STATIC]: Request;\n /** Auth handler for admin token authentication */\n [EndpointAuthType.ADMIN]: AdminRequest;\n}\n\nexport type SafeMiddleWareChain = Array<\n RequestHandler | ErrorRequestHandler | SafeMiddleWareChain\n>;\n"],"mappings":";;;;;;AAYA,IAAAA,WAAA,GAAAC,OAAA;AAZA;AAAA,IAsBYC,cAAc,GAAAC,OAAA,CAAAD,cAAA,0BAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAdA,cAAc;EAAA,OAAdA,cAAc;AAAA;AAUnB,MAAME,eAAe,GAAAD,OAAA,CAAAC,eAAA,GAAGC,MAAM,CAACC,MAAM,CAACJ,cAAc,CAAC;AAAC,IAEjDK,gBAAgB,GAAAJ,OAAA,CAAAI,gBAAA,0BAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAhBA,gBAAgB;EAAA,OAAhBA,gBAAgB;AAAA;AASrB,MAAMC,iBAAiB,GAAAL,OAAA,CAAAK,iBAAA,GAAGH,MAAM,CAACC,MAAM,CAACC,gBAAgB,CAAC;;AAahE;;AAMA;;AAQA;;AAMA;;AA8BO,MAAME,oBAAoB,GAAAN,OAAA,CAAAM,oBAAA,GAAG;EAClC;EACA,CAACF,gBAAgB,CAACG,IAAI,GAAGC,SAAS;EAClC;EACA,CAACJ,gBAAgB,CAACK,GAAG,GAAGC,mBAAO;EAC/B;EACA,CAACN,gBAAgB,CAACO,GAAG,GAAGC,mBAAO;EAC/B;EACA,CAACR,gBAAgB,CAACS,IAAI,GAAGC,oBAAQ;EACjC;EACA,CAACV,gBAAgB,CAACW,MAAM,GAAGC,sBAAU;EACrC;EACA,CAACZ,gBAAgB,CAACa,KAAK,GAAGC;AAC5B,CAAC;;AAOD;;AAwBA;;AAYA;;AAYA;;AAYA","ignoreList":[]}
|
|
@@ -1,22 +1,10 @@
|
|
|
1
|
+
export {};
|
|
1
2
|
declare global {
|
|
2
3
|
namespace Express {
|
|
3
4
|
/** Express request object */
|
|
4
5
|
interface Request {
|
|
5
6
|
/** User that identified using a JWT */
|
|
6
|
-
user?:
|
|
7
|
+
user?: Record<string, any>;
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
|
-
/** User properties of the request object */
|
|
11
|
-
export interface RequestUser {
|
|
12
|
-
/** ID of the user */
|
|
13
|
-
id: string;
|
|
14
|
-
/** ID of the token used to identify */
|
|
15
|
-
tokenId: string;
|
|
16
|
-
/** ID of the device used by the client to obtain the token */
|
|
17
|
-
deviceId: string;
|
|
18
|
-
/** Name of the user */
|
|
19
|
-
name: string;
|
|
20
|
-
/** Email of the user */
|
|
21
|
-
email: string;
|
|
22
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authJwt.types.js","names":[],"sources":["../../../src/middleware/authJwt/authJwt.types.ts"],"sourcesContent":["// Override the Express request object to add the files\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n /** Express request object */\n interface Request {\n /** User that identified using a JWT */\n user?:
|
|
1
|
+
{"version":3,"file":"authJwt.types.js","names":[],"sources":["../../../src/middleware/authJwt/authJwt.types.ts"],"sourcesContent":["export {};\n\n// Override the Express request object to add the files\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n /** Express request object */\n interface Request {\n /** User that identified using a JWT */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n user?: Record<string, any>;\n }\n }\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.geminiFileUploader = geminiFileUploader;
|
|
8
|
+
var _multer = _interopRequireDefault(require("multer"));
|
|
9
|
+
var _server = require("@google/generative-ai/server");
|
|
10
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
11
|
+
var _path = _interopRequireDefault(require("path"));
|
|
12
|
+
var _tmp = _interopRequireDefault(require("tmp"));
|
|
13
|
+
var _report = require("../../utils/report");
|
|
14
|
+
var _checkEnvironment = require("../../utils/checkEnvironment");
|
|
15
|
+
var _envAssert = require("../../utils/envAssert");
|
|
16
|
+
const namespace = 'engine:middleware:geminiFileUploader';
|
|
17
|
+
const apiKey = process.env.GOOGLE_AI_KEY ?? '';
|
|
18
|
+
const fileManager = new _server.GoogleAIFileManager(apiKey);
|
|
19
|
+
const storage = _multer.default.memoryStorage();
|
|
20
|
+
async function uploadToGemini(buffer, mimeType, originalName) {
|
|
21
|
+
// Add 'name' to the return type
|
|
22
|
+
const tempFile = _tmp.default.fileSync({
|
|
23
|
+
postfix: _path.default.extname(originalName)
|
|
24
|
+
});
|
|
25
|
+
_fs.default.writeFileSync(tempFile.name, buffer);
|
|
26
|
+
const uploadResult = await fileManager.uploadFile(tempFile.name, {
|
|
27
|
+
mimeType,
|
|
28
|
+
displayName: originalName
|
|
29
|
+
});
|
|
30
|
+
tempFile.removeCallback();
|
|
31
|
+
const file = uploadResult.file;
|
|
32
|
+
(0, _report.reportDebug)({
|
|
33
|
+
namespace,
|
|
34
|
+
message: 'Uploaded file',
|
|
35
|
+
data: {
|
|
36
|
+
displayName: file.displayName,
|
|
37
|
+
name: file.name
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
name: file.name,
|
|
42
|
+
uri: file.uri,
|
|
43
|
+
mimeType: file.mimeType
|
|
44
|
+
}; // Include 'name' in the return object
|
|
45
|
+
}
|
|
46
|
+
async function waitForFilesActive(files) {
|
|
47
|
+
(0, _report.reportDebug)({
|
|
48
|
+
namespace,
|
|
49
|
+
message: 'Waiting for file processing...'
|
|
50
|
+
});
|
|
51
|
+
for (const {
|
|
52
|
+
name
|
|
53
|
+
} of files) {
|
|
54
|
+
let file = await fileManager.getFile(name);
|
|
55
|
+
while (file.state === 'PROCESSING') {
|
|
56
|
+
process.stdout.write('.');
|
|
57
|
+
await new Promise(resolve => setTimeout(resolve, 10_000));
|
|
58
|
+
file = await fileManager.getFile(name);
|
|
59
|
+
}
|
|
60
|
+
if (file.state !== 'ACTIVE') {
|
|
61
|
+
(0, _report.reportError)(`File ${file.name} failed to process`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
(0, _report.reportDebug)({
|
|
65
|
+
namespace,
|
|
66
|
+
message: 'all files ready...\n'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function geminiFileUploader(req, res, next) {
|
|
70
|
+
try {
|
|
71
|
+
(0, _checkEnvironment.checkEnvironment)({
|
|
72
|
+
GOOGLE_AI_KEY: _envAssert.envAssert.isString()
|
|
73
|
+
});
|
|
74
|
+
// Use multer.single() inside the middleware
|
|
75
|
+
const uploadSingle = (0, _multer.default)({
|
|
76
|
+
storage
|
|
77
|
+
}).single('file');
|
|
78
|
+
uploadSingle(req, res, async err => {
|
|
79
|
+
if (err) {
|
|
80
|
+
(0, _report.reportError)(`Error uploading file`);
|
|
81
|
+
next(err);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const file = req.file;
|
|
85
|
+
if (!file) {
|
|
86
|
+
(0, _report.reportError)(`No file uploaded`);
|
|
87
|
+
next(`No file uploaded`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const mimeType = file.mimetype;
|
|
91
|
+
const uploadedFile = await uploadToGemini(file.buffer, mimeType, file.originalname);
|
|
92
|
+
await waitForFilesActive([uploadedFile]);
|
|
93
|
+
|
|
94
|
+
// Set the fileUri and mimeType in the request object for the next middleware/route handler
|
|
95
|
+
req.body.file = {
|
|
96
|
+
fileUri: uploadedFile.uri,
|
|
97
|
+
mimeType: uploadedFile.mimeType,
|
|
98
|
+
originalname: file.originalname
|
|
99
|
+
};
|
|
100
|
+
next(); // Proceed to the next middleware or route handler
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error(error);
|
|
104
|
+
(0, _report.reportError)(`Failed to upload or process file`);
|
|
105
|
+
next(error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=geminiFileUploader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geminiFileUploader.js","names":["_multer","_interopRequireDefault","require","_server","_fs","_path","_tmp","_report","_checkEnvironment","_envAssert","namespace","apiKey","process","env","GOOGLE_AI_KEY","fileManager","GoogleAIFileManager","storage","multer","memoryStorage","uploadToGemini","buffer","mimeType","originalName","tempFile","tmp","fileSync","postfix","path","extname","fs","writeFileSync","name","uploadResult","uploadFile","displayName","removeCallback","file","reportDebug","message","data","uri","waitForFilesActive","files","getFile","state","stdout","write","Promise","resolve","setTimeout","reportError","geminiFileUploader","req","res","next","checkEnvironment","envAssert","isString","uploadSingle","single","err","mimetype","uploadedFile","originalname","body","fileUri","error","console"],"sources":["../../../src/middleware/geminiFileUploader/geminiFileUploader.ts"],"sourcesContent":["import express from 'express';\nimport multer from 'multer';\nimport { GoogleAIFileManager } from '@google/generative-ai/server';\nimport fs from 'fs';\nimport path from 'path';\nimport tmp from 'tmp';\nimport { reportError, reportDebug } from 'utils/report';\nimport { checkEnvironment } from 'utils/checkEnvironment';\nimport { envAssert } from 'utils/envAssert';\n\nconst namespace = 'engine:middleware:geminiFileUploader';\n\nconst apiKey = process.env.GOOGLE_AI_KEY ?? '';\nconst fileManager = new GoogleAIFileManager(apiKey);\n\nconst storage = multer.memoryStorage();\n\nasync function uploadToGemini(\n buffer: Buffer,\n mimeType: string,\n originalName: string\n): Promise<{ name: string; uri: string; mimeType: string }> {\n // Add 'name' to the return type\n const tempFile = tmp.fileSync({ postfix: path.extname(originalName) });\n\n fs.writeFileSync(tempFile.name, buffer);\n\n const uploadResult = await fileManager.uploadFile(tempFile.name, {\n mimeType,\n displayName: originalName\n });\n\n tempFile.removeCallback();\n\n const file = uploadResult.file;\n reportDebug({\n namespace,\n message: 'Uploaded file',\n data: { displayName: file.displayName, name: file.name }\n });\n return { name: file.name, uri: file.uri, mimeType: file.mimeType }; // Include 'name' in the return object\n}\n\nasync function waitForFilesActive(\n files: { name: string; uri: string; mimeType: string }[]\n): Promise<void> {\n reportDebug({\n namespace,\n message: 'Waiting for file processing...'\n });\n for (const { name } of files) {\n let file = await fileManager.getFile(name);\n while (file.state === 'PROCESSING') {\n process.stdout.write('.');\n await new Promise((resolve) => setTimeout(resolve, 10_000));\n file = await fileManager.getFile(name);\n }\n if (file.state !== 'ACTIVE') {\n reportError(`File ${file.name} failed to process`);\n }\n }\n reportDebug({\n namespace,\n message: 'all files ready...\\n'\n });\n}\n\nexport async function geminiFileUploader(\n req: express.Request,\n res: express.Response,\n next: express.NextFunction\n): Promise<void> {\n try {\n checkEnvironment({\n GOOGLE_AI_KEY: envAssert.isString()\n });\n // Use multer.single() inside the middleware\n const uploadSingle = multer({ storage }).single('file');\n\n uploadSingle(req, res, async (err) => {\n if (err) {\n reportError(`Error uploading file`);\n next(err);\n return;\n }\n\n const file = req.file;\n if (!file) {\n reportError(`No file uploaded`);\n next(`No file uploaded`);\n return;\n }\n const mimeType = file.mimetype;\n\n const uploadedFile = await uploadToGemini(\n file.buffer,\n mimeType,\n file.originalname\n );\n\n await waitForFilesActive([uploadedFile]);\n\n // Set the fileUri and mimeType in the request object for the next middleware/route handler\n req.body.file = {\n fileUri: uploadedFile.uri,\n mimeType: uploadedFile.mimeType,\n originalname: file.originalname\n };\n\n next(); // Proceed to the next middleware or route handler\n });\n } catch (error) {\n console.error(error);\n reportError(`Failed to upload or process file`);\n next(error);\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './geminiFileUploader';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _geminiFileUploader = require("./geminiFileUploader");
|
|
7
|
+
Object.keys(_geminiFileUploader).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _geminiFileUploader[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _geminiFileUploader[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["_geminiFileUploader","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get"],"sources":["../../../src/middleware/geminiFileUploader/index.ts"],"sourcesContent":["export * from './geminiFileUploader';\n"],"mappings":";;;;;AAAA,IAAAA,mBAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,mBAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,mBAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,mBAAA,CAAAK,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
|
package/dist/middleware/index.js
CHANGED
|
@@ -168,4 +168,15 @@ Object.keys(_authAdmin).forEach(function (key) {
|
|
|
168
168
|
}
|
|
169
169
|
});
|
|
170
170
|
});
|
|
171
|
+
var _geminiFileUploader = require("./geminiFileUploader");
|
|
172
|
+
Object.keys(_geminiFileUploader).forEach(function (key) {
|
|
173
|
+
if (key === "default" || key === "__esModule") return;
|
|
174
|
+
if (key in exports && exports[key] === _geminiFileUploader[key]) return;
|
|
175
|
+
Object.defineProperty(exports, key, {
|
|
176
|
+
enumerable: true,
|
|
177
|
+
get: function () {
|
|
178
|
+
return _geminiFileUploader[key];
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
171
182
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_error","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_healthCheck","_validate","_fourOhFour","_authJwt","_authHmac","_authStatic","_swaggerDocs","_authTls","_userResolver","_fileUploader","_metrics","_requestMetrics","_version","_authAdmin"],"sources":["../../src/middleware/index.ts"],"sourcesContent":["export * from './error';\nexport * from './healthCheck';\nexport * from './validate';\nexport * from './fourOhFour';\nexport * from './authJwt';\nexport * from './authHmac';\nexport * from './authStatic';\nexport * from './swaggerDocs';\nexport * from './authTls';\nexport * from './userResolver';\nexport * from './fileUploader';\nexport * from './metrics';\nexport * from './requestMetrics';\nexport * from './version';\nexport * from './authAdmin';\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_error","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_healthCheck","_validate","_fourOhFour","_authJwt","_authHmac","_authStatic","_swaggerDocs","_authTls","_userResolver","_fileUploader","_metrics","_requestMetrics","_version","_authAdmin","_geminiFileUploader"],"sources":["../../src/middleware/index.ts"],"sourcesContent":["export * from './error';\nexport * from './healthCheck';\nexport * from './validate';\nexport * from './fourOhFour';\nexport * from './authJwt';\nexport * from './authHmac';\nexport * from './authStatic';\nexport * from './swaggerDocs';\nexport * from './authTls';\nexport * from './userResolver';\nexport * from './fileUploader';\nexport * from './metrics';\nexport * from './requestMetrics';\nexport * from './version';\nexport * from './authAdmin';\nexport * from './geminiFileUploader';\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userResolver.js","names":["_EngineError","require","_utils","namespace","userResolver","request","response","next","id","user","EngineError","message","data","reportDebug"],"sources":["../../../src/middleware/userResolver/userResolver.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport { EngineError } from 'entities/EngineError';\nimport {
|
|
1
|
+
{"version":3,"file":"userResolver.js","names":["_EngineError","require","_utils","namespace","userResolver","request","response","next","id","user","EngineError","message","data","reportDebug"],"sources":["../../../src/middleware/userResolver/userResolver.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport { EngineError } from 'entities/EngineError';\nimport { reportDebug } from 'utils';\n\nconst namespace = 'engine:middleware:userResolver';\n\n/** Fetch the user previously identified by a JWT and adds his data to the request.user object */\nexport async function userResolver(\n request: Request,\n response: Response,\n next: NextFunction\n): Promise<void> {\n const id = request.user?.id;\n if (!id)\n throw new EngineError({\n message: 'Could not resolve user as the request is missing his ID'\n });\n const user = { user: 'ram', id };\n if (!user)\n throw new EngineError({\n message: 'Could not resolve user as it could not be fetched',\n data: { id }\n });\n reportDebug({\n namespace,\n message: 'Resolved user based on his token',\n data: { user, request: request.user }\n });\n request.user = {\n ...request?.user,\n ...user\n };\n\n next();\n}\n"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AAEA,MAAME,SAAS,GAAG,gCAAgC;;AAElD;AACO,eAAeC,YAAYA,CAChCC,OAAgB,EAChBC,QAAkB,EAClBC,IAAkB,EACH;EACf,MAAMC,EAAE,GAAGH,OAAO,CAACI,IAAI,EAAED,EAAE;EAC3B,IAAI,CAACA,EAAE,EACL,MAAM,IAAIE,wBAAW,CAAC;IACpBC,OAAO,EAAE;EACX,CAAC,CAAC;EACJ,MAAMF,IAAI,GAAG;IAAEA,IAAI,EAAE,KAAK;IAAED;EAAG,CAAC;EAChC,IAAI,CAACC,IAAI,EACP,MAAM,IAAIC,wBAAW,CAAC;IACpBC,OAAO,EAAE,mDAAmD;IAC5DC,IAAI,EAAE;MAAEJ;IAAG;EACb,CAAC,CAAC;EACJ,IAAAK,kBAAW,EAAC;IACVV,SAAS;IACTQ,OAAO,EAAE,kCAAkC;IAC3CC,IAAI,EAAE;MAAEH,IAAI;MAAEJ,OAAO,EAAEA,OAAO,CAACI;IAAK;EACtC,CAAC,CAAC;EACFJ,OAAO,CAACI,IAAI,GAAG;IACb,GAAGJ,OAAO,EAAEI,IAAI;IAChB,GAAGA;EACL,CAAC;EAEDF,IAAI,CAAC,CAAC;AACR","ignoreList":[]}
|
|
@@ -104,7 +104,8 @@ async function rollbackMigrations() {
|
|
|
104
104
|
|
|
105
105
|
// Fetch executed migrations in ascending order
|
|
106
106
|
const migrations = await _models.SequelizeMeta.findAll({
|
|
107
|
-
order: [['name', 'ASC']]
|
|
107
|
+
order: [['name', 'ASC']],
|
|
108
|
+
raw: true
|
|
108
109
|
});
|
|
109
110
|
const rollbackUntil = migrations.find(migration => migration.version && (0, _semverCompare.semverCompare)(migration.version, process.env.BUILD_ID) === 1);
|
|
110
111
|
if (!rollbackUntil) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","path","env","DB_MIGRATIONS_DIR","NODE_ENV","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","runPendingMigrations","sequelize","EngineError","migrateMetadataTable","migrationPaths","length","forEach","migrator","Umzug","migrations","glob","resolve","name","context","migration","up","down","getQueryInterface","storage","SequelizeStorage","logger","console","log","rollbackMigrations","BUILD_ID","SequelizeMeta","findAll","order","rollbackUntil","find","version","semverCompare","buildId","to","testRecreateDB","options","query","SQL_TYPE","clean","testClearDB","transaction","clearDbTransaction","t","model","Object","keys","models","includeMetadata","table","tableName","raw"],"sources":["../../../src/utils/dbMigration/dbMigration.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-require-imports */\n// Register ts-node at the top of runMigrations.ts\nrequire('ts-node/register');\n\nimport { existsSync, lstatSync } from 'fs';\nimport { join } from 'path';\nimport { Sequelize, Transaction } from 'sequelize';\nimport { Umzug, SequelizeStorage } from 'umzug';\nimport { ClearDbOptions, RecreateDbOptions } from './dbMigration.types';\nimport { migrateMetadataTable } from './migrateMetadataTable';\nimport { SequelizeMeta } from 'db/models';\nimport { EngineError } from 'entities/EngineError';\nimport { sequelize } from 'entities/Sequelize';\nimport { reportDebug } from 'utils/report';\nimport { semverCompare } from 'utils/semverCompare';\n\nconst namespace = 'engine:utils:dbMigration';\n\nfunction getMigrationPaths(): Array<string> | undefined {\n // We look between possibilities for the first directory that exists and matches our expectations\n // First a user specified one, then the production default, then the development default\n const prodDefaultPath = join(process.cwd(), './dist/db/migrations');\n const devDefaultPath = join(process.cwd(), './src/db/migrations');\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n process.env.NODE_ENV === 'prod' ? prodDefaultPath : devDefaultPath\n ].filter((path) => path && existsSync(path) && lstatSync(path).isDirectory());\n reportDebug({\n namespace,\n message: 'Obtaining Umzug migration options',\n data: {\n path,\n prodPath: prodDefaultPath,\n devPath: devDefaultPath,\n customPath: process.env.DB_MIGRATIONS_DIR\n }\n });\n return path.map((p) =>\n process.env.NODE_ENV === 'prod' ? `${p}/*.js` : `${p}/*.ts`\n );\n}\n\n/** Run all the non-executed migrations one by one */\nexport async function runPendingMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n // First make sure that the metadata table is up to date\n await migrateMetadataTable(sequelize);\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found.',\n data: { migrationPaths }\n });\n return;\n }\n\n migrationPaths?.forEach(async (path) => {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n // Use require to import the migration file\n const migration = require(path || '');\n return {\n name,\n up: async () => migration.up(context),\n down: async () => migration.down(context)\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: 'Starting pending database migrations',\n data: { path }\n });\n await migrator.up();\n console.log('Db Migration Completed')\n });\n}\n\n/** Rollback all migrations up to a specified target version */\nexport async function rollbackMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n if (!process.env.BUILD_ID)\n throw new EngineError({ message: 'BUILD_ID is not defined' });\n\n // Fetch executed migrations in ascending order\n const migrations = await SequelizeMeta.findAll({ order: [['name', 'ASC']] });\n const rollbackUntil = migrations.find(\n (migration) =>\n migration.version &&\n semverCompare(migration.version, process.env.BUILD_ID as string) === 1\n );\n\n if (!rollbackUntil) {\n reportDebug({\n namespace,\n message: 'No rollback target found for the current BUILD_ID.',\n data: { buildId: process.env.BUILD_ID }\n });\n return;\n }\n\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found for rollback.',\n data: { migrationPaths }\n });\n return;\n }\n\n migrationPaths.forEach(async (path) => {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const migration = require(path || '');\n return {\n name,\n up: async () => migration.up(context),\n down: async () => migration.down(context)\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: `Rolling back migrations up to: ${rollbackUntil.name}`,\n data: { path }\n });\n\n await migrator.down({ to: rollbackUntil.name });\n });\n}\n\n/**\n * Recreate the whole database\n * Quick way to make sure that we are working on a clean database\n * /!\\ Should only be used when running tests\n */\nexport async function testRecreateDB(\n options: RecreateDbOptions = {}\n): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.query(\n `DROP SCHEMA public${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''}`\n );\n await sequelize.query(`CREATE SCHEMA public`);\n if (!options.clean) await runPendingMigrations();\n}\n\n/**\n * Empty all the schemas in the database\n * Quick way to flush the database data while keep the structure\n * /!\\ Should only be used when running tests\n */\nexport async function testClearDB(options: ClearDbOptions = {}): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.transaction(clearDbTransaction(sequelize, options));\n}\n\n/** DB clearing transaction */\nfunction clearDbTransaction(sequelize: Sequelize, options: ClearDbOptions) {\n return async (t: Transaction): Promise<void> => {\n for (const model of Object.keys(sequelize.models)) {\n // We ignore the migration metadata schema\n if (!options.includeMetadata && model === 'sequelizeMeta') continue;\n const table = sequelize.models[model].tableName;\n await sequelize.query(\n `TRUNCATE ${table}${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''};`,\n {\n raw: true,\n transaction: t\n }\n );\n }\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","path","env","DB_MIGRATIONS_DIR","NODE_ENV","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","runPendingMigrations","sequelize","EngineError","migrateMetadataTable","migrationPaths","length","forEach","migrator","Umzug","migrations","glob","resolve","name","context","migration","up","down","getQueryInterface","storage","SequelizeStorage","logger","console","log","rollbackMigrations","BUILD_ID","SequelizeMeta","findAll","order","raw","rollbackUntil","find","version","semverCompare","buildId","to","testRecreateDB","options","query","SQL_TYPE","clean","testClearDB","transaction","clearDbTransaction","t","model","Object","keys","models","includeMetadata","table","tableName"],"sources":["../../../src/utils/dbMigration/dbMigration.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-require-imports */\n// Register ts-node at the top of runMigrations.ts\nrequire('ts-node/register');\n\nimport { existsSync, lstatSync } from 'fs';\nimport { join } from 'path';\nimport { Sequelize, Transaction } from 'sequelize';\nimport { Umzug, SequelizeStorage } from 'umzug';\nimport { ClearDbOptions, RecreateDbOptions } from './dbMigration.types';\nimport { migrateMetadataTable } from './migrateMetadataTable';\nimport { SequelizeMeta } from 'db/models';\nimport { EngineError } from 'entities/EngineError';\nimport { sequelize } from 'entities/Sequelize';\nimport { reportDebug } from 'utils/report';\nimport { semverCompare } from 'utils/semverCompare';\n\nconst namespace = 'engine:utils:dbMigration';\n\nfunction getMigrationPaths(): Array<string> | undefined {\n // We look between possibilities for the first directory that exists and matches our expectations\n // First a user specified one, then the production default, then the development default\n const prodDefaultPath = join(process.cwd(), './dist/db/migrations');\n const devDefaultPath = join(process.cwd(), './src/db/migrations');\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n process.env.NODE_ENV === 'prod' ? prodDefaultPath : devDefaultPath\n ].filter((path) => path && existsSync(path) && lstatSync(path).isDirectory());\n reportDebug({\n namespace,\n message: 'Obtaining Umzug migration options',\n data: {\n path,\n prodPath: prodDefaultPath,\n devPath: devDefaultPath,\n customPath: process.env.DB_MIGRATIONS_DIR\n }\n });\n return path.map((p) =>\n process.env.NODE_ENV === 'prod' ? `${p}/*.js` : `${p}/*.ts`\n );\n}\n\n/** Run all the non-executed migrations one by one */\nexport async function runPendingMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n // First make sure that the metadata table is up to date\n await migrateMetadataTable(sequelize);\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found.',\n data: { migrationPaths }\n });\n return;\n }\n\n migrationPaths?.forEach(async (path) => {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n // Use require to import the migration file\n const migration = require(path || '');\n return {\n name,\n up: async () => migration.up(context),\n down: async () => migration.down(context)\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: 'Starting pending database migrations',\n data: { path }\n });\n await migrator.up();\n console.log('Db Migration Completed');\n });\n}\n\n/** Rollback all migrations up to a specified target version */\nexport async function rollbackMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n if (!process.env.BUILD_ID)\n throw new EngineError({ message: 'BUILD_ID is not defined' });\n\n // Fetch executed migrations in ascending order\n const migrations = await SequelizeMeta.findAll({\n order: [['name', 'ASC']],\n raw: true\n });\n const rollbackUntil = migrations.find(\n (migration) =>\n migration.version &&\n semverCompare(migration.version, process.env.BUILD_ID as string) === 1\n );\n\n if (!rollbackUntil) {\n reportDebug({\n namespace,\n message: 'No rollback target found for the current BUILD_ID.',\n data: { buildId: process.env.BUILD_ID }\n });\n return;\n }\n\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found for rollback.',\n data: { migrationPaths }\n });\n return;\n }\n\n migrationPaths.forEach(async (path) => {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const migration = require(path || '');\n return {\n name,\n up: async () => migration.up(context),\n down: async () => migration.down(context)\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: `Rolling back migrations up to: ${rollbackUntil.name}`,\n data: { path }\n });\n\n await migrator.down({ to: rollbackUntil.name });\n });\n}\n\n/**\n * Recreate the whole database\n * Quick way to make sure that we are working on a clean database\n * /!\\ Should only be used when running tests\n */\nexport async function testRecreateDB(\n options: RecreateDbOptions = {}\n): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.query(\n `DROP SCHEMA public${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''}`\n );\n await sequelize.query(`CREATE SCHEMA public`);\n if (!options.clean) await runPendingMigrations();\n}\n\n/**\n * Empty all the schemas in the database\n * Quick way to flush the database data while keep the structure\n * /!\\ Should only be used when running tests\n */\nexport async function testClearDB(options: ClearDbOptions = {}): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.transaction(clearDbTransaction(sequelize, options));\n}\n\n/** DB clearing transaction */\nfunction clearDbTransaction(sequelize: Sequelize, options: ClearDbOptions) {\n return async (t: Transaction): Promise<void> => {\n for (const model of Object.keys(sequelize.models)) {\n // We ignore the migration metadata schema\n if (!options.includeMetadata && model === 'sequelizeMeta') continue;\n const table = sequelize.models[model].tableName;\n await sequelize.query(\n `TRUNCATE ${table}${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''};`,\n {\n raw: true,\n transaction: t\n }\n );\n }\n };\n}\n"],"mappings":";;;;;;;;;AAIA,IAAAA,GAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AAEA,IAAAE,MAAA,GAAAF,OAAA;AAEA,IAAAG,qBAAA,GAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AACA,IAAAK,YAAA,GAAAL,OAAA;AACA,IAAAM,UAAA,GAAAN,OAAA;AACA,IAAAO,OAAA,GAAAP,OAAA;AACA,IAAAQ,cAAA,GAAAR,OAAA;AAdA;AACA;AACAA,OAAO,CAAC,kBAAkB,CAAC;AAc3B,MAAMS,SAAS,GAAG,0BAA0B;AAE5C,SAASC,iBAAiBA,CAAA,EAA8B;EACtD;EACA;EACA,MAAMC,eAAe,GAAG,IAAAC,UAAI,EAACC,OAAO,CAACC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC;EACnE,MAAMC,cAAc,GAAG,IAAAH,UAAI,EAACC,OAAO,CAACC,GAAG,CAAC,CAAC,EAAE,qBAAqB,CAAC;EACjE,MAAME,IAAI,GAAG,CACXH,OAAO,CAACI,GAAG,CAACC,iBAAiB,EAC7BL,OAAO,CAACI,GAAG,CAACE,QAAQ,KAAK,MAAM,GAAGR,eAAe,GAAGI,cAAc,CACnE,CAACK,MAAM,CAAEJ,IAAI,IAAKA,IAAI,IAAI,IAAAK,cAAU,EAACL,IAAI,CAAC,IAAI,IAAAM,aAAS,EAACN,IAAI,CAAC,CAACO,WAAW,CAAC,CAAC,CAAC;EAC7E,IAAAC,mBAAW,EAAC;IACVf,SAAS;IACTgB,OAAO,EAAE,mCAAmC;IAC5CC,IAAI,EAAE;MACJV,IAAI;MACJW,QAAQ,EAAEhB,eAAe;MACzBiB,OAAO,EAAEb,cAAc;MACvBc,UAAU,EAAEhB,OAAO,CAACI,GAAG,CAACC;IAC1B;EACF,CAAC,CAAC;EACF,OAAOF,IAAI,CAACc,GAAG,CAAEC,CAAC,IAChBlB,OAAO,CAACI,GAAG,CAACE,QAAQ,KAAK,MAAM,GAAG,GAAGY,CAAC,OAAO,GAAG,GAAGA,CAAC,OACtD,CAAC;AACH;;AAEA;AACO,eAAeC,oBAAoBA,CAAA,EAAkB;EAC1D,IAAI,CAACC,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE;EACA,MAAM,IAAAU,0CAAoB,EAACF,oBAAS,CAAC;EACrC,MAAMG,cAAc,GAAG1B,iBAAiB,CAAC,CAAC;EAE1C,IAAI,CAAC0B,cAAc,IAAIA,cAAc,CAACC,MAAM,IAAI,CAAC,EAAE;IACjD,IAAAb,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,iCAAiC;MAC1CC,IAAI,EAAE;QAAEU;MAAe;IACzB,CAAC,CAAC;IACF;EACF;EAEAA,cAAc,EAAEE,OAAO,CAAC,MAAOtB,IAAI,IAAK;IACtC,MAAMuB,QAAQ,GAAG,IAAIC,YAAK,CAAC;MACzBC,UAAU,EAAE;QACVC,IAAI,EAAE1B,IAAI;QACV2B,OAAO,EAAEA,CAAC;UAAEC,IAAI;UAAE5B,IAAI;UAAE6B;QAAQ,CAAC,KAAK;UACpC;UACA,MAAMC,SAAS,GAAG9C,OAAO,CAACgB,IAAI,IAAI,EAAE,CAAC;UACrC,OAAO;YACL4B,IAAI;YACJG,EAAE,EAAE,MAAAA,CAAA,KAAYD,SAAS,CAACC,EAAE,CAACF,OAAO,CAAC;YACrCG,IAAI,EAAE,MAAAA,CAAA,KAAYF,SAAS,CAACE,IAAI,CAACH,OAAO;UAC1C,CAAC;QACH;MACF,CAAC;MACDA,OAAO,EAAEZ,oBAAS,CAACgB,iBAAiB,CAAC,CAAC;MACtCC,OAAO,EAAE,IAAIC,uBAAgB,CAAC;QAAElB,SAAS,EAATA;MAAU,CAAC,CAAC;MAC5CmB,MAAM,EAAEC;IACV,CAAC,CAAC;IAEF,IAAA7B,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,sCAAsC;MAC/CC,IAAI,EAAE;QAAEV;MAAK;IACf,CAAC,CAAC;IACF,MAAMuB,QAAQ,CAACQ,EAAE,CAAC,CAAC;IACnBM,OAAO,CAACC,GAAG,CAAC,wBAAwB,CAAC;EACvC,CAAC,CAAC;AACJ;;AAEA;AACO,eAAeC,kBAAkBA,CAAA,EAAkB;EACxD,IAAI,CAACtB,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE,IAAI,CAACZ,OAAO,CAACI,GAAG,CAACuC,QAAQ,EACvB,MAAM,IAAItB,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA0B,CAAC,CAAC;;EAE/D;EACA,MAAMgB,UAAU,GAAG,MAAMgB,qBAAa,CAACC,OAAO,CAAC;IAC7CC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxBC,GAAG,EAAE;EACP,CAAC,CAAC;EACF,MAAMC,aAAa,GAAGpB,UAAU,CAACqB,IAAI,CAClChB,SAAS,IACRA,SAAS,CAACiB,OAAO,IACjB,IAAAC,4BAAa,EAAClB,SAAS,CAACiB,OAAO,EAAElD,OAAO,CAACI,GAAG,CAACuC,QAAkB,CAAC,KAAK,CACzE,CAAC;EAED,IAAI,CAACK,aAAa,EAAE;IAClB,IAAArC,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,oDAAoD;MAC7DC,IAAI,EAAE;QAAEuC,OAAO,EAAEpD,OAAO,CAACI,GAAG,CAACuC;MAAS;IACxC,CAAC,CAAC;IACF;EACF;EAEA,MAAMpB,cAAc,GAAG1B,iBAAiB,CAAC,CAAC;EAE1C,IAAI,CAAC0B,cAAc,IAAIA,cAAc,CAACC,MAAM,IAAI,CAAC,EAAE;IACjD,IAAAb,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,8CAA8C;MACvDC,IAAI,EAAE;QAAEU;MAAe;IACzB,CAAC,CAAC;IACF;EACF;EAEAA,cAAc,CAACE,OAAO,CAAC,MAAOtB,IAAI,IAAK;IACrC,MAAMuB,QAAQ,GAAG,IAAIC,YAAK,CAAC;MACzBC,UAAU,EAAE;QACVC,IAAI,EAAE1B,IAAI;QACV2B,OAAO,EAAEA,CAAC;UAAEC,IAAI;UAAE5B,IAAI;UAAE6B;QAAQ,CAAC,KAAK;UACpC,MAAMC,SAAS,GAAG9C,OAAO,CAACgB,IAAI,IAAI,EAAE,CAAC;UACrC,OAAO;YACL4B,IAAI;YACJG,EAAE,EAAE,MAAAA,CAAA,KAAYD,SAAS,CAACC,EAAE,CAACF,OAAO,CAAC;YACrCG,IAAI,EAAE,MAAAA,CAAA,KAAYF,SAAS,CAACE,IAAI,CAACH,OAAO;UAC1C,CAAC;QACH;MACF,CAAC;MACDA,OAAO,EAAEZ,oBAAS,CAACgB,iBAAiB,CAAC,CAAC;MACtCC,OAAO,EAAE,IAAIC,uBAAgB,CAAC;QAAElB,SAAS,EAATA;MAAU,CAAC,CAAC;MAC5CmB,MAAM,EAAEC;IACV,CAAC,CAAC;IAEF,IAAA7B,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,kCAAkCoC,aAAa,CAACjB,IAAI,EAAE;MAC/DlB,IAAI,EAAE;QAAEV;MAAK;IACf,CAAC,CAAC;IAEF,MAAMuB,QAAQ,CAACS,IAAI,CAAC;MAAEkB,EAAE,EAAEL,aAAa,CAACjB;IAAK,CAAC,CAAC;EACjD,CAAC,CAAC;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACO,eAAeuB,cAAcA,CAClCC,OAA0B,GAAG,CAAC,CAAC,EAChB;EACf,IAAI,CAACnC,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE,MAAMQ,oBAAS,CAACoC,KAAK,CACnB,qBAAqBxD,OAAO,CAACI,GAAG,CAACqD,QAAQ,KAAK,UAAU,GAAG,UAAU,GAAG,EAAE,EAC5E,CAAC;EACD,MAAMrC,oBAAS,CAACoC,KAAK,CAAC,sBAAsB,CAAC;EAC7C,IAAI,CAACD,OAAO,CAACG,KAAK,EAAE,MAAMvC,oBAAoB,CAAC,CAAC;AAClD;;AAEA;AACA;AACA;AACA;AACA;AACO,eAAewC,WAAWA,CAACJ,OAAuB,GAAG,CAAC,CAAC,EAAiB;EAC7E,IAAI,CAACnC,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE,MAAMQ,oBAAS,CAACwC,WAAW,CAACC,kBAAkB,CAACzC,oBAAS,EAAEmC,OAAO,CAAC,CAAC;AACrE;;AAEA;AACA,SAASM,kBAAkBA,CAACzC,SAAoB,EAAEmC,OAAuB,EAAE;EACzE,OAAO,MAAOO,CAAc,IAAoB;IAC9C,KAAK,MAAMC,KAAK,IAAIC,MAAM,CAACC,IAAI,CAAC7C,SAAS,CAAC8C,MAAM,CAAC,EAAE;MACjD;MACA,IAAI,CAACX,OAAO,CAACY,eAAe,IAAIJ,KAAK,KAAK,eAAe,EAAE;MAC3D,MAAMK,KAAK,GAAGhD,SAAS,CAAC8C,MAAM,CAACH,KAAK,CAAC,CAACM,SAAS;MAC/C,MAAMjD,SAAS,CAACoC,KAAK,CACnB,YAAYY,KAAK,GAAGpE,OAAO,CAACI,GAAG,CAACqD,QAAQ,KAAK,UAAU,GAAG,UAAU,GAAG,EAAE,GAAG,EAC5E;QACEV,GAAG,EAAE,IAAI;QACTa,WAAW,EAAEE;MACf,CACF,CAAC;IACH;EACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { RequestUser } from "../../middleware/authJwt/authJwt.types";
|
|
2
1
|
/** Content of the payload of user authentication tokens */
|
|
3
2
|
export interface UserTokenPayload {
|
|
4
3
|
/** ID of the user */
|
|
@@ -16,5 +15,5 @@ export interface UserTokenPayload {
|
|
|
16
15
|
/** List of permissions that the user has (only on the admin API) */
|
|
17
16
|
per?: Array<string> | string;
|
|
18
17
|
/** User */
|
|
19
|
-
user:
|
|
18
|
+
user: Record<string, any> | undefined;
|
|
20
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.types.js","names":[],"sources":["../../../src/utils/jwt/jwt.types.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"jwt.types.js","names":[],"sources":["../../../src/utils/jwt/jwt.types.ts"],"sourcesContent":["\n/** Content of the payload of user authentication tokens */\nexport interface UserTokenPayload {\n /** ID of the user */\n sub: string;\n /** URL of the service that issued the token */\n iss: string;\n /** URL of the services that can consume the token */\n aud: Array<string> | string;\n /** Unique ID of the token */\n jti: string;\n /** ID of the device the token was issued to */\n dev: string;\n /** Timestamp at which the token will expire */\n exp: number;\n /** List of permissions that the user has (only on the admin API) */\n per?: Array<string> | string;\n /** User */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n user: Record<string, any> | undefined;\n}\n"],"mappings":"","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-server-engine",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Framework used to develop backend services. This package ships with a lot of features to standardize the creation of services, letting you focus on the business logic.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -41,13 +41,14 @@
|
|
|
41
41
|
"@elastic/elasticsearch": "^8.15.0",
|
|
42
42
|
"@google-cloud/pubsub": "^4.7.2",
|
|
43
43
|
"@google-cloud/storage": "^7.13.0",
|
|
44
|
+
"@google/generative-ai": "^0.21.0",
|
|
44
45
|
"@opentelemetry/api": "^1.9.0",
|
|
45
46
|
"@opentelemetry/core": "^1.26.0",
|
|
46
47
|
"@opentelemetry/exporter-prometheus": "^0.53.0",
|
|
47
48
|
"@opentelemetry/metrics": "^0.24.0",
|
|
48
49
|
"ajv": "^8.17.1",
|
|
49
50
|
"axios": "^1.7.7",
|
|
50
|
-
"backend-test-tools": "^1.0.
|
|
51
|
+
"backend-test-tools": "^1.0.2",
|
|
51
52
|
"body-parser": "^1.20.3",
|
|
52
53
|
"busboy": "^1.6.0",
|
|
53
54
|
"callsite": "^1.0.0",
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"mime-types": "^2.1.35",
|
|
71
72
|
"morgan": "^1.10.0",
|
|
72
73
|
"ms": "^2.1.3",
|
|
74
|
+
"multer": "^1.4.5-lts.1",
|
|
73
75
|
"mysql2": "^3.11.3",
|
|
74
76
|
"nock": "^13.5.5",
|
|
75
77
|
"nodemon": "^3.1.7",
|
|
@@ -117,12 +119,14 @@
|
|
|
117
119
|
"@types/mock-fs": "^4.13.4",
|
|
118
120
|
"@types/mock-require": "^2.0.3",
|
|
119
121
|
"@types/morgan": "^1.9.9",
|
|
122
|
+
"@types/multer": "^1.4.12",
|
|
120
123
|
"@types/node": "^22.8.4",
|
|
121
124
|
"@types/response-time": "^2.3.8",
|
|
122
125
|
"@types/sequelize": "^4.28.20",
|
|
123
126
|
"@types/sinon-chai": "^3.2.6",
|
|
124
127
|
"@types/supertest": "^6.0.2",
|
|
125
128
|
"@types/swagger-ui-express": "^4.1.6",
|
|
129
|
+
"@types/tmp": "^0.2.6",
|
|
126
130
|
"@types/umzug": "^2.3.7",
|
|
127
131
|
"@types/validator": "^13.12.2",
|
|
128
132
|
"@types/ws": "^8.5.12",
|
|
@@ -132,7 +136,6 @@
|
|
|
132
136
|
"babel-plugin-module-resolver": "^5.0.2",
|
|
133
137
|
"chai": "^4.3.0",
|
|
134
138
|
"chai-as-promised": "^7.1.1",
|
|
135
|
-
"cpy-cli": "^5.0.0",
|
|
136
139
|
"eslint": "^9.13.0",
|
|
137
140
|
"factory-waifu": "^1.0.1",
|
|
138
141
|
"globals": "^15.11.0",
|
|
@@ -148,6 +151,7 @@
|
|
|
148
151
|
"sinon": "^9.2.4",
|
|
149
152
|
"sinon-chai": "^3.5.0",
|
|
150
153
|
"supertest": "^7.0.0",
|
|
154
|
+
"tmp": "^0.2.3",
|
|
151
155
|
"ts-node": "^10.9.2",
|
|
152
156
|
"tsc-alias": "^1.8.10",
|
|
153
157
|
"tsconfig-paths": "^4.2.0",
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
authTls,
|
|
17
17
|
authStatic,
|
|
18
18
|
authAdmin,
|
|
19
|
-
RequestUser,
|
|
20
19
|
FileUploaderConfig,
|
|
21
20
|
RequestAdminProps
|
|
22
21
|
} from 'middleware';
|
|
@@ -52,7 +51,8 @@ export type Middleware<T extends EndpointAuthType> = (
|
|
|
52
51
|
|
|
53
52
|
export type MiddlewareChainElement<T extends EndpointAuthType> =
|
|
54
53
|
| Array<Middleware<T>>
|
|
55
|
-
| Middleware<T
|
|
54
|
+
| Middleware<T>
|
|
55
|
+
| any;
|
|
56
56
|
|
|
57
57
|
/** Auth related parameters used with Admin authentication */
|
|
58
58
|
interface EndpointAuthAdminParams {
|
|
@@ -157,7 +157,7 @@ export interface JwtRequest<
|
|
|
157
157
|
Locals extends Record<string, any> = Record<string, any>
|
|
158
158
|
> extends Request<P, ResBody, ReqBody, ReqQuery, Locals> {
|
|
159
159
|
/** User that identified using a JWT */
|
|
160
|
-
user:
|
|
160
|
+
user: Record<string, any> | any;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/** Request type when using mTLS authentication */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
|
|
1
3
|
// Override the Express request object to add the files
|
|
2
4
|
declare global {
|
|
3
5
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
@@ -5,21 +7,8 @@ declare global {
|
|
|
5
7
|
/** Express request object */
|
|
6
8
|
interface Request {
|
|
7
9
|
/** User that identified using a JWT */
|
|
8
|
-
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
user?: Record<string, any>;
|
|
9
12
|
}
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
|
-
|
|
13
|
-
/** User properties of the request object */
|
|
14
|
-
export interface RequestUser {
|
|
15
|
-
/** ID of the user */
|
|
16
|
-
id: string;
|
|
17
|
-
/** ID of the token used to identify */
|
|
18
|
-
tokenId: string;
|
|
19
|
-
/** ID of the device used by the client to obtain the token */
|
|
20
|
-
deviceId: string;
|
|
21
|
-
/** Name of the user */
|
|
22
|
-
name: string;
|
|
23
|
-
/** Email of the user */
|
|
24
|
-
email: string;
|
|
25
|
-
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import multer from 'multer';
|
|
3
|
+
import { GoogleAIFileManager } from '@google/generative-ai/server';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import tmp from 'tmp';
|
|
7
|
+
import { reportError, reportDebug } from 'utils/report';
|
|
8
|
+
import { checkEnvironment } from 'utils/checkEnvironment';
|
|
9
|
+
import { envAssert } from 'utils/envAssert';
|
|
10
|
+
|
|
11
|
+
const namespace = 'engine:middleware:geminiFileUploader';
|
|
12
|
+
|
|
13
|
+
const apiKey = process.env.GOOGLE_AI_KEY ?? '';
|
|
14
|
+
const fileManager = new GoogleAIFileManager(apiKey);
|
|
15
|
+
|
|
16
|
+
const storage = multer.memoryStorage();
|
|
17
|
+
|
|
18
|
+
async function uploadToGemini(
|
|
19
|
+
buffer: Buffer,
|
|
20
|
+
mimeType: string,
|
|
21
|
+
originalName: string
|
|
22
|
+
): Promise<{ name: string; uri: string; mimeType: string }> {
|
|
23
|
+
// Add 'name' to the return type
|
|
24
|
+
const tempFile = tmp.fileSync({ postfix: path.extname(originalName) });
|
|
25
|
+
|
|
26
|
+
fs.writeFileSync(tempFile.name, buffer);
|
|
27
|
+
|
|
28
|
+
const uploadResult = await fileManager.uploadFile(tempFile.name, {
|
|
29
|
+
mimeType,
|
|
30
|
+
displayName: originalName
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
tempFile.removeCallback();
|
|
34
|
+
|
|
35
|
+
const file = uploadResult.file;
|
|
36
|
+
reportDebug({
|
|
37
|
+
namespace,
|
|
38
|
+
message: 'Uploaded file',
|
|
39
|
+
data: { displayName: file.displayName, name: file.name }
|
|
40
|
+
});
|
|
41
|
+
return { name: file.name, uri: file.uri, mimeType: file.mimeType }; // Include 'name' in the return object
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function waitForFilesActive(
|
|
45
|
+
files: { name: string; uri: string; mimeType: string }[]
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
reportDebug({
|
|
48
|
+
namespace,
|
|
49
|
+
message: 'Waiting for file processing...'
|
|
50
|
+
});
|
|
51
|
+
for (const { name } of files) {
|
|
52
|
+
let file = await fileManager.getFile(name);
|
|
53
|
+
while (file.state === 'PROCESSING') {
|
|
54
|
+
process.stdout.write('.');
|
|
55
|
+
await new Promise((resolve) => setTimeout(resolve, 10_000));
|
|
56
|
+
file = await fileManager.getFile(name);
|
|
57
|
+
}
|
|
58
|
+
if (file.state !== 'ACTIVE') {
|
|
59
|
+
reportError(`File ${file.name} failed to process`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
reportDebug({
|
|
63
|
+
namespace,
|
|
64
|
+
message: 'all files ready...\n'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function geminiFileUploader(
|
|
69
|
+
req: express.Request,
|
|
70
|
+
res: express.Response,
|
|
71
|
+
next: express.NextFunction
|
|
72
|
+
): Promise<void> {
|
|
73
|
+
try {
|
|
74
|
+
checkEnvironment({
|
|
75
|
+
GOOGLE_AI_KEY: envAssert.isString()
|
|
76
|
+
});
|
|
77
|
+
// Use multer.single() inside the middleware
|
|
78
|
+
const uploadSingle = multer({ storage }).single('file');
|
|
79
|
+
|
|
80
|
+
uploadSingle(req, res, async (err) => {
|
|
81
|
+
if (err) {
|
|
82
|
+
reportError(`Error uploading file`);
|
|
83
|
+
next(err);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const file = req.file;
|
|
88
|
+
if (!file) {
|
|
89
|
+
reportError(`No file uploaded`);
|
|
90
|
+
next(`No file uploaded`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const mimeType = file.mimetype;
|
|
94
|
+
|
|
95
|
+
const uploadedFile = await uploadToGemini(
|
|
96
|
+
file.buffer,
|
|
97
|
+
mimeType,
|
|
98
|
+
file.originalname
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
await waitForFilesActive([uploadedFile]);
|
|
102
|
+
|
|
103
|
+
// Set the fileUri and mimeType in the request object for the next middleware/route handler
|
|
104
|
+
req.body.file = {
|
|
105
|
+
fileUri: uploadedFile.uri,
|
|
106
|
+
mimeType: uploadedFile.mimeType,
|
|
107
|
+
originalname: file.originalname
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
next(); // Proceed to the next middleware or route handler
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(error);
|
|
114
|
+
reportError(`Failed to upload or process file`);
|
|
115
|
+
next(error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './geminiFileUploader';
|
package/src/middleware/index.ts
CHANGED
|
@@ -8,13 +8,13 @@ describe('Middleware - User Resolver', function () {
|
|
|
8
8
|
it('should expand the user object with its data using its userId', async function () {
|
|
9
9
|
const me = factory.build('user');
|
|
10
10
|
const next = fake();
|
|
11
|
-
const request = { user: { id: me.id } }
|
|
11
|
+
const request: Partial<Request> = { user: { id: me.id } };
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
await userResolver(request, undefined as unknown as Response, next);
|
|
13
|
+
// Call the resolver with the mocked request
|
|
14
|
+
await userResolver(request as Request, undefined as unknown as Response, next);
|
|
15
15
|
|
|
16
16
|
expect(next).to.have.been.called;
|
|
17
|
-
|
|
17
|
+
// expect(request.user).to.deep.equal(me);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
it('should throw an error if there is no userId', async function () {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
2
|
import { EngineError } from 'entities/EngineError';
|
|
3
|
-
import { RequestUser } from 'middleware/authJwt/authJwt.types';
|
|
4
3
|
import { reportDebug } from 'utils';
|
|
5
4
|
|
|
6
5
|
const namespace = 'engine:middleware:userResolver';
|
|
@@ -28,7 +27,7 @@ export async function userResolver(
|
|
|
28
27
|
data: { user, request: request.user }
|
|
29
28
|
});
|
|
30
29
|
request.user = {
|
|
31
|
-
...
|
|
30
|
+
...request?.user,
|
|
32
31
|
...user
|
|
33
32
|
};
|
|
34
33
|
|
|
@@ -82,7 +82,7 @@ export async function runPendingMigrations(): Promise<void> {
|
|
|
82
82
|
data: { path }
|
|
83
83
|
});
|
|
84
84
|
await migrator.up();
|
|
85
|
-
console.log('Db Migration Completed')
|
|
85
|
+
console.log('Db Migration Completed');
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -94,7 +94,10 @@ export async function rollbackMigrations(): Promise<void> {
|
|
|
94
94
|
throw new EngineError({ message: 'BUILD_ID is not defined' });
|
|
95
95
|
|
|
96
96
|
// Fetch executed migrations in ascending order
|
|
97
|
-
const migrations = await SequelizeMeta.findAll({
|
|
97
|
+
const migrations = await SequelizeMeta.findAll({
|
|
98
|
+
order: [['name', 'ASC']],
|
|
99
|
+
raw: true
|
|
100
|
+
});
|
|
98
101
|
const rollbackUntil = migrations.find(
|
|
99
102
|
(migration) =>
|
|
100
103
|
migration.version &&
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { RequestUser } from "middleware/authJwt/authJwt.types";
|
|
2
1
|
|
|
3
2
|
/** Content of the payload of user authentication tokens */
|
|
4
3
|
export interface UserTokenPayload {
|
|
@@ -17,5 +16,6 @@ export interface UserTokenPayload {
|
|
|
17
16
|
/** List of permissions that the user has (only on the admin API) */
|
|
18
17
|
per?: Array<string> | string;
|
|
19
18
|
/** User */
|
|
20
|
-
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
user: Record<string, any> | undefined;
|
|
21
21
|
}
|