@modular-rest/server 1.16.2 → 1.17.1
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/application.js +36 -8
- package/dist/config.d.ts +21 -10
- package/dist/helper/presetup_services.d.ts +13 -4
- package/dist/helper/presetup_services.js +16 -5
- package/dist/index.d.ts +23 -0
- package/dist/services/file/service.d.ts +16 -4
- package/dist/services/file/service.js +36 -8
- package/package.json +1 -1
- package/src/application.ts +48 -8
- package/src/config.ts +21 -10
- package/src/helper/presetup_services.ts +30 -6
- package/src/index.ts +26 -0
- package/src/services/file/service.ts +47 -9
package/dist/application.js
CHANGED
|
@@ -104,13 +104,41 @@ async function createRest(options) {
|
|
|
104
104
|
/**
|
|
105
105
|
* Plug In KoaStatic
|
|
106
106
|
*/
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
107
|
+
// Collect static paths from new property or fallback to old property
|
|
108
|
+
let staticPathsToMount = [];
|
|
109
|
+
if (config_1.config.staticPaths && config_1.config.staticPaths.length > 0) {
|
|
110
|
+
// Use new staticPaths property
|
|
111
|
+
staticPathsToMount = config_1.config.staticPaths;
|
|
112
|
+
}
|
|
113
|
+
else if (config_1.config.staticPath) {
|
|
114
|
+
// Backward compatibility: use old staticPath property with deprecation warning
|
|
115
|
+
console.warn('\x1b[33m%s\x1b[0m', "Warning: 'staticPath' is deprecated and will be removed in a future version. Please use 'staticPaths' (array) instead.");
|
|
116
|
+
staticPathsToMount = Array.isArray(config_1.config.staticPath) ? config_1.config.staticPath : [config_1.config.staticPath];
|
|
117
|
+
}
|
|
118
|
+
// Mount all static paths
|
|
119
|
+
for (const staticPathConfig of staticPathsToMount) {
|
|
120
|
+
const directory = staticPathConfig.directory || '';
|
|
121
|
+
const urlPath = staticPathConfig.urlPath || '/assets';
|
|
122
|
+
const staticOptions = { ...staticPathConfig, defer: true };
|
|
123
|
+
delete staticOptions.directory;
|
|
124
|
+
delete staticOptions.urlPath;
|
|
125
|
+
app.use((0, koa_mount_1.default)(urlPath, (0, koa_static_1.default)(directory, staticOptions)));
|
|
126
|
+
}
|
|
127
|
+
// Auto-mount uploadDirectoryConfig if staticPaths (new property) is configured
|
|
128
|
+
if (config_1.config.staticPaths && config_1.config.staticPaths.length > 0 && config_1.config.uploadDirectoryConfig) {
|
|
129
|
+
const uploadDirectory = config_1.config.uploadDirectoryConfig.directory || '';
|
|
130
|
+
const uploadUrlPath = config_1.config.uploadDirectoryConfig.urlPath || '/assets';
|
|
131
|
+
const uploadStaticOptions = {
|
|
132
|
+
...config_1.config.uploadDirectoryConfig,
|
|
133
|
+
defer: true,
|
|
134
|
+
};
|
|
135
|
+
delete uploadStaticOptions.directory;
|
|
136
|
+
delete uploadStaticOptions.urlPath;
|
|
137
|
+
app.use((0, koa_mount_1.default)(uploadUrlPath, (0, koa_static_1.default)(uploadDirectory, uploadStaticOptions)));
|
|
138
|
+
}
|
|
139
|
+
// Show deprecation warning for old uploadDirectory property
|
|
140
|
+
if (config_1.config.uploadDirectory) {
|
|
141
|
+
console.warn('\x1b[33m%s\x1b[0m', "Warning: 'uploadDirectory' is deprecated and will be removed in a future version. Please use 'uploadDirectoryConfig' (StaticPathOptions) instead.");
|
|
114
142
|
}
|
|
115
143
|
/**
|
|
116
144
|
* Run before hook
|
|
@@ -185,7 +213,7 @@ async function createRest(options) {
|
|
|
185
213
|
}
|
|
186
214
|
// 4. Setting up default services
|
|
187
215
|
try {
|
|
188
|
-
await require('./helper/presetup_services').setup(
|
|
216
|
+
await require('./helper/presetup_services').setup(config_1.config);
|
|
189
217
|
}
|
|
190
218
|
catch (e) {
|
|
191
219
|
return Promise.reject(e);
|
package/dist/config.d.ts
CHANGED
|
@@ -8,16 +8,17 @@ import { Options as KoaStaticOptionsBase } from 'koa-static';
|
|
|
8
8
|
/**
|
|
9
9
|
* The options for the static file server, it's a combination of modular-rest and [koa-static options](https://github.com/koajs/static?tab=readme-ov-file#options)
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
11
|
+
export interface StaticPathOptions extends KoaStaticOptionsBase {
|
|
12
12
|
/**
|
|
13
|
-
* The
|
|
13
|
+
* The filesystem directory where static files are stored
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
directory: string;
|
|
16
16
|
/**
|
|
17
|
-
* The path
|
|
17
|
+
* The URL path where static files will be served from
|
|
18
|
+
* @default '/assets'
|
|
18
19
|
*/
|
|
19
|
-
|
|
20
|
-
}
|
|
20
|
+
urlPath?: string;
|
|
21
|
+
}
|
|
21
22
|
/**
|
|
22
23
|
* JWT keypair configuration
|
|
23
24
|
* @interface KeyPair
|
|
@@ -53,9 +54,9 @@ interface AdminUser {
|
|
|
53
54
|
* @interface RestOptions
|
|
54
55
|
* @property {KoaCorsOptions} [cors] - CORS configuration [options](https://github.com/koajs/cors?tab=readme-ov-file#corsoptions)
|
|
55
56
|
* @property {string} [modulesPath] - Path to custom modules directory
|
|
56
|
-
* @property {
|
|
57
|
+
* @property {StaticPathOptions[]} [staticPaths] - Array of static file serving configurations
|
|
58
|
+
* @property {StaticPathOptions} [uploadDirectoryConfig] - Upload directory configuration with static path info
|
|
57
59
|
* @property {any} [koaBodyOptions] - Options for koa-body middleware
|
|
58
|
-
* @property {StaticPathOptions} [staticPath] - Static file serving options
|
|
59
60
|
* @property {Function} [onBeforeInit] - Hook called before initialization
|
|
60
61
|
* @property {Function} [onAfterInit] - Hook called after initialization
|
|
61
62
|
* @property {number} [port] - Port to listen on
|
|
@@ -69,13 +70,15 @@ interface AdminUser {
|
|
|
69
70
|
* @property {CmsTrigger[]} [authTriggers] - Authentication triggers
|
|
70
71
|
* @property {CmsTrigger[]} [fileTriggers] - File handling triggers
|
|
71
72
|
* @property {DefinedFunction[]} [functions] - Custom API functions
|
|
73
|
+
* @property {string} [uploadDirectory] - @deprecated Use uploadDirectoryConfig instead. Directory for file uploads
|
|
74
|
+
* @property {StaticPathOptions | StaticPathOptions[]} [staticPath] - @deprecated Use staticPaths instead. Static file serving options
|
|
72
75
|
*/
|
|
73
76
|
export interface RestOptions {
|
|
74
77
|
cors?: KoaCorsOptions;
|
|
75
78
|
modulesPath?: string;
|
|
76
|
-
|
|
79
|
+
staticPaths?: StaticPathOptions[];
|
|
80
|
+
uploadDirectoryConfig?: StaticPathOptions;
|
|
77
81
|
koaBodyOptions?: any;
|
|
78
|
-
staticPath?: StaticPathOptions;
|
|
79
82
|
onBeforeInit?: (koaApp: Koa) => void;
|
|
80
83
|
onAfterInit?: (koaApp: Koa) => void;
|
|
81
84
|
port?: number;
|
|
@@ -89,6 +92,14 @@ export interface RestOptions {
|
|
|
89
92
|
authTriggers?: CmsTrigger[];
|
|
90
93
|
fileTriggers?: CmsTrigger[];
|
|
91
94
|
functions?: DefinedFunction[];
|
|
95
|
+
/**
|
|
96
|
+
* @deprecated Use uploadDirectoryConfig instead. This property will be removed in a future version.
|
|
97
|
+
*/
|
|
98
|
+
uploadDirectory?: string;
|
|
99
|
+
/**
|
|
100
|
+
* @deprecated Use staticPaths instead. This property will be removed in a future version.
|
|
101
|
+
*/
|
|
102
|
+
staticPath?: StaticPathOptions | StaticPathOptions[];
|
|
92
103
|
}
|
|
93
104
|
/**
|
|
94
105
|
* Global configuration object
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { StaticPathOptions } from '../config';
|
|
1
2
|
/**
|
|
2
3
|
* Setup options interface for initializing required services
|
|
3
4
|
* @interface SetupOptions
|
|
@@ -7,7 +8,8 @@
|
|
|
7
8
|
* @property {Object} adminUser - Admin user configuration
|
|
8
9
|
* @property {string} adminUser.email - Admin user email address
|
|
9
10
|
* @property {string} adminUser.password - Admin user password
|
|
10
|
-
* @property {
|
|
11
|
+
* @property {StaticPathOptions} [uploadDirectoryConfig] - Upload directory configuration with static path info
|
|
12
|
+
* @property {string} [uploadDirectory] - @deprecated Use uploadDirectoryConfig instead. Directory for file uploads
|
|
11
13
|
*/
|
|
12
14
|
interface SetupOptions {
|
|
13
15
|
keypair?: {
|
|
@@ -18,6 +20,10 @@ interface SetupOptions {
|
|
|
18
20
|
email: string;
|
|
19
21
|
password: string;
|
|
20
22
|
};
|
|
23
|
+
uploadDirectoryConfig?: StaticPathOptions;
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated Use uploadDirectoryConfig instead. This property will be removed in a future version.
|
|
26
|
+
*/
|
|
21
27
|
uploadDirectory?: string;
|
|
22
28
|
}
|
|
23
29
|
/**
|
|
@@ -34,7 +40,7 @@ interface SetupOptions {
|
|
|
34
40
|
*
|
|
35
41
|
* @example
|
|
36
42
|
* ```typescript
|
|
37
|
-
* // Setup with custom keypair
|
|
43
|
+
* // Setup with custom keypair and uploadDirectoryConfig
|
|
38
44
|
* await setup({
|
|
39
45
|
* keypair: {
|
|
40
46
|
* private: 'your-private-key',
|
|
@@ -44,7 +50,10 @@ interface SetupOptions {
|
|
|
44
50
|
* email: 'admin@example.com',
|
|
45
51
|
* password: 'secure-password'
|
|
46
52
|
* },
|
|
47
|
-
*
|
|
53
|
+
* uploadDirectoryConfig: {
|
|
54
|
+
* directory: './uploads',
|
|
55
|
+
* urlPath: '/assets'
|
|
56
|
+
* }
|
|
48
57
|
* });
|
|
49
58
|
*
|
|
50
59
|
* // Setup with auto-generated keypair
|
|
@@ -56,5 +65,5 @@ interface SetupOptions {
|
|
|
56
65
|
* });
|
|
57
66
|
* ```
|
|
58
67
|
*/
|
|
59
|
-
export declare function setup({ keypair, adminUser, uploadDirectory }: SetupOptions): Promise<void>;
|
|
68
|
+
export declare function setup({ keypair, adminUser, uploadDirectory, uploadDirectoryConfig, }: SetupOptions): Promise<void>;
|
|
60
69
|
export {};
|
|
@@ -40,6 +40,7 @@ exports.setup = setup;
|
|
|
40
40
|
const DataInsertion = __importStar(require("./data_insertion"));
|
|
41
41
|
const JWT = __importStar(require("../services/jwt/service"));
|
|
42
42
|
const FileService = __importStar(require("../services/file/service"));
|
|
43
|
+
const config_1 = require("../config");
|
|
43
44
|
const keypair_1 = __importDefault(require("keypair"));
|
|
44
45
|
/**
|
|
45
46
|
* Sets up required services for the application to run
|
|
@@ -55,7 +56,7 @@ const keypair_1 = __importDefault(require("keypair"));
|
|
|
55
56
|
*
|
|
56
57
|
* @example
|
|
57
58
|
* ```typescript
|
|
58
|
-
* // Setup with custom keypair
|
|
59
|
+
* // Setup with custom keypair and uploadDirectoryConfig
|
|
59
60
|
* await setup({
|
|
60
61
|
* keypair: {
|
|
61
62
|
* private: 'your-private-key',
|
|
@@ -65,7 +66,10 @@ const keypair_1 = __importDefault(require("keypair"));
|
|
|
65
66
|
* email: 'admin@example.com',
|
|
66
67
|
* password: 'secure-password'
|
|
67
68
|
* },
|
|
68
|
-
*
|
|
69
|
+
* uploadDirectoryConfig: {
|
|
70
|
+
* directory: './uploads',
|
|
71
|
+
* urlPath: '/assets'
|
|
72
|
+
* }
|
|
69
73
|
* });
|
|
70
74
|
*
|
|
71
75
|
* // Setup with auto-generated keypair
|
|
@@ -77,7 +81,7 @@ const keypair_1 = __importDefault(require("keypair"));
|
|
|
77
81
|
* });
|
|
78
82
|
* ```
|
|
79
83
|
*/
|
|
80
|
-
async function setup({ keypair, adminUser, uploadDirectory }) {
|
|
84
|
+
async function setup({ keypair, adminUser, uploadDirectory, uploadDirectoryConfig, }) {
|
|
81
85
|
/**
|
|
82
86
|
* Json web Token
|
|
83
87
|
*
|
|
@@ -90,7 +94,7 @@ async function setup({ keypair, adminUser, uploadDirectory }) {
|
|
|
90
94
|
}
|
|
91
95
|
JWT.main.setKies(keyPairToUse.private, keyPairToUse.public);
|
|
92
96
|
if (!adminUser) {
|
|
93
|
-
throw new Error('Admin user is
|
|
97
|
+
throw new Error('Admin user configuration is required. Please provide adminUser in your createRest() options.');
|
|
94
98
|
}
|
|
95
99
|
/**
|
|
96
100
|
* Data Insertion
|
|
@@ -102,7 +106,14 @@ async function setup({ keypair, adminUser, uploadDirectory }) {
|
|
|
102
106
|
/**
|
|
103
107
|
* File Service
|
|
104
108
|
*/
|
|
105
|
-
|
|
109
|
+
// Check for uploadDirectoryConfig from global config first, then from options
|
|
110
|
+
const uploadConfigToUse = config_1.config.uploadDirectoryConfig || uploadDirectoryConfig;
|
|
111
|
+
if (uploadConfigToUse) {
|
|
112
|
+
FileService.main.setUploadDirectory(uploadConfigToUse);
|
|
113
|
+
}
|
|
114
|
+
else if (uploadDirectory) {
|
|
115
|
+
// Backward compatibility: use old uploadDirectory property with deprecation warning
|
|
116
|
+
console.warn('\x1b[33m%s\x1b[0m', "Warning: 'uploadDirectory' is deprecated and will be removed in a future version. Please use 'uploadDirectoryConfig' (StaticPathOptions) instead.");
|
|
106
117
|
FileService.main.setUploadDirectory(uploadDirectory);
|
|
107
118
|
}
|
|
108
119
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRest } from './application';
|
|
2
2
|
import { Schema } from 'mongoose';
|
|
3
|
+
import { StaticPathOptions, RestOptions } from './config';
|
|
3
4
|
import * as paginator from './class/paginator';
|
|
4
5
|
import * as reply from './class/reply';
|
|
5
6
|
import { validator } from './class/validator';
|
|
@@ -23,6 +24,28 @@ import * as middleware from './middlewares';
|
|
|
23
24
|
* @returns A new REST API instance
|
|
24
25
|
*/
|
|
25
26
|
export { createRest };
|
|
27
|
+
/**
|
|
28
|
+
* @description Configuration types for creating a REST API instance
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { RestOptions, StaticPathOptions } from '@modular-rest/server-ts';
|
|
32
|
+
*
|
|
33
|
+
* const config: RestOptions = {
|
|
34
|
+
* port: 3000,
|
|
35
|
+
* staticPaths: [
|
|
36
|
+
* {
|
|
37
|
+
* directory: './public',
|
|
38
|
+
* urlPath: '/static'
|
|
39
|
+
* }
|
|
40
|
+
* ],
|
|
41
|
+
* uploadDirectoryConfig: {
|
|
42
|
+
* directory: './uploads',
|
|
43
|
+
* urlPath: '/assets'
|
|
44
|
+
* }
|
|
45
|
+
* };
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export type { RestOptions, StaticPathOptions };
|
|
26
49
|
export { CollectionDefinition, defineCollection };
|
|
27
50
|
/**
|
|
28
51
|
* @description Provides predefined database schemas
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { StaticPathOptions } from '../../config';
|
|
1
2
|
import { IFile } from '../../class/db_schemas';
|
|
2
3
|
/**
|
|
3
4
|
* Service name constant
|
|
@@ -51,6 +52,10 @@ declare class FileService {
|
|
|
51
52
|
* @hidden
|
|
52
53
|
*/
|
|
53
54
|
private directory;
|
|
55
|
+
/**
|
|
56
|
+
* @hidden
|
|
57
|
+
*/
|
|
58
|
+
private urlPath;
|
|
54
59
|
/**
|
|
55
60
|
* @hidden
|
|
56
61
|
*/
|
|
@@ -63,16 +68,23 @@ declare class FileService {
|
|
|
63
68
|
* @hidden
|
|
64
69
|
*
|
|
65
70
|
* Sets the upload directory for file storage
|
|
66
|
-
* @param {string}
|
|
71
|
+
* @param {string | StaticPathOptions} directoryOrConfig - Directory path for file storage or StaticPathOptions configuration
|
|
67
72
|
* @throws {Error} If directory is invalid or not writable
|
|
68
73
|
* @example
|
|
69
74
|
* ```typescript
|
|
70
75
|
* import { fileService } from '@modular-rest/server';
|
|
71
76
|
*
|
|
77
|
+
* // New format with StaticPathOptions
|
|
78
|
+
* fileService.setUploadDirectory({
|
|
79
|
+
* directory: '/path/to/uploads',
|
|
80
|
+
* urlPath: '/assets'
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* // Legacy format (deprecated)
|
|
72
84
|
* fileService.setUploadDirectory('/path/to/uploads');
|
|
73
85
|
* ```
|
|
74
86
|
*/
|
|
75
|
-
setUploadDirectory(
|
|
87
|
+
setUploadDirectory(directoryOrConfig: string | StaticPathOptions): void;
|
|
76
88
|
/**
|
|
77
89
|
* @hidden
|
|
78
90
|
*
|
|
@@ -170,13 +182,13 @@ declare class FileService {
|
|
|
170
182
|
*
|
|
171
183
|
* @param {string} fileId - File ID to get link for
|
|
172
184
|
* @returns {Promise<string>} Promise resolving to file URL
|
|
173
|
-
* @throws {Error} If
|
|
185
|
+
* @throws {Error} If URL path is not defined or file is not found
|
|
174
186
|
* @example
|
|
175
187
|
* ```typescript
|
|
176
188
|
* import { fileService } from '@modular-rest/server';
|
|
177
189
|
*
|
|
178
190
|
* const link = await fileService.getFileLink('file123');
|
|
179
|
-
* // Returns: '/
|
|
191
|
+
* // Returns: '/uploads/jpeg/profile/1234567890.jpeg'
|
|
180
192
|
* ```
|
|
181
193
|
*/
|
|
182
194
|
getFileLink(fileId: string): Promise<string>;
|
|
@@ -41,7 +41,6 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
41
41
|
const path_1 = __importDefault(require("path"));
|
|
42
42
|
const DataProvider = __importStar(require("../data_provider/service"));
|
|
43
43
|
const trigger_operator_1 = __importDefault(require("../../class/trigger_operator"));
|
|
44
|
-
const config_1 = require("../../config");
|
|
45
44
|
/**
|
|
46
45
|
* Service name constant
|
|
47
46
|
* @constant {string}
|
|
@@ -63,25 +62,54 @@ class FileService {
|
|
|
63
62
|
* @hidden
|
|
64
63
|
*/
|
|
65
64
|
this.directory = null;
|
|
65
|
+
/**
|
|
66
|
+
* @hidden
|
|
67
|
+
*/
|
|
68
|
+
this.urlPath = null;
|
|
66
69
|
}
|
|
67
70
|
/**
|
|
68
71
|
* @hidden
|
|
69
72
|
*
|
|
70
73
|
* Sets the upload directory for file storage
|
|
71
|
-
* @param {string}
|
|
74
|
+
* @param {string | StaticPathOptions} directoryOrConfig - Directory path for file storage or StaticPathOptions configuration
|
|
72
75
|
* @throws {Error} If directory is invalid or not writable
|
|
73
76
|
* @example
|
|
74
77
|
* ```typescript
|
|
75
78
|
* import { fileService } from '@modular-rest/server';
|
|
76
79
|
*
|
|
80
|
+
* // New format with StaticPathOptions
|
|
81
|
+
* fileService.setUploadDirectory({
|
|
82
|
+
* directory: '/path/to/uploads',
|
|
83
|
+
* urlPath: '/assets'
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* // Legacy format (deprecated)
|
|
77
87
|
* fileService.setUploadDirectory('/path/to/uploads');
|
|
78
88
|
* ```
|
|
79
89
|
*/
|
|
80
|
-
setUploadDirectory(
|
|
90
|
+
setUploadDirectory(directoryOrConfig) {
|
|
91
|
+
// Handle backward compatibility with string
|
|
92
|
+
if (typeof directoryOrConfig === 'string') {
|
|
93
|
+
console.warn('\x1b[33m%s\x1b[0m', "Warning: Passing a string to 'setUploadDirectory' is deprecated. Please use StaticPathOptions object instead.");
|
|
94
|
+
if (!fs_1.default.existsSync(directoryOrConfig)) {
|
|
95
|
+
fs_1.default.mkdirSync(directoryOrConfig, { recursive: true });
|
|
96
|
+
}
|
|
97
|
+
this.directory = directoryOrConfig;
|
|
98
|
+
this.urlPath = null; // No URL path available with legacy format
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// New format: Extract only necessary properties from StaticPathOptions
|
|
102
|
+
const directory = directoryOrConfig.directory || '';
|
|
103
|
+
const urlPath = directoryOrConfig.urlPath || '/assets';
|
|
104
|
+
if (!directory) {
|
|
105
|
+
throw new Error('directory is required in uploadDirectoryConfig');
|
|
106
|
+
}
|
|
81
107
|
if (!fs_1.default.existsSync(directory)) {
|
|
82
108
|
fs_1.default.mkdirSync(directory, { recursive: true });
|
|
83
109
|
}
|
|
110
|
+
// Store only the necessary properties (ignore koa-static options)
|
|
84
111
|
this.directory = directory;
|
|
112
|
+
this.urlPath = urlPath;
|
|
85
113
|
}
|
|
86
114
|
/**
|
|
87
115
|
* @hidden
|
|
@@ -295,21 +323,21 @@ class FileService {
|
|
|
295
323
|
*
|
|
296
324
|
* @param {string} fileId - File ID to get link for
|
|
297
325
|
* @returns {Promise<string>} Promise resolving to file URL
|
|
298
|
-
* @throws {Error} If
|
|
326
|
+
* @throws {Error} If URL path is not defined or file is not found
|
|
299
327
|
* @example
|
|
300
328
|
* ```typescript
|
|
301
329
|
* import { fileService } from '@modular-rest/server';
|
|
302
330
|
*
|
|
303
331
|
* const link = await fileService.getFileLink('file123');
|
|
304
|
-
* // Returns: '/
|
|
332
|
+
* // Returns: '/uploads/jpeg/profile/1234567890.jpeg'
|
|
305
333
|
* ```
|
|
306
334
|
*/
|
|
307
335
|
async getFileLink(fileId) {
|
|
308
336
|
const fileDoc = await FileService.instance.getFile(fileId);
|
|
309
|
-
if (!
|
|
310
|
-
throw new Error('
|
|
337
|
+
if (!FileService.instance.urlPath) {
|
|
338
|
+
throw new Error('Upload directory URL path is not defined. Please configure uploadDirectoryConfig with a urlPath property.');
|
|
311
339
|
}
|
|
312
|
-
const link =
|
|
340
|
+
const link = `${FileService.instance.urlPath}/${fileDoc.format}/${fileDoc.tag}/${fileDoc.fileName}`;
|
|
313
341
|
return link;
|
|
314
342
|
}
|
|
315
343
|
/**
|
package/package.json
CHANGED
package/src/application.ts
CHANGED
|
@@ -74,16 +74,56 @@ export async function createRest(options: RestOptions): Promise<{ app: Koa; serv
|
|
|
74
74
|
/**
|
|
75
75
|
* Plug In KoaStatic
|
|
76
76
|
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
// Collect static paths from new property or fallback to old property
|
|
78
|
+
let staticPathsToMount: StaticPathOptions[] = [];
|
|
79
|
+
|
|
80
|
+
if (config.staticPaths && config.staticPaths.length > 0) {
|
|
81
|
+
// Use new staticPaths property
|
|
82
|
+
staticPathsToMount = config.staticPaths;
|
|
83
|
+
} else if (config.staticPath) {
|
|
84
|
+
// Backward compatibility: use old staticPath property with deprecation warning
|
|
85
|
+
console.warn(
|
|
86
|
+
'\x1b[33m%s\x1b[0m',
|
|
87
|
+
"Warning: 'staticPath' is deprecated and will be removed in a future version. Please use 'staticPaths' (array) instead."
|
|
88
|
+
);
|
|
89
|
+
staticPathsToMount = Array.isArray(config.staticPath) ? config.staticPath : [config.staticPath];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Mount all static paths
|
|
93
|
+
for (const staticPathConfig of staticPathsToMount) {
|
|
94
|
+
const directory = staticPathConfig.directory || '';
|
|
95
|
+
const urlPath = staticPathConfig.urlPath || '/assets';
|
|
96
|
+
|
|
97
|
+
const staticOptions: Partial<StaticPathOptions> = { ...staticPathConfig, defer: true };
|
|
80
98
|
|
|
81
|
-
|
|
99
|
+
delete staticOptions.directory;
|
|
100
|
+
delete staticOptions.urlPath;
|
|
101
|
+
|
|
102
|
+
app.use(mount(urlPath, koaStatic(directory, staticOptions)));
|
|
103
|
+
}
|
|
82
104
|
|
|
83
|
-
|
|
84
|
-
|
|
105
|
+
// Auto-mount uploadDirectoryConfig if staticPaths (new property) is configured
|
|
106
|
+
if (config.staticPaths && config.staticPaths.length > 0 && config.uploadDirectoryConfig) {
|
|
107
|
+
const uploadDirectory = config.uploadDirectoryConfig.directory || '';
|
|
108
|
+
const uploadUrlPath = config.uploadDirectoryConfig.urlPath || '/assets';
|
|
109
|
+
|
|
110
|
+
const uploadStaticOptions: Partial<StaticPathOptions> = {
|
|
111
|
+
...config.uploadDirectoryConfig,
|
|
112
|
+
defer: true,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
delete uploadStaticOptions.directory;
|
|
116
|
+
delete uploadStaticOptions.urlPath;
|
|
117
|
+
|
|
118
|
+
app.use(mount(uploadUrlPath, koaStatic(uploadDirectory, uploadStaticOptions)));
|
|
119
|
+
}
|
|
85
120
|
|
|
86
|
-
|
|
121
|
+
// Show deprecation warning for old uploadDirectory property
|
|
122
|
+
if (config.uploadDirectory) {
|
|
123
|
+
console.warn(
|
|
124
|
+
'\x1b[33m%s\x1b[0m',
|
|
125
|
+
"Warning: 'uploadDirectory' is deprecated and will be removed in a future version. Please use 'uploadDirectoryConfig' (StaticPathOptions) instead."
|
|
126
|
+
);
|
|
87
127
|
}
|
|
88
128
|
|
|
89
129
|
/**
|
|
@@ -172,7 +212,7 @@ export async function createRest(options: RestOptions): Promise<{ app: Koa; serv
|
|
|
172
212
|
|
|
173
213
|
// 4. Setting up default services
|
|
174
214
|
try {
|
|
175
|
-
await require('./helper/presetup_services').setup(
|
|
215
|
+
await require('./helper/presetup_services').setup(config);
|
|
176
216
|
} catch (e) {
|
|
177
217
|
return Promise.reject(e);
|
|
178
218
|
}
|
package/src/config.ts
CHANGED
|
@@ -10,16 +10,17 @@ import { Options as KoaStaticOptionsBase } from 'koa-static';
|
|
|
10
10
|
/**
|
|
11
11
|
* The options for the static file server, it's a combination of modular-rest and [koa-static options](https://github.com/koajs/static?tab=readme-ov-file#options)
|
|
12
12
|
*/
|
|
13
|
-
export
|
|
13
|
+
export interface StaticPathOptions extends KoaStaticOptionsBase {
|
|
14
14
|
/**
|
|
15
|
-
* The
|
|
15
|
+
* The filesystem directory where static files are stored
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
directory: string;
|
|
18
18
|
/**
|
|
19
|
-
* The path
|
|
19
|
+
* The URL path where static files will be served from
|
|
20
|
+
* @default '/assets'
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
-
}
|
|
22
|
+
urlPath?: string;
|
|
23
|
+
}
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* JWT keypair configuration
|
|
@@ -59,9 +60,9 @@ interface AdminUser {
|
|
|
59
60
|
* @interface RestOptions
|
|
60
61
|
* @property {KoaCorsOptions} [cors] - CORS configuration [options](https://github.com/koajs/cors?tab=readme-ov-file#corsoptions)
|
|
61
62
|
* @property {string} [modulesPath] - Path to custom modules directory
|
|
62
|
-
* @property {
|
|
63
|
+
* @property {StaticPathOptions[]} [staticPaths] - Array of static file serving configurations
|
|
64
|
+
* @property {StaticPathOptions} [uploadDirectoryConfig] - Upload directory configuration with static path info
|
|
63
65
|
* @property {any} [koaBodyOptions] - Options for koa-body middleware
|
|
64
|
-
* @property {StaticPathOptions} [staticPath] - Static file serving options
|
|
65
66
|
* @property {Function} [onBeforeInit] - Hook called before initialization
|
|
66
67
|
* @property {Function} [onAfterInit] - Hook called after initialization
|
|
67
68
|
* @property {number} [port] - Port to listen on
|
|
@@ -75,13 +76,15 @@ interface AdminUser {
|
|
|
75
76
|
* @property {CmsTrigger[]} [authTriggers] - Authentication triggers
|
|
76
77
|
* @property {CmsTrigger[]} [fileTriggers] - File handling triggers
|
|
77
78
|
* @property {DefinedFunction[]} [functions] - Custom API functions
|
|
79
|
+
* @property {string} [uploadDirectory] - @deprecated Use uploadDirectoryConfig instead. Directory for file uploads
|
|
80
|
+
* @property {StaticPathOptions | StaticPathOptions[]} [staticPath] - @deprecated Use staticPaths instead. Static file serving options
|
|
78
81
|
*/
|
|
79
82
|
export interface RestOptions {
|
|
80
83
|
cors?: KoaCorsOptions;
|
|
81
84
|
modulesPath?: string;
|
|
82
|
-
|
|
85
|
+
staticPaths?: StaticPathOptions[];
|
|
86
|
+
uploadDirectoryConfig?: StaticPathOptions;
|
|
83
87
|
koaBodyOptions?: any;
|
|
84
|
-
staticPath?: StaticPathOptions;
|
|
85
88
|
onBeforeInit?: (koaApp: Koa) => void;
|
|
86
89
|
onAfterInit?: (koaApp: Koa) => void;
|
|
87
90
|
port?: number;
|
|
@@ -95,6 +98,14 @@ export interface RestOptions {
|
|
|
95
98
|
authTriggers?: CmsTrigger[];
|
|
96
99
|
fileTriggers?: CmsTrigger[];
|
|
97
100
|
functions?: DefinedFunction[];
|
|
101
|
+
/**
|
|
102
|
+
* @deprecated Use uploadDirectoryConfig instead. This property will be removed in a future version.
|
|
103
|
+
*/
|
|
104
|
+
uploadDirectory?: string;
|
|
105
|
+
/**
|
|
106
|
+
* @deprecated Use staticPaths instead. This property will be removed in a future version.
|
|
107
|
+
*/
|
|
108
|
+
staticPath?: StaticPathOptions | StaticPathOptions[];
|
|
98
109
|
}
|
|
99
110
|
|
|
100
111
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as DataInsertion from './data_insertion';
|
|
2
2
|
import * as JWT from '../services/jwt/service';
|
|
3
3
|
import * as FileService from '../services/file/service';
|
|
4
|
+
import { config, StaticPathOptions } from '../config';
|
|
4
5
|
import generateKeypair from 'keypair';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -12,7 +13,8 @@ import generateKeypair from 'keypair';
|
|
|
12
13
|
* @property {Object} adminUser - Admin user configuration
|
|
13
14
|
* @property {string} adminUser.email - Admin user email address
|
|
14
15
|
* @property {string} adminUser.password - Admin user password
|
|
15
|
-
* @property {
|
|
16
|
+
* @property {StaticPathOptions} [uploadDirectoryConfig] - Upload directory configuration with static path info
|
|
17
|
+
* @property {string} [uploadDirectory] - @deprecated Use uploadDirectoryConfig instead. Directory for file uploads
|
|
16
18
|
*/
|
|
17
19
|
interface SetupOptions {
|
|
18
20
|
keypair?: {
|
|
@@ -23,6 +25,10 @@ interface SetupOptions {
|
|
|
23
25
|
email: string;
|
|
24
26
|
password: string;
|
|
25
27
|
};
|
|
28
|
+
uploadDirectoryConfig?: StaticPathOptions;
|
|
29
|
+
/**
|
|
30
|
+
* @deprecated Use uploadDirectoryConfig instead. This property will be removed in a future version.
|
|
31
|
+
*/
|
|
26
32
|
uploadDirectory?: string;
|
|
27
33
|
}
|
|
28
34
|
|
|
@@ -40,7 +46,7 @@ interface SetupOptions {
|
|
|
40
46
|
*
|
|
41
47
|
* @example
|
|
42
48
|
* ```typescript
|
|
43
|
-
* // Setup with custom keypair
|
|
49
|
+
* // Setup with custom keypair and uploadDirectoryConfig
|
|
44
50
|
* await setup({
|
|
45
51
|
* keypair: {
|
|
46
52
|
* private: 'your-private-key',
|
|
@@ -50,7 +56,10 @@ interface SetupOptions {
|
|
|
50
56
|
* email: 'admin@example.com',
|
|
51
57
|
* password: 'secure-password'
|
|
52
58
|
* },
|
|
53
|
-
*
|
|
59
|
+
* uploadDirectoryConfig: {
|
|
60
|
+
* directory: './uploads',
|
|
61
|
+
* urlPath: '/assets'
|
|
62
|
+
* }
|
|
54
63
|
* });
|
|
55
64
|
*
|
|
56
65
|
* // Setup with auto-generated keypair
|
|
@@ -62,7 +71,12 @@ interface SetupOptions {
|
|
|
62
71
|
* });
|
|
63
72
|
* ```
|
|
64
73
|
*/
|
|
65
|
-
export async function setup({
|
|
74
|
+
export async function setup({
|
|
75
|
+
keypair,
|
|
76
|
+
adminUser,
|
|
77
|
+
uploadDirectory,
|
|
78
|
+
uploadDirectoryConfig,
|
|
79
|
+
}: SetupOptions): Promise<void> {
|
|
66
80
|
/**
|
|
67
81
|
* Json web Token
|
|
68
82
|
*
|
|
@@ -77,7 +91,7 @@ export async function setup({ keypair, adminUser, uploadDirectory }: SetupOption
|
|
|
77
91
|
JWT.main.setKies(keyPairToUse.private, keyPairToUse.public);
|
|
78
92
|
|
|
79
93
|
if (!adminUser) {
|
|
80
|
-
throw new Error('Admin user is
|
|
94
|
+
throw new Error('Admin user configuration is required. Please provide adminUser in your createRest() options.');
|
|
81
95
|
}
|
|
82
96
|
/**
|
|
83
97
|
* Data Insertion
|
|
@@ -90,7 +104,17 @@ export async function setup({ keypair, adminUser, uploadDirectory }: SetupOption
|
|
|
90
104
|
/**
|
|
91
105
|
* File Service
|
|
92
106
|
*/
|
|
93
|
-
|
|
107
|
+
// Check for uploadDirectoryConfig from global config first, then from options
|
|
108
|
+
const uploadConfigToUse = config.uploadDirectoryConfig || uploadDirectoryConfig;
|
|
109
|
+
|
|
110
|
+
if (uploadConfigToUse) {
|
|
111
|
+
FileService.main.setUploadDirectory(uploadConfigToUse);
|
|
112
|
+
} else if (uploadDirectory) {
|
|
113
|
+
// Backward compatibility: use old uploadDirectory property with deprecation warning
|
|
114
|
+
console.warn(
|
|
115
|
+
'\x1b[33m%s\x1b[0m',
|
|
116
|
+
"Warning: 'uploadDirectory' is deprecated and will be removed in a future version. Please use 'uploadDirectoryConfig' (StaticPathOptions) instead."
|
|
117
|
+
);
|
|
94
118
|
FileService.main.setUploadDirectory(uploadDirectory);
|
|
95
119
|
}
|
|
96
120
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { createRest } from './application';
|
|
3
3
|
import { Schema } from 'mongoose';
|
|
4
4
|
|
|
5
|
+
// Configuration types
|
|
6
|
+
import { StaticPathOptions, RestOptions } from './config';
|
|
7
|
+
|
|
5
8
|
// Utilities
|
|
6
9
|
import * as paginator from './class/paginator';
|
|
7
10
|
import * as reply from './class/reply';
|
|
@@ -37,6 +40,29 @@ import * as middleware from './middlewares';
|
|
|
37
40
|
*/
|
|
38
41
|
export { createRest };
|
|
39
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @description Configuration types for creating a REST API instance
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* import { RestOptions, StaticPathOptions } from '@modular-rest/server-ts';
|
|
48
|
+
*
|
|
49
|
+
* const config: RestOptions = {
|
|
50
|
+
* port: 3000,
|
|
51
|
+
* staticPaths: [
|
|
52
|
+
* {
|
|
53
|
+
* directory: './public',
|
|
54
|
+
* urlPath: '/static'
|
|
55
|
+
* }
|
|
56
|
+
* ],
|
|
57
|
+
* uploadDirectoryConfig: {
|
|
58
|
+
* directory: './uploads',
|
|
59
|
+
* urlPath: '/assets'
|
|
60
|
+
* }
|
|
61
|
+
* };
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export type { RestOptions, StaticPathOptions };
|
|
65
|
+
|
|
40
66
|
export { CollectionDefinition, defineCollection };
|
|
41
67
|
|
|
42
68
|
/**
|
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import pathModule from 'path';
|
|
3
3
|
import * as DataProvider from '../data_provider/service';
|
|
4
4
|
import triggerService from '../../class/trigger_operator';
|
|
5
|
-
import { config } from '../../config';
|
|
5
|
+
import { config, StaticPathOptions } from '../../config';
|
|
6
6
|
import { IFile } from '../../class/db_schemas';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -61,6 +61,11 @@ class FileService {
|
|
|
61
61
|
*/
|
|
62
62
|
private directory: string | null = null;
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* @hidden
|
|
66
|
+
*/
|
|
67
|
+
private urlPath: string | null = null;
|
|
68
|
+
|
|
64
69
|
/**
|
|
65
70
|
* @hidden
|
|
66
71
|
*/
|
|
@@ -75,20 +80,52 @@ class FileService {
|
|
|
75
80
|
* @hidden
|
|
76
81
|
*
|
|
77
82
|
* Sets the upload directory for file storage
|
|
78
|
-
* @param {string}
|
|
83
|
+
* @param {string | StaticPathOptions} directoryOrConfig - Directory path for file storage or StaticPathOptions configuration
|
|
79
84
|
* @throws {Error} If directory is invalid or not writable
|
|
80
85
|
* @example
|
|
81
86
|
* ```typescript
|
|
82
87
|
* import { fileService } from '@modular-rest/server';
|
|
83
88
|
*
|
|
89
|
+
* // New format with StaticPathOptions
|
|
90
|
+
* fileService.setUploadDirectory({
|
|
91
|
+
* directory: '/path/to/uploads',
|
|
92
|
+
* urlPath: '/assets'
|
|
93
|
+
* });
|
|
94
|
+
*
|
|
95
|
+
* // Legacy format (deprecated)
|
|
84
96
|
* fileService.setUploadDirectory('/path/to/uploads');
|
|
85
97
|
* ```
|
|
86
98
|
*/
|
|
87
|
-
setUploadDirectory(
|
|
99
|
+
setUploadDirectory(directoryOrConfig: string | StaticPathOptions): void {
|
|
100
|
+
// Handle backward compatibility with string
|
|
101
|
+
if (typeof directoryOrConfig === 'string') {
|
|
102
|
+
console.warn(
|
|
103
|
+
'\x1b[33m%s\x1b[0m',
|
|
104
|
+
"Warning: Passing a string to 'setUploadDirectory' is deprecated. Please use StaticPathOptions object instead."
|
|
105
|
+
);
|
|
106
|
+
if (!fs.existsSync(directoryOrConfig)) {
|
|
107
|
+
fs.mkdirSync(directoryOrConfig, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
this.directory = directoryOrConfig;
|
|
110
|
+
this.urlPath = null; // No URL path available with legacy format
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// New format: Extract only necessary properties from StaticPathOptions
|
|
115
|
+
const directory = directoryOrConfig.directory || '';
|
|
116
|
+
const urlPath = directoryOrConfig.urlPath || '/assets';
|
|
117
|
+
|
|
118
|
+
if (!directory) {
|
|
119
|
+
throw new Error('directory is required in uploadDirectoryConfig');
|
|
120
|
+
}
|
|
121
|
+
|
|
88
122
|
if (!fs.existsSync(directory)) {
|
|
89
123
|
fs.mkdirSync(directory, { recursive: true });
|
|
90
124
|
}
|
|
125
|
+
|
|
126
|
+
// Store only the necessary properties (ignore koa-static options)
|
|
91
127
|
this.directory = directory;
|
|
128
|
+
this.urlPath = urlPath;
|
|
92
129
|
}
|
|
93
130
|
|
|
94
131
|
/**
|
|
@@ -333,24 +370,25 @@ class FileService {
|
|
|
333
370
|
*
|
|
334
371
|
* @param {string} fileId - File ID to get link for
|
|
335
372
|
* @returns {Promise<string>} Promise resolving to file URL
|
|
336
|
-
* @throws {Error} If
|
|
373
|
+
* @throws {Error} If URL path is not defined or file is not found
|
|
337
374
|
* @example
|
|
338
375
|
* ```typescript
|
|
339
376
|
* import { fileService } from '@modular-rest/server';
|
|
340
377
|
*
|
|
341
378
|
* const link = await fileService.getFileLink('file123');
|
|
342
|
-
* // Returns: '/
|
|
379
|
+
* // Returns: '/uploads/jpeg/profile/1234567890.jpeg'
|
|
343
380
|
* ```
|
|
344
381
|
*/
|
|
345
382
|
async getFileLink(fileId: string): Promise<string> {
|
|
346
383
|
const fileDoc = await FileService.instance.getFile(fileId);
|
|
347
384
|
|
|
348
|
-
if (!
|
|
349
|
-
throw new Error(
|
|
385
|
+
if (!FileService.instance.urlPath) {
|
|
386
|
+
throw new Error(
|
|
387
|
+
'Upload directory URL path is not defined. Please configure uploadDirectoryConfig with a urlPath property.'
|
|
388
|
+
);
|
|
350
389
|
}
|
|
351
390
|
|
|
352
|
-
const link =
|
|
353
|
-
config.staticPath.actualPath + `/${fileDoc.format}/${fileDoc.tag}/` + fileDoc.fileName;
|
|
391
|
+
const link = `${FileService.instance.urlPath}/${fileDoc.format}/${fileDoc.tag}/${fileDoc.fileName}`;
|
|
354
392
|
|
|
355
393
|
return link;
|
|
356
394
|
}
|