@modular-rest/server 1.18.1 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nvmrc +1 -1
- package/dist/application.js +5 -4
- package/dist/class/collection_definition.d.ts +28 -3
- package/dist/class/collection_definition.js +72 -2
- package/dist/class/combinator.js +7 -3
- package/dist/class/directory.d.ts +2 -4
- package/dist/class/directory.js +42 -64
- package/dist/helper/data_insertion.js +93 -26
- package/dist/index.d.ts +12 -1
- package/dist/index.js +13 -1
- package/dist/services/data_provider/model_registry.d.ts +72 -0
- package/dist/services/data_provider/model_registry.js +214 -0
- package/dist/services/data_provider/service.js +73 -14
- package/dist/services/file/service.d.ts +47 -78
- package/dist/services/file/service.js +114 -155
- package/dist/services/functions/service.js +4 -4
- package/dist/services/jwt/router.js +2 -1
- package/dist/services/user_manager/router.js +1 -1
- package/dist/services/user_manager/service.js +48 -17
- package/jest.config.ts +18 -0
- package/package.json +11 -2
- package/src/application.ts +5 -4
- package/src/class/collection_definition.ts +94 -4
- package/src/class/combinator.ts +10 -3
- package/src/class/directory.ts +40 -58
- package/src/helper/data_insertion.ts +101 -27
- package/src/index.ts +13 -1
- package/src/services/data_provider/model_registry.ts +243 -0
- package/src/services/data_provider/service.ts +74 -14
- package/src/services/file/service.ts +136 -178
- package/src/services/functions/service.ts +4 -4
- package/src/services/jwt/router.ts +2 -1
- package/src/services/user_manager/router.ts +1 -1
- package/src/services/user_manager/service.ts +49 -20
- package/tests/helpers/test-app.ts +182 -0
- package/tests/router/data-provider.router.int.test.ts +192 -0
- package/tests/router/file.router.int.test.ts +104 -0
- package/tests/router/functions.router.int.test.ts +91 -0
- package/tests/router/jwt.router.int.test.ts +69 -0
- package/tests/router/user-manager.router.int.test.ts +85 -0
- package/tests/setup/jest.setup.ts +5 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.modelRegistry = void 0;
|
|
7
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
8
|
+
/**
|
|
9
|
+
* ModelRegistry - Singleton class for managing mongoose models and connections
|
|
10
|
+
* Pre-creates all models before database connections are established
|
|
11
|
+
*/
|
|
12
|
+
class ModelRegistry {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.connections = {};
|
|
15
|
+
this.models = {};
|
|
16
|
+
this.collectionDefinitions = [];
|
|
17
|
+
this.mongoOption = null;
|
|
18
|
+
// Private constructor for singleton pattern
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the singleton instance of ModelRegistry
|
|
22
|
+
* @returns {ModelRegistry} The singleton instance
|
|
23
|
+
*/
|
|
24
|
+
static getInstance() {
|
|
25
|
+
if (!ModelRegistry.instance) {
|
|
26
|
+
ModelRegistry.instance = new ModelRegistry();
|
|
27
|
+
}
|
|
28
|
+
return ModelRegistry.instance;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Register a collection definition and create its model
|
|
32
|
+
* @param {CollectionDefinition} definition - The collection definition
|
|
33
|
+
* @param {MongoOption} mongoOption - MongoDB connection options
|
|
34
|
+
* @returns {Model<any>} The created mongoose model
|
|
35
|
+
*/
|
|
36
|
+
registerCollection(definition, mongoOption) {
|
|
37
|
+
// Store mongoOption if not already stored
|
|
38
|
+
if (!this.mongoOption) {
|
|
39
|
+
this.mongoOption = mongoOption;
|
|
40
|
+
}
|
|
41
|
+
const { database, collection, schema } = definition;
|
|
42
|
+
// Check if this definition is already registered
|
|
43
|
+
const isAlreadyRegistered = this.collectionDefinitions.some(def => def.database === database && def.collection === collection);
|
|
44
|
+
// Store collection definition if not already registered
|
|
45
|
+
if (!isAlreadyRegistered) {
|
|
46
|
+
this.collectionDefinitions.push(definition);
|
|
47
|
+
}
|
|
48
|
+
// Initialize models object for this database if needed
|
|
49
|
+
if (!this.models[database]) {
|
|
50
|
+
this.models[database] = {};
|
|
51
|
+
}
|
|
52
|
+
// Check if model already exists
|
|
53
|
+
if (this.models[database][collection]) {
|
|
54
|
+
return this.models[database][collection];
|
|
55
|
+
}
|
|
56
|
+
// Get or create connection for this database
|
|
57
|
+
let connection = this.connections[database];
|
|
58
|
+
if (!connection) {
|
|
59
|
+
const fullDbName = (mongoOption.dbPrefix || '') + database;
|
|
60
|
+
const connectionString = mongoOption.mongoBaseAddress;
|
|
61
|
+
// Create connection (but don't connect yet)
|
|
62
|
+
connection = mongoose_1.default.createConnection(connectionString, {
|
|
63
|
+
useUnifiedTopology: true,
|
|
64
|
+
useNewUrlParser: true,
|
|
65
|
+
dbName: fullDbName,
|
|
66
|
+
serverSelectionTimeoutMS: 10000, // 10 second timeout for server selection
|
|
67
|
+
socketTimeoutMS: 45000, // 45 second timeout for socket operations
|
|
68
|
+
});
|
|
69
|
+
this.connections[database] = connection;
|
|
70
|
+
}
|
|
71
|
+
// Create model on the connection
|
|
72
|
+
// Mongoose allows creating models before connection is established
|
|
73
|
+
const model = connection.model(collection, schema);
|
|
74
|
+
this.models[database][collection] = model;
|
|
75
|
+
return model;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get a model by database and collection name
|
|
79
|
+
* @param {string} database - Database name
|
|
80
|
+
* @param {string} collection - Collection name
|
|
81
|
+
* @returns {Model<any> | null} The mongoose model or null if not found
|
|
82
|
+
*/
|
|
83
|
+
getModel(database, collection) {
|
|
84
|
+
if (!this.models[database] || !this.models[database][collection]) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return this.models[database][collection];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get a connection for a database
|
|
91
|
+
* @param {string} database - Database name
|
|
92
|
+
* @returns {Connection | null} The mongoose connection or null if not found
|
|
93
|
+
*/
|
|
94
|
+
getConnection(database) {
|
|
95
|
+
return this.connections[database] || null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Initialize all connections and connect to databases
|
|
99
|
+
* This should be called during server startup
|
|
100
|
+
* @param {MongoOption} mongoOption - MongoDB connection options
|
|
101
|
+
* @returns {Promise<void>} A promise that resolves when all connections are established
|
|
102
|
+
*/
|
|
103
|
+
async initializeConnections(mongoOption) {
|
|
104
|
+
this.mongoOption = mongoOption;
|
|
105
|
+
// Group collection definitions by database
|
|
106
|
+
const dbGroups = {};
|
|
107
|
+
this.collectionDefinitions.forEach(definition => {
|
|
108
|
+
if (!dbGroups[definition.database]) {
|
|
109
|
+
dbGroups[definition.database] = [];
|
|
110
|
+
}
|
|
111
|
+
dbGroups[definition.database].push(definition);
|
|
112
|
+
});
|
|
113
|
+
// Connect to each database
|
|
114
|
+
const connectionPromises = Object.entries(dbGroups).map(([dbName]) => {
|
|
115
|
+
return new Promise((done, reject) => {
|
|
116
|
+
const connection = this.connections[dbName];
|
|
117
|
+
if (!connection) {
|
|
118
|
+
// If connection doesn't exist, create it
|
|
119
|
+
const fullDbName = (mongoOption.dbPrefix || '') + dbName;
|
|
120
|
+
const connectionString = mongoOption.mongoBaseAddress;
|
|
121
|
+
const newConnection = mongoose_1.default.createConnection(connectionString, {
|
|
122
|
+
useUnifiedTopology: true,
|
|
123
|
+
useNewUrlParser: true,
|
|
124
|
+
dbName: fullDbName,
|
|
125
|
+
serverSelectionTimeoutMS: 10000, // 10 second timeout for server selection
|
|
126
|
+
socketTimeoutMS: 45000, // 45 second timeout for socket operations
|
|
127
|
+
});
|
|
128
|
+
this.connections[dbName] = newConnection;
|
|
129
|
+
// Create models for this database if they don't exist
|
|
130
|
+
const definitions = dbGroups[dbName];
|
|
131
|
+
definitions.forEach(def => {
|
|
132
|
+
if (!this.models[dbName]) {
|
|
133
|
+
this.models[dbName] = {};
|
|
134
|
+
}
|
|
135
|
+
if (!this.models[dbName][def.collection]) {
|
|
136
|
+
this.models[dbName][def.collection] = newConnection.model(def.collection, def.schema);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
newConnection.on('connected', () => {
|
|
140
|
+
console.info(`- ${fullDbName} database has been connected`);
|
|
141
|
+
done();
|
|
142
|
+
});
|
|
143
|
+
newConnection.on('error', err => {
|
|
144
|
+
reject(err);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// Connection already exists, just wait for it to be ready
|
|
149
|
+
if (connection.readyState === 1) {
|
|
150
|
+
// Already connected
|
|
151
|
+
done();
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
connection.once('connected', () => {
|
|
155
|
+
done();
|
|
156
|
+
});
|
|
157
|
+
connection.once('error', err => {
|
|
158
|
+
reject(err);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
await Promise.all(connectionPromises);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get all registered collection definitions
|
|
168
|
+
* @returns {CollectionDefinition[]} Array of collection definitions
|
|
169
|
+
*/
|
|
170
|
+
getCollectionDefinitions() {
|
|
171
|
+
return [...this.collectionDefinitions];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get all models for a specific database
|
|
175
|
+
* @param {string} database - Database name
|
|
176
|
+
* @returns {Record<string, Model<any>> | null} Object mapping collection names to models, or null if database not found
|
|
177
|
+
*/
|
|
178
|
+
getModelsForDatabase(database) {
|
|
179
|
+
return this.models[database] || null;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Check if a model exists
|
|
183
|
+
* @param {string} database - Database name
|
|
184
|
+
* @param {string} collection - Collection name
|
|
185
|
+
* @returns {boolean} True if model exists, false otherwise
|
|
186
|
+
*/
|
|
187
|
+
hasModel(database, collection) {
|
|
188
|
+
return !!(this.models[database] && this.models[database][collection]);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Clear all internal state, including connections and models.
|
|
192
|
+
* Useful for testing when different database prefixes are used.
|
|
193
|
+
*/
|
|
194
|
+
async clear() {
|
|
195
|
+
// Close all connections first
|
|
196
|
+
await Promise.all(Object.values(this.connections).map(async (connection) => {
|
|
197
|
+
if (connection.readyState !== 0) {
|
|
198
|
+
try {
|
|
199
|
+
await connection.close();
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
// Ignore close errors
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}));
|
|
206
|
+
this.connections = {};
|
|
207
|
+
this.models = {};
|
|
208
|
+
this.collectionDefinitions = [];
|
|
209
|
+
this.mongoOption = null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Export singleton instance
|
|
213
|
+
exports.modelRegistry = ModelRegistry.getInstance();
|
|
214
|
+
exports.default = exports.modelRegistry;
|
|
@@ -16,6 +16,7 @@ const trigger_operator_1 = __importDefault(require("../../class/trigger_operator
|
|
|
16
16
|
exports.triggers = trigger_operator_1.default;
|
|
17
17
|
const typeCasters_1 = __importDefault(require("./typeCasters"));
|
|
18
18
|
exports.TypeCasters = typeCasters_1.default;
|
|
19
|
+
const model_registry_1 = __importDefault(require("./model_registry"));
|
|
19
20
|
/**
|
|
20
21
|
* Service name constant
|
|
21
22
|
* @constant {string}
|
|
@@ -39,15 +40,25 @@ const permissionDefinitions = {};
|
|
|
39
40
|
*/
|
|
40
41
|
function connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList = [], mongoOption) {
|
|
41
42
|
return new Promise((done, reject) => {
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
// Check if connection already exists in registry
|
|
44
|
+
let connection = model_registry_1.default.getConnection(dbName);
|
|
45
|
+
// Create db connection if it doesn't exist
|
|
46
|
+
if (!connection) {
|
|
47
|
+
const fullDbName = (mongoOption.dbPrefix || '') + dbName;
|
|
48
|
+
const connectionString = mongoOption.mongoBaseAddress;
|
|
49
|
+
console.info(`- Connecting to database: ${fullDbName}`);
|
|
50
|
+
connection = mongoose_1.default.createConnection(connectionString, {
|
|
51
|
+
useUnifiedTopology: true,
|
|
52
|
+
useNewUrlParser: true,
|
|
53
|
+
dbName: fullDbName,
|
|
54
|
+
serverSelectionTimeoutMS: 10000, // 10 second timeout for server selection
|
|
55
|
+
socketTimeoutMS: 45000, // 45 second timeout for socket operations
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const fullDbName = (mongoOption.dbPrefix || '') + dbName;
|
|
60
|
+
console.info(`- Using existing connection for database: ${fullDbName}`);
|
|
61
|
+
}
|
|
51
62
|
// Store connection
|
|
52
63
|
connections[dbName] = connection;
|
|
53
64
|
// add db models from schemas
|
|
@@ -58,10 +69,30 @@ function connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitio
|
|
|
58
69
|
collections[dbName] = {};
|
|
59
70
|
if (permissionDefinitions[dbName] == undefined)
|
|
60
71
|
permissionDefinitions[dbName] = {};
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
// Check if model already exists in registry (pre-created)
|
|
73
|
+
let model = model_registry_1.default.getModel(dbName, collection);
|
|
74
|
+
if (!model) {
|
|
75
|
+
// Model doesn't exist in registry, create it on the connection
|
|
76
|
+
// This can happen if defineCollection was called without mongoOption
|
|
77
|
+
model = connection.model(collection, schema);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// Model exists in registry, verify it's using the same connection
|
|
81
|
+
// Mongoose models are bound to their connection, so we should use the registry model
|
|
82
|
+
// But we need to ensure the connection matches
|
|
83
|
+
const registryConnection = model_registry_1.default.getConnection(dbName);
|
|
84
|
+
if (registryConnection && registryConnection !== connection) {
|
|
85
|
+
// Connections don't match, but this shouldn't happen in normal flow
|
|
86
|
+
// Use the model from registry as it's already created
|
|
87
|
+
model = model_registry_1.default.getModel(dbName, collection);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Store model in global collections object
|
|
64
91
|
collections[dbName][collection] = model;
|
|
92
|
+
// Also update the CollectionDefinition with the model if it has a setModel method
|
|
93
|
+
if (collectionDefinition.setModel) {
|
|
94
|
+
collectionDefinition.setModel(model);
|
|
95
|
+
}
|
|
65
96
|
// define Access Definition from component permissions
|
|
66
97
|
// and store it on global access definition object
|
|
67
98
|
permissionDefinitions[dbName][collection] = new security_1.AccessDefinition({
|
|
@@ -83,10 +114,22 @@ function connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitio
|
|
|
83
114
|
});
|
|
84
115
|
}
|
|
85
116
|
});
|
|
86
|
-
connection
|
|
117
|
+
// If connection is already connected, resolve immediately
|
|
118
|
+
if (connection.readyState === 1) {
|
|
119
|
+
const fullDbName = (mongoOption.dbPrefix || '') + dbName;
|
|
87
120
|
console.info(`- ${fullDbName} database has been connected`);
|
|
88
121
|
done();
|
|
89
|
-
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
connection.on('connected', () => {
|
|
125
|
+
const fullDbName = (mongoOption.dbPrefix || '') + dbName;
|
|
126
|
+
console.info(`- ${fullDbName} database has been connected`);
|
|
127
|
+
done();
|
|
128
|
+
});
|
|
129
|
+
connection.on('error', err => {
|
|
130
|
+
reject(err);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
90
133
|
});
|
|
91
134
|
}
|
|
92
135
|
/**
|
|
@@ -113,6 +156,15 @@ function connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitio
|
|
|
113
156
|
* ```
|
|
114
157
|
*/
|
|
115
158
|
async function addCollectionDefinitionByList({ list, mongoOption, }) {
|
|
159
|
+
// First, ensure all collections are registered in the ModelRegistry
|
|
160
|
+
// This pre-creates models before connections are established
|
|
161
|
+
list.forEach(collectionDefinition => {
|
|
162
|
+
// Check if model already exists in registry
|
|
163
|
+
if (!model_registry_1.default.hasModel(collectionDefinition.database, collectionDefinition.collection)) {
|
|
164
|
+
// Register the collection and create its model
|
|
165
|
+
model_registry_1.default.registerCollection(collectionDefinition, mongoOption);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
116
168
|
// Group collection definitions by database
|
|
117
169
|
const dbGroups = {};
|
|
118
170
|
list.forEach(collectionDefinition => {
|
|
@@ -122,6 +174,7 @@ async function addCollectionDefinitionByList({ list, mongoOption, }) {
|
|
|
122
174
|
dbGroups[collectionDefinition.database].push(collectionDefinition);
|
|
123
175
|
});
|
|
124
176
|
// Connect to each database
|
|
177
|
+
// Models are already pre-created, so connections will use existing models
|
|
125
178
|
const connectionPromises = Object.entries(dbGroups).map(([dbName, collectionDefinitionList]) => connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList, mongoOption));
|
|
126
179
|
await Promise.all(connectionPromises);
|
|
127
180
|
}
|
|
@@ -185,6 +238,12 @@ function checkAccess(db, collection, operationType, queryOrDoc, user) {
|
|
|
185
238
|
return true;
|
|
186
239
|
if (permission.accessType === 'user_access' && user.type === 'user')
|
|
187
240
|
return true;
|
|
241
|
+
if (typeof user.hasPermission === 'function' && user.hasPermission(permission.accessType)) {
|
|
242
|
+
if (operationType === security_1.AccessTypes.read)
|
|
243
|
+
return permission.read;
|
|
244
|
+
if (operationType === security_1.AccessTypes.write)
|
|
245
|
+
return permission.write;
|
|
246
|
+
}
|
|
188
247
|
return false;
|
|
189
248
|
});
|
|
190
249
|
}
|
|
@@ -21,9 +21,12 @@ interface StoredFileDetail {
|
|
|
21
21
|
* File upload options interface
|
|
22
22
|
* @interface StoreFileOptions
|
|
23
23
|
* @property {Object} file - File details
|
|
24
|
-
* @property {string} file.path - Temporary file path
|
|
25
|
-
* @property {string} file.
|
|
26
|
-
* @property {string} file.
|
|
24
|
+
* @property {string} [file.path] - Temporary file path (legacy)
|
|
25
|
+
* @property {string} [file.filepath] - Temporary file path (koa-body v6+)
|
|
26
|
+
* @property {string} [file.type] - MIME type of the file (legacy)
|
|
27
|
+
* @property {string} [file.mimetype] - MIME type of the file (koa-body v6+)
|
|
28
|
+
* @property {string} [file.name] - Original filename (legacy)
|
|
29
|
+
* @property {string} [file.originalFilename] - Original filename (koa-body v6+)
|
|
27
30
|
* @property {number} file.size - File size in bytes
|
|
28
31
|
* @property {string} ownerId - ID of the file owner
|
|
29
32
|
* @property {string} tag - Tag for file organization
|
|
@@ -31,9 +34,12 @@ interface StoredFileDetail {
|
|
|
31
34
|
*/
|
|
32
35
|
interface StoreFileOptions {
|
|
33
36
|
file: {
|
|
34
|
-
path
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
path?: string;
|
|
38
|
+
filepath?: string;
|
|
39
|
+
type?: string;
|
|
40
|
+
mimetype?: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
originalFilename?: string;
|
|
37
43
|
size: number;
|
|
38
44
|
};
|
|
39
45
|
ownerId: string;
|
|
@@ -41,11 +47,11 @@ interface StoreFileOptions {
|
|
|
41
47
|
removeFileAfterStore?: boolean;
|
|
42
48
|
}
|
|
43
49
|
/**
|
|
44
|
-
* File service for handling file
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
50
|
+
* File service class for handling file operations
|
|
51
|
+
* @class FileService
|
|
52
|
+
* @description
|
|
53
|
+
* This class provides methods for managing file uploads, retrieval, and deletion.
|
|
54
|
+
* It handles physical file storage and database metadata management.
|
|
49
55
|
*/
|
|
50
56
|
declare class FileService {
|
|
51
57
|
/**
|
|
@@ -86,29 +92,17 @@ declare class FileService {
|
|
|
86
92
|
*/
|
|
87
93
|
setUploadDirectory(directoryOrConfig: string | StaticPathOptions): void;
|
|
88
94
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* Creates stored file details with unique filename
|
|
95
|
+
* Creates a unique filename and storage details
|
|
92
96
|
* @param {string} fileType - MIME type of the file
|
|
93
|
-
* @param {string} tag -
|
|
94
|
-
* @returns {StoredFileDetail} Storage details including filename and path
|
|
95
|
-
* @
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* ```typescript
|
|
99
|
-
* import { fileService } from '@modular-rest/server';
|
|
100
|
-
*
|
|
101
|
-
* const details = fileService.createStoredDetail('image/jpeg', 'profile');
|
|
102
|
-
* // Returns: { fileName: '1234567890.jpeg', fullPath: '/uploads/jpeg/profile/1234567890.jpeg', fileFormat: 'jpeg' }
|
|
103
|
-
* ```
|
|
97
|
+
* @param {string} tag - File tag
|
|
98
|
+
* @returns {StoredFileDetail} Storage details including unique filename and path
|
|
99
|
+
* @hidden
|
|
104
100
|
*/
|
|
105
101
|
createStoredDetail(fileType: string, tag: string): StoredFileDetail;
|
|
106
102
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* Stores a file, removes the temporary file, and saves metadata to database
|
|
103
|
+
* Stores a file on disc and creates metadata in database
|
|
110
104
|
* @param {StoreFileOptions} options - File storage options
|
|
111
|
-
* @returns {Promise<IFile>}
|
|
105
|
+
* @returns {Promise<IFile>} The created file document
|
|
112
106
|
* @throws {Error} If upload directory is not set or storage fails
|
|
113
107
|
* @example
|
|
114
108
|
* ```typescript
|
|
@@ -129,75 +123,50 @@ declare class FileService {
|
|
|
129
123
|
*/
|
|
130
124
|
storeFile({ file, ownerId, tag, removeFileAfterStore }: StoreFileOptions): Promise<IFile>;
|
|
131
125
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* @
|
|
136
|
-
* @returns {Promise<void>} Promise resolving when file is removed
|
|
137
|
-
* @throws {Error} If file removal fails
|
|
126
|
+
* Deletes a file from disc and database
|
|
127
|
+
* @param {string} fileId - ID of the file to delete
|
|
128
|
+
* @returns {Promise<boolean>} True if deletion was successful
|
|
129
|
+
* @throws {Error} If file is not found or deletion fails
|
|
138
130
|
* @example
|
|
139
131
|
* ```typescript
|
|
140
132
|
* import { fileService } from '@modular-rest/server';
|
|
141
133
|
*
|
|
142
|
-
* await fileService.
|
|
134
|
+
* await fileService.removeFile('file123');
|
|
143
135
|
* ```
|
|
144
136
|
*/
|
|
145
|
-
|
|
137
|
+
removeFile(fileId: string): Promise<boolean>;
|
|
146
138
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* @
|
|
150
|
-
* @
|
|
151
|
-
* @throws {Error} If file is not found or removal fails
|
|
152
|
-
* @example
|
|
153
|
-
* ```typescript
|
|
154
|
-
* import { fileService } from '@modular-rest/server';
|
|
155
|
-
*
|
|
156
|
-
* try {
|
|
157
|
-
* await fileService.removeFile('file123');
|
|
158
|
-
* console.log('File removed successfully');
|
|
159
|
-
* } catch (error) {
|
|
160
|
-
* console.error('Failed to remove file:', error);
|
|
161
|
-
* }
|
|
162
|
-
* ```
|
|
139
|
+
* Deletes a file from physical storage
|
|
140
|
+
* @param {string} path - Physical path to the file
|
|
141
|
+
* @returns {Promise<boolean>} True if deletion was successful
|
|
142
|
+
* @hidden
|
|
163
143
|
*/
|
|
164
|
-
|
|
144
|
+
removeFromDisc(path: string): Promise<boolean>;
|
|
165
145
|
/**
|
|
166
|
-
* Retrieves a file document from
|
|
167
|
-
*
|
|
168
|
-
* @
|
|
169
|
-
* @
|
|
170
|
-
* @
|
|
171
|
-
* @example
|
|
172
|
-
* ```typescript
|
|
173
|
-
* import { fileService } from '@modular-rest/server';
|
|
174
|
-
*
|
|
175
|
-
* const fileDoc = await fileService.getFile('file123');
|
|
176
|
-
* console.log('File details:', fileDoc);
|
|
177
|
-
* ```
|
|
146
|
+
* Retrieves a file document from database
|
|
147
|
+
* @param {string} fileId - ID of the file
|
|
148
|
+
* @returns {Promise<IFile>} The file document
|
|
149
|
+
* @throws {Error} If file is not found
|
|
150
|
+
* @hidden
|
|
178
151
|
*/
|
|
179
152
|
getFile(fileId: string): Promise<IFile>;
|
|
180
153
|
/**
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* @
|
|
184
|
-
* @returns {Promise<string>} Promise resolving to file URL
|
|
185
|
-
* @throws {Error} If URL path is not defined or file is not found
|
|
154
|
+
* Gets the public URL for a file
|
|
155
|
+
* @param {string} fileId - ID of the file
|
|
156
|
+
* @returns {Promise<string>} The public URL
|
|
186
157
|
* @example
|
|
187
158
|
* ```typescript
|
|
188
159
|
* import { fileService } from '@modular-rest/server';
|
|
189
160
|
*
|
|
190
|
-
* const
|
|
191
|
-
* // Returns: '/
|
|
161
|
+
* const url = await fileService.getFileLink('file123');
|
|
162
|
+
* // Returns: '/assets/jpeg/profile/1234567890.jpeg'
|
|
192
163
|
* ```
|
|
193
164
|
*/
|
|
194
165
|
getFileLink(fileId: string): Promise<string>;
|
|
195
166
|
/**
|
|
196
|
-
* Gets the
|
|
197
|
-
*
|
|
198
|
-
* @
|
|
199
|
-
* @returns {Promise<string>} Promise resolving to full file path
|
|
200
|
-
* @throws {Error} If upload directory is not set or file is not found
|
|
167
|
+
* Gets the physical path for a file
|
|
168
|
+
* @param {string} fileId - ID of the file
|
|
169
|
+
* @returns {Promise<string>} The physical path
|
|
201
170
|
* @example
|
|
202
171
|
* ```typescript
|
|
203
172
|
* import { fileService } from '@modular-rest/server';
|