@modular-rest/server 1.11.12 → 1.11.14

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.
Files changed (112) hide show
  1. package/.nvmrc +1 -0
  2. package/.prettierrc.json +9 -0
  3. package/.releaserc.json +24 -0
  4. package/README.md +79 -94
  5. package/dist/index.js +79 -0
  6. package/docs/.keep +0 -0
  7. package/docs/system-access-type.md +26 -0
  8. package/package.json +58 -45
  9. package/src/application.ts +206 -0
  10. package/src/class/cms_trigger.ts +68 -0
  11. package/src/class/collection_definition.ts +134 -0
  12. package/src/class/combinator.ts +176 -0
  13. package/src/class/database_trigger.ts +99 -0
  14. package/src/class/db_schemas.ts +44 -0
  15. package/src/class/{directory.js → directory.ts} +40 -18
  16. package/src/class/paginator.ts +51 -0
  17. package/src/class/reply.ts +59 -0
  18. package/src/class/security.ts +250 -0
  19. package/src/class/trigger_operator.ts +142 -0
  20. package/src/class/user.ts +199 -0
  21. package/src/class/validator.ts +123 -0
  22. package/src/config.ts +122 -0
  23. package/src/defult-permissions.ts +31 -0
  24. package/src/events.ts +59 -0
  25. package/src/helper/data_insertion.ts +94 -0
  26. package/src/helper/presetup_services.ts +96 -0
  27. package/src/index.ts +146 -0
  28. package/src/middlewares.ts +75 -0
  29. package/src/play-test.ts +8 -0
  30. package/src/services/data_provider/router.ts +191 -0
  31. package/src/services/data_provider/service.ts +305 -0
  32. package/src/services/data_provider/typeCasters.ts +15 -0
  33. package/src/services/file/db.ts +29 -0
  34. package/src/services/file/router.ts +88 -0
  35. package/src/services/file/service.ts +387 -0
  36. package/src/services/functions/router.ts +34 -0
  37. package/src/services/functions/service.ts +203 -0
  38. package/src/services/jwt/router.ts +73 -0
  39. package/src/services/jwt/service.ts +139 -0
  40. package/src/services/user_manager/db.ts +87 -0
  41. package/src/services/user_manager/permissionManager.ts +49 -0
  42. package/src/services/user_manager/router.ts +193 -0
  43. package/src/services/user_manager/service.ts +698 -0
  44. package/tsconfig.json +16 -9
  45. package/typedoc.mjs +41 -0
  46. package/LICENSE +0 -21
  47. package/package-lock.json +0 -1373
  48. package/src/application.js +0 -239
  49. package/src/class/cms_trigger.js +0 -20
  50. package/src/class/collection_definition.js +0 -33
  51. package/src/class/combinator.js +0 -133
  52. package/src/class/database_trigger.js +0 -20
  53. package/src/class/db_schemas.js +0 -18
  54. package/src/class/paginator.js +0 -31
  55. package/src/class/reply.js +0 -37
  56. package/src/class/security.js +0 -141
  57. package/src/class/trigger_operator.js +0 -39
  58. package/src/class/user.js +0 -112
  59. package/src/class/validator.js +0 -91
  60. package/src/config.js +0 -67
  61. package/src/events.js +0 -15
  62. package/src/helper/data_insertion.js +0 -64
  63. package/src/helper/presetup_services.js +0 -31
  64. package/src/index.js +0 -66
  65. package/src/middlewares.js +0 -44
  66. package/src/services/data_provider/router.js +0 -552
  67. package/src/services/data_provider/service.js +0 -262
  68. package/src/services/data_provider/typeCasters.js +0 -10
  69. package/src/services/file/db.js +0 -29
  70. package/src/services/file/router.js +0 -92
  71. package/src/services/file/service.js +0 -231
  72. package/src/services/functions/router.js +0 -37
  73. package/src/services/functions/service.js +0 -74
  74. package/src/services/jwt/router.js +0 -70
  75. package/src/services/jwt/service.js +0 -37
  76. package/src/services/user_manager/db.js +0 -83
  77. package/src/services/user_manager/permissionManager.js +0 -43
  78. package/src/services/user_manager/router.js +0 -176
  79. package/src/services/user_manager/service.js +0 -377
  80. package/types/application.d.ts +0 -97
  81. package/types/class/cms_trigger.d.ts +0 -24
  82. package/types/class/collection_definition.d.ts +0 -36
  83. package/types/class/combinator.d.ts +0 -30
  84. package/types/class/database_trigger.d.ts +0 -28
  85. package/types/class/db_schemas.d.ts +0 -2
  86. package/types/class/directory.d.ts +0 -2
  87. package/types/class/paginator.d.ts +0 -8
  88. package/types/class/reply.d.ts +0 -8
  89. package/types/class/security.d.ts +0 -109
  90. package/types/class/trigger_operator.d.ts +0 -19
  91. package/types/class/user.d.ts +0 -24
  92. package/types/class/validator.d.ts +0 -9
  93. package/types/config.d.ts +0 -101
  94. package/types/events.d.ts +0 -7
  95. package/types/helper/data_insertion.d.ts +0 -4
  96. package/types/helper/presetup_services.d.ts +0 -5
  97. package/types/index.d.ts +0 -72
  98. package/types/middlewares.d.ts +0 -9
  99. package/types/services/data_provider/router.d.ts +0 -3
  100. package/types/services/data_provider/service.d.ts +0 -40
  101. package/types/services/data_provider/typeCasters.d.ts +0 -3
  102. package/types/services/file/db.d.ts +0 -3
  103. package/types/services/file/router.d.ts +0 -3
  104. package/types/services/file/service.d.ts +0 -81
  105. package/types/services/functions/router.d.ts +0 -3
  106. package/types/services/functions/service.d.ts +0 -23
  107. package/types/services/jwt/router.d.ts +0 -3
  108. package/types/services/jwt/service.d.ts +0 -10
  109. package/types/services/user_manager/db.d.ts +0 -3
  110. package/types/services/user_manager/permissionManager.d.ts +0 -3
  111. package/types/services/user_manager/router.d.ts +0 -3
  112. package/types/services/user_manager/service.d.ts +0 -131
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Type for CMS operations that can trigger a callback
3
+ * @typedef {('update-one' | 'insert-one' | 'remove-one')} CmsOperation
4
+ * @description Supported CMS operations:
5
+ * - 'update-one': Triggered when updating a single document in the CMS
6
+ * - 'insert-one': Triggered when inserting a new document in the CMS
7
+ * - 'remove-one': Triggered when removing a document from the CMS
8
+ */
9
+ export type CmsOperation = 'update-one' | 'insert-one' | 'remove-one';
10
+
11
+ /**
12
+ * Context interface for CMS trigger callbacks
13
+ * @interface CmsTriggerContext
14
+ * @property {Record<string, any>} query - The query parameters used in the CMS operation
15
+ * @property {any} queryResult - The result of the CMS operation
16
+ */
17
+ export interface CmsTriggerContext {
18
+ query: Record<string, any>;
19
+ queryResult: any;
20
+ }
21
+
22
+ /**
23
+ * Defines a callback to be executed on specific CMS operations
24
+ * @class CmsTrigger
25
+ * @property {CmsOperation} operation - The CMS operation that triggers the callback
26
+ * @property {Function} callback - The callback function to be executed
27
+ * @example
28
+ * ```typescript
29
+ * const trigger = new CmsTrigger('insert-one', (context) => {
30
+ * console.log('New CMS document inserted:', context.queryResult);
31
+ * // Perform additional actions after CMS document insertion
32
+ * });
33
+ *
34
+ * // Use the trigger in RestOptions
35
+ * const { app } = await createRest({
36
+ * authTriggers: [trigger],
37
+ * // ... other options
38
+ * });
39
+ * ```
40
+ */
41
+ export class CmsTrigger {
42
+ operation: CmsOperation;
43
+ callback: (context: CmsTriggerContext) => void;
44
+
45
+ /**
46
+ * Creates a new CmsTrigger instance
47
+ * @param {CmsOperation} operation - The CMS operation to trigger on
48
+ * @param {Function} [callback=() => {}] - The callback function to execute
49
+ * @example
50
+ * ```typescript
51
+ * // Log all CMS updates
52
+ * const updateTrigger = new CmsTrigger('update-one', (context) => {
53
+ * console.log('CMS document updated:', context.queryResult);
54
+ * });
55
+ *
56
+ * // Track CMS document removals
57
+ * const removeTrigger = new CmsTrigger('remove-one', (context) => {
58
+ * console.log('CMS document removed:', context.queryResult);
59
+ * });
60
+ * ```
61
+ */
62
+ constructor(operation: CmsOperation, callback: (context: CmsTriggerContext) => void = () => {}) {
63
+ this.operation = operation;
64
+ this.callback = callback;
65
+ }
66
+ }
67
+
68
+ export default CmsTrigger;
@@ -0,0 +1,134 @@
1
+ import { Schema } from 'mongoose';
2
+ import { Permission } from './security';
3
+ import { DatabaseTrigger } from './database_trigger';
4
+
5
+ /**
6
+ * Configuration options for creating a collection definition.
7
+ * This interface defines the structure for configuring MongoDB collections with their associated
8
+ * schemas, permissions, and triggers.
9
+ *
10
+ * @inline
11
+ *
12
+ */
13
+ interface CollectionDefinitionOptions {
14
+ /** The name of the database where the collection resides */
15
+ database: string;
16
+ /** The name of the collection to be configured */
17
+ collection: string;
18
+ /** List of permissions controlling access to the collection */
19
+ permissions: Permission[];
20
+ /** Optional database triggers for custom operations */
21
+ triggers?: DatabaseTrigger[];
22
+
23
+ /**
24
+ * Mongoose schema definition for the collection
25
+ * @type {Schema}
26
+ * @see https://mongoosejs.com/docs/5.x/docs/guide.html
27
+ */
28
+ schema: Schema<any>;
29
+ }
30
+
31
+ /**
32
+ * To have define any collection in your database you haveto use below method in your `db.[js|ts]` file and export an array of CollectionDefinition instances.
33
+ *
34
+ * @param {CollectionDefinitionOptions} options - The options for the collection
35
+ * @expandType CollectionDefinitionOptions
36
+ *
37
+ * @returns A new instance of CollectionDefinition
38
+ *
39
+ * @public
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * import { defineCollection } from '@modular-rest/server';
44
+ *
45
+ * export default [
46
+ * defineCollection({
47
+ * database: 'users',
48
+ * collection: 'info',
49
+ * // schema: Schema,
50
+ * // permissions: Permission[]
51
+ * // trigger: DatabaseTrigger[]
52
+ * })
53
+ * ]
54
+ * ```
55
+ */
56
+ export function defineCollection(options: CollectionDefinitionOptions) {
57
+ return new CollectionDefinition(options);
58
+ }
59
+
60
+ /**
61
+ * A class that represents a MongoDB collection configuration. Provides full support for schema validation, access control through permissions,
62
+ * and custom triggers for various database operations.
63
+ *
64
+ * @hideconstructor
65
+ *
66
+ * @deprecated Use `defineCollection` instead.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const userSchema = new Schema({
71
+ * name: String,
72
+ * email: String,
73
+ * age: Number
74
+ * });
75
+ *
76
+ * const collection = new CollectionDefinition({
77
+ * database: 'myapp',
78
+ * collection: 'users',
79
+ * schema: userSchema,
80
+ * permissions: [
81
+ * new Permission({
82
+ * type: 'user_access',
83
+ * read: true,
84
+ * write: true
85
+ * })
86
+ * ],
87
+ * triggers: [
88
+ * new DatabaseTrigger('insert-one', (data) => {
89
+ * console.log('New user created:', data);
90
+ * })
91
+ * ]
92
+ * });
93
+ * ```
94
+ *
95
+ * @private
96
+ */
97
+ export class CollectionDefinition {
98
+ /** @readonly The name of the database */
99
+ database: string;
100
+
101
+ /** @readonly The name of the collection */
102
+ collection: string;
103
+
104
+ /** @readonly Mongoose schema definition */
105
+ schema: Schema<any>;
106
+
107
+ /** @readonly List of permissions for the collection */
108
+ permissions: Permission[];
109
+
110
+ /** @readonly Optional database triggers */
111
+ triggers?: DatabaseTrigger[];
112
+
113
+ /**
114
+ * Creates a new CollectionDefinition instance
115
+ *
116
+ * @param options - Configuration options for the collection
117
+ * @returns A new instance of CollectionDefinition
118
+ *
119
+ * @beta
120
+ */
121
+ constructor({
122
+ database,
123
+ collection,
124
+ schema,
125
+ permissions,
126
+ triggers,
127
+ }: CollectionDefinitionOptions) {
128
+ this.database = database;
129
+ this.collection = collection;
130
+ this.schema = schema;
131
+ this.permissions = permissions;
132
+ this.triggers = triggers;
133
+ }
134
+ }
@@ -0,0 +1,176 @@
1
+ import Router from 'koa-router';
2
+ import Koa from 'koa';
3
+ import * as directory from './directory';
4
+ import { addFunction } from '../services/functions/service';
5
+
6
+ interface FilenameOption {
7
+ name: string;
8
+ extension: string;
9
+ }
10
+
11
+ interface ModuleOptions {
12
+ rootDirectory: string;
13
+ filename: FilenameOption;
14
+ combineWithRoot?: boolean;
15
+ convertToArray?: boolean;
16
+ }
17
+
18
+ interface FunctionOptions {
19
+ rootDirectory: string;
20
+ filename: FilenameOption;
21
+ }
22
+
23
+ class Combinator {
24
+ async combineRoutesByFilePath(rootDirectory: string, app: Koa): Promise<void> {
25
+ // find route paths
26
+ const option = {
27
+ name: 'router',
28
+ filter: ['.js'],
29
+ };
30
+
31
+ let routerPaths: string[] = [];
32
+ try {
33
+ routerPaths = await directory.find(rootDirectory, option);
34
+ } catch (e) {
35
+ console.log(e);
36
+ }
37
+
38
+ // create and combine routes into the app
39
+ for (let i = 0; i < routerPaths.length; i++) {
40
+ const service = require(routerPaths[i]);
41
+ const name = service.name;
42
+
43
+ const serviceRouter = new Router();
44
+ serviceRouter.use(`/${name}`, service.main.routes());
45
+
46
+ app.use(serviceRouter.routes());
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Combine modules from files in a directory
52
+ * @param options - Configuration options
53
+ */
54
+ async combineModulesByFilePath({
55
+ rootDirectory,
56
+ filename,
57
+ combineWithRoot,
58
+ convertToArray,
59
+ }: ModuleOptions): Promise<any> {
60
+ // find route paths
61
+ let rootObject_temp: any;
62
+
63
+ const option = {
64
+ name: filename.name,
65
+ filter: [filename.extension],
66
+ };
67
+
68
+ let modulesPath: string[] = [];
69
+ try {
70
+ modulesPath = await directory.find(rootDirectory, option);
71
+ } catch (e) {
72
+ console.log(e);
73
+ }
74
+
75
+ // create and combine routes into the app
76
+ for (let i = 0; i < modulesPath.length; i++) {
77
+ const moduleObject = require(modulesPath[i]);
78
+
79
+ // act by otherOption
80
+ if (combineWithRoot) {
81
+ if (moduleObject.name) delete moduleObject.name;
82
+
83
+ if (Array.isArray(moduleObject)) {
84
+ if (!rootObject_temp) rootObject_temp = [];
85
+
86
+ rootObject_temp = [...rootObject_temp, ...moduleObject];
87
+ } else {
88
+ rootObject_temp = this.extendObj(rootObject_temp, moduleObject);
89
+ }
90
+ }
91
+ // default act
92
+ else {
93
+ const name = moduleObject.name;
94
+ rootObject_temp[name] = moduleObject;
95
+ }
96
+ }
97
+
98
+ // options
99
+ // convertToArray
100
+ if (convertToArray) {
101
+ rootObject_temp = Object.values(rootObject_temp);
102
+ }
103
+
104
+ // set result to main rootObject
105
+ return rootObject_temp;
106
+ }
107
+
108
+ /**
109
+ * Combine functions from files in a directory
110
+ * @param options - Function options
111
+ */
112
+ async combineFunctionsByFilePath({ rootDirectory, filename }: FunctionOptions): Promise<void> {
113
+ // find route paths
114
+ const option = {
115
+ name: filename.name,
116
+ filter: [filename.extension],
117
+ };
118
+
119
+ let functionsPaths: string[] = [];
120
+ try {
121
+ functionsPaths = await directory.find(rootDirectory, option);
122
+ } catch (e) {
123
+ console.log(e);
124
+ }
125
+
126
+ // create and combine routes into the app
127
+ for (let i = 0; i < functionsPaths.length; i++) {
128
+ const modularFunctions = require(functionsPaths[i]);
129
+
130
+ if (!modularFunctions.functions) {
131
+ throw new Error(`Module file ${functionsPaths[i]} does not have functions property.`);
132
+ }
133
+
134
+ // if array
135
+ if (Array.isArray(modularFunctions.functions)) {
136
+ for (const moduleFunction of modularFunctions.functions) {
137
+ addFunction(moduleFunction);
138
+ }
139
+ } else {
140
+ addFunction(modularFunctions.functions);
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Add functions from an array
147
+ * @param functionList - List of functions to add
148
+ */
149
+ addFunctionsByArray(functionList: any[]): void {
150
+ for (const functionItem of functionList) {
151
+ addFunction(functionItem);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Extend an object with properties from another
157
+ * @param obj - Target object
158
+ * @param src - Source object
159
+ * @returns Extended object
160
+ */
161
+ extendObj(obj: any, src: any): any {
162
+ obj = obj || {};
163
+ for (const key in src) {
164
+ if (Object.prototype.hasOwnProperty.call(src, key)) obj[key] = src[key];
165
+ }
166
+ return obj;
167
+ }
168
+
169
+ static get instance(): Combinator {
170
+ return instance;
171
+ }
172
+ }
173
+
174
+ const instance = new Combinator();
175
+
176
+ export = instance;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Type for database operations that can trigger a callback
3
+ */
4
+ export type DatabaseOperation =
5
+ | 'find'
6
+ | 'find-one'
7
+ | 'count'
8
+ | 'update-one'
9
+ | 'insert-one'
10
+ | 'remove-one'
11
+ | 'aggregate';
12
+
13
+ /**
14
+ * Context interface for database trigger callbacks
15
+ * @interface DatabaseTriggerContext
16
+ * @property {Record<string, any>} query - The query parameters used in the database operation
17
+ * @property {any | any[]} queryResult - The result of the database operation
18
+ */
19
+ export interface DatabaseTriggerContext {
20
+ query: Record<string, any>;
21
+ queryResult: any | any[];
22
+ }
23
+
24
+ /**
25
+ * The callback function to be executed on specific database operations
26
+ * @param {DatabaseTriggerContext} context - The context of the database operation
27
+ * @example
28
+ * ```typescript
29
+ * const trigger = new DatabaseTrigger('insert-one', (context) => {
30
+ * console.log('New document inserted:', context.queryResult);
31
+ * });
32
+ * ```
33
+ */
34
+ type DatabaseTriggerCallback = (context: DatabaseTriggerContext) => void;
35
+
36
+ /**
37
+ * in a complex application, you may need to perform additional actions after a database operation.
38
+ * this is where DatabaseTrigger comes in. so you can define a callback to be executed on specific database operations for a collection.
39
+ *
40
+ * Supported triggers are:
41
+ *
42
+ * | Trigger | Description |
43
+ * | ------------ | ------------------------------------------------------------ |
44
+ * | `find` | Triggered when a find query is executed on collection. |
45
+ * | `find-one` | Triggered when a find one query is executed on collection. |
46
+ * | `count` | Triggered when a count query is executed on collection. |
47
+ * | `update-one` | Triggered when a update one query is executed on collection. |
48
+ * | `insert-one` | Triggered when a insert one query is executed on collection. |
49
+ * | `remove-one` | Triggered when a remove one query is executed on collection. |
50
+ * | `aggregate` | Triggered when a aggregate query is executed on collection. |
51
+ *
52
+ * @property {DatabaseOperation} operation - The database operation that triggers the callback
53
+ * @property {DatabaseTriggerCallback} callback - The callback function to be executed
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * import { DatabaseTrigger } from '@server-ts/database';
58
+ *
59
+ * const trigger = new DatabaseTrigger('insert-one', ({ query, queryResult }) => {
60
+ * console.log('New document inserted:', queryResult);
61
+ *
62
+ * try {
63
+ * // Perform additional actions after document insertion
64
+ * } catch (error) {
65
+ * console.error('Error performing additional actions:', error);
66
+ * }
67
+ * });
68
+ *
69
+ * // Use the trigger in a collection definition
70
+ * const collection = new CollectionDefinition({
71
+ * triggers: [trigger]
72
+ * });
73
+ * ```
74
+ */
75
+ export class DatabaseTrigger {
76
+ operation: DatabaseOperation;
77
+ callback: (context: DatabaseTriggerContext) => void;
78
+
79
+ /**
80
+ * @hidden
81
+ *
82
+ * Creates a new DatabaseTrigger instance
83
+ * @param {DatabaseOperation} operation - The database operation to trigger on
84
+ * @param {DatabaseTriggerCallback} [callback=() => {}] - The callback function to execute
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const trigger = new DatabaseTrigger('insert-one', (context) => {
89
+ * console.log('New document inserted:', context.queryResult);
90
+ * });
91
+ *
92
+ */
93
+ constructor(operation: DatabaseOperation, callback: DatabaseTriggerCallback = () => {}) {
94
+ this.operation = operation;
95
+ this.callback = callback;
96
+ }
97
+ }
98
+
99
+ export default DatabaseTrigger;
@@ -0,0 +1,44 @@
1
+ import mongoose from 'mongoose';
2
+ const { Schema } = mongoose;
3
+
4
+ /**
5
+ * File schema interface
6
+ */
7
+ export interface IFile {
8
+ originalName: string;
9
+ fileName: string;
10
+ owner: string;
11
+ format: string;
12
+ // Tag being used as the parent dir for files
13
+ // uploadDir/$format/$tag/timestamp.format
14
+ tag: string;
15
+ size: number;
16
+ createdAt?: Date;
17
+ updatedAt?: Date;
18
+ }
19
+
20
+ /**
21
+ * File schema
22
+ */
23
+ export const fileSchema = new Schema<IFile>(
24
+ {
25
+ originalName: String,
26
+ fileName: String,
27
+ owner: String,
28
+ format: String,
29
+ // Tag being used as the parent dir for files
30
+ // uploadDir/$format/$tag/timestamp.format
31
+ tag: String,
32
+ size: Number,
33
+ },
34
+ { timestamps: true }
35
+ );
36
+
37
+ /**
38
+ * Schema definitions
39
+ */
40
+ export const schemas = {
41
+ file: fileSchema,
42
+ };
43
+
44
+ export default schemas;
@@ -1,19 +1,39 @@
1
- const fs = require("fs");
2
- const path = require("path");
1
+ import fs from 'fs';
2
+ import path from 'path';
3
3
 
4
- function walk(dir, settings, done) {
5
- let results = [];
4
+ interface DirectorySettings {
5
+ name?: string;
6
+ filter?: string[];
7
+ }
8
+
9
+ type WalkCallback = (err: Error | null, results: string[]) => void;
10
+
11
+ /**
12
+ * Walk through a directory and its subdirectories
13
+ * @param dir - Directory to walk
14
+ * @param settings - Settings for filtering files
15
+ * @param done - Callback function
16
+ */
17
+ function walk(dir: string, settings: DirectorySettings, done: WalkCallback): void {
18
+ let results: string[] = [];
6
19
 
7
20
  // Read director file and folders
8
21
  fs.readdir(dir, function (err, list) {
9
22
  if (err) return done(err, results);
10
23
 
11
- var pending = list.length;
24
+ let pending = list.length;
12
25
  if (!pending) return done(null, results);
13
26
 
14
27
  list.forEach(function (file) {
15
28
  file = path.join(dir, file);
16
29
  fs.stat(file, function (err, stat) {
30
+ if (err) {
31
+ // Handle file stat error but continue with other files
32
+ console.error(`Error reading file stats for ${file}:`, err);
33
+ if (!--pending) done(null, results);
34
+ return;
35
+ }
36
+
17
37
  // If directory, execute a recursive call
18
38
  if (stat && stat.isDirectory()) {
19
39
  // Add directory to array [comment if you need to remove the directories from the array]
@@ -24,9 +44,9 @@ function walk(dir, settings, done) {
24
44
  });
25
45
  } else {
26
46
  // file filter
27
- var extension = path.extname(file);
28
- var fileName = path.basename(file).split(".")[0];
29
- var fileNameKey = true;
47
+ const extension = path.extname(file);
48
+ const fileName = path.basename(file).split('.')[0];
49
+ let fileNameKey = true;
30
50
 
31
51
  // name filter
32
52
  if (settings.name && settings.name === fileName) fileNameKey = true;
@@ -35,9 +55,8 @@ function walk(dir, settings, done) {
35
55
  // extension filter
36
56
  if (settings.filter && fileNameKey) {
37
57
  settings.filter.forEach(function (element) {
38
- if (element.toLowerCase() === extension.toLowerCase())
39
- results.push(file);
40
- }, this);
58
+ if (element.toLowerCase() === extension.toLowerCase()) results.push(file);
59
+ });
41
60
  }
42
61
 
43
62
  // push any file if no option
@@ -50,16 +69,19 @@ function walk(dir, settings, done) {
50
69
  });
51
70
  }
52
71
 
53
- function find(dir, settings) {
54
- return new Promise((don, reject) => {
72
+ /**
73
+ * Find files in a directory with Promise API
74
+ * @param dir - Directory to search
75
+ * @param settings - Settings for filtering files
76
+ * @returns Promise resolving to an array of file paths
77
+ */
78
+ function find(dir: string, settings: DirectorySettings): Promise<string[]> {
79
+ return new Promise((resolve, reject) => {
55
80
  walk(dir, settings, (err, result) => {
56
81
  if (err) reject(err);
57
- else don(result);
82
+ else resolve(result);
58
83
  });
59
84
  });
60
85
  }
61
86
 
62
- module.exports = {
63
- walk,
64
- find,
65
- };
87
+ export { walk, find };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Pagination result interface
3
+ */
4
+ export interface PaginationResult {
5
+ pages: number;
6
+ page: number;
7
+ from: number;
8
+ to: number;
9
+ }
10
+
11
+ /**
12
+ * Creates a pagination object based on the given parameters.
13
+ * @param count - The total number of items to paginate.
14
+ * @param perPage - The number of items to display per page.
15
+ * @param page - The current page number.
16
+ * @returns An object containing pagination information.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { paginator } from '@modular-rest/server';
21
+ *
22
+ * const pagination = paginator.create(100, 10, 1);
23
+ * // json response will be like this
24
+ * // {
25
+ * // pages: 10,
26
+ * // page: 1,
27
+ * // from: 0,
28
+ * // to: 10,
29
+ * // }
30
+ * ```
31
+ */
32
+ export function create(count: number, perPage: number, page: number): PaginationResult {
33
+ const totalPages = Math.ceil(count / perPage);
34
+
35
+ if (page > totalPages) page = 1;
36
+
37
+ let from = 0;
38
+ if (perPage === 1) from = page - 1;
39
+ else from = perPage * page - perPage;
40
+
41
+ if (page <= 1) from = 0;
42
+
43
+ const result: PaginationResult = {
44
+ pages: totalPages,
45
+ page: page,
46
+ from: from,
47
+ to: perPage,
48
+ };
49
+
50
+ return result;
51
+ }