@airoom/nextmin-node 0.1.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.
Files changed (45) hide show
  1. package/LICENSE +49 -0
  2. package/README.md +178 -0
  3. package/dist/api/apiRouter.d.ts +65 -0
  4. package/dist/api/apiRouter.js +1548 -0
  5. package/dist/database/DatabaseAdapter.d.ts +14 -0
  6. package/dist/database/DatabaseAdapter.js +2 -0
  7. package/dist/database/InMemoryAdapter.d.ts +15 -0
  8. package/dist/database/InMemoryAdapter.js +71 -0
  9. package/dist/database/MongoAdapter.d.ts +52 -0
  10. package/dist/database/MongoAdapter.js +409 -0
  11. package/dist/files/FileStorageAdapter.d.ts +35 -0
  12. package/dist/files/FileStorageAdapter.js +2 -0
  13. package/dist/files/S3FileStorageAdapter.d.ts +30 -0
  14. package/dist/files/S3FileStorageAdapter.js +84 -0
  15. package/dist/files/filename.d.ts +5 -0
  16. package/dist/files/filename.js +40 -0
  17. package/dist/index.d.ts +13 -0
  18. package/dist/index.js +87 -0
  19. package/dist/models/BaseModel.d.ts +44 -0
  20. package/dist/models/BaseModel.js +31 -0
  21. package/dist/policy/authorize.d.ts +25 -0
  22. package/dist/policy/authorize.js +305 -0
  23. package/dist/policy/conditions.d.ts +14 -0
  24. package/dist/policy/conditions.js +30 -0
  25. package/dist/policy/types.d.ts +53 -0
  26. package/dist/policy/types.js +2 -0
  27. package/dist/policy/utils.d.ts +9 -0
  28. package/dist/policy/utils.js +118 -0
  29. package/dist/schemas/Roles.json +64 -0
  30. package/dist/schemas/Settings.json +62 -0
  31. package/dist/schemas/Users.json +123 -0
  32. package/dist/services/SchemaService.d.ts +10 -0
  33. package/dist/services/SchemaService.js +46 -0
  34. package/dist/utils/DefaultDataInitializer.d.ts +21 -0
  35. package/dist/utils/DefaultDataInitializer.js +269 -0
  36. package/dist/utils/Logger.d.ts +12 -0
  37. package/dist/utils/Logger.js +79 -0
  38. package/dist/utils/SchemaLoader.d.ts +51 -0
  39. package/dist/utils/SchemaLoader.js +323 -0
  40. package/dist/utils/apiKey.d.ts +5 -0
  41. package/dist/utils/apiKey.js +14 -0
  42. package/dist/utils/fieldCodecs.d.ts +13 -0
  43. package/dist/utils/fieldCodecs.js +133 -0
  44. package/package.json +45 -0
  45. package/tsconfig.json +8 -0
@@ -0,0 +1,323 @@
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.SchemaLoader = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chokidar_1 = __importDefault(require("chokidar"));
10
+ const Logger_1 = __importDefault(require("./Logger"));
11
+ const events_1 = require("events");
12
+ function validateSchema(obj) {
13
+ const missing = [];
14
+ if (!obj.modelName || typeof obj.modelName !== 'string')
15
+ missing.push('modelName');
16
+ if (!obj.attributes ||
17
+ typeof obj.attributes !== 'object' ||
18
+ Array.isArray(obj.attributes)) {
19
+ missing.push('attributes');
20
+ }
21
+ else {
22
+ for (const [key, attr] of Object.entries(obj.attributes)) {
23
+ if (Array.isArray(attr)) {
24
+ // Each element in the array must be an object with type:string
25
+ if (attr.length === 0 ||
26
+ attr.some((item) => item === null ||
27
+ typeof item !== 'object' ||
28
+ Array.isArray(item) ||
29
+ typeof item.type !== 'string')) {
30
+ missing.push(`attributes.${key}[]`);
31
+ }
32
+ }
33
+ else {
34
+ if (attr === null ||
35
+ typeof attr !== 'object' ||
36
+ Array.isArray(attr) ||
37
+ // @ts-ignore
38
+ typeof attr.type !== 'string') {
39
+ missing.push(`attributes.${key}.type`);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ if (!obj.allowedMethods ||
45
+ typeof obj.allowedMethods !== 'object' ||
46
+ Array.isArray(obj.allowedMethods)) {
47
+ missing.push('allowedMethods');
48
+ }
49
+ else {
50
+ const allowed = obj.allowedMethods;
51
+ if (typeof allowed.create !== 'boolean' &&
52
+ typeof allowed.read !== 'boolean' &&
53
+ typeof allowed.update !== 'boolean' &&
54
+ typeof allowed.delete !== 'boolean') {
55
+ missing.push('allowedMethods.(at least one CRUD boolean)');
56
+ }
57
+ }
58
+ return missing;
59
+ }
60
+ class SchemaLoader {
61
+ // Singleton instance
62
+ static getInstance() {
63
+ if (!SchemaLoader._instance) {
64
+ SchemaLoader._instance = new SchemaLoader();
65
+ }
66
+ return SchemaLoader._instance;
67
+ }
68
+ constructor() {
69
+ this.emitter = new events_1.EventEmitter();
70
+ this.schemas = {};
71
+ this.isDevelopment = false;
72
+ this.nonOverridableSchemas = new Set(['User', 'Role']);
73
+ this.watcher = null; // <-- TS-safe
74
+ this.isDevelopment = process.env.APP_MODE !== 'production';
75
+ const baseDir = process.cwd();
76
+ const basePackageDir = path_1.default.resolve(__dirname, '..');
77
+ this.packageSchemasDir = path_1.default.join(basePackageDir, 'schemas');
78
+ this.userSchemasDir = path_1.default.resolve(baseDir, 'schemas');
79
+ this.loadSchemas();
80
+ if (this.isDevelopment) {
81
+ this.setupHotReload();
82
+ }
83
+ }
84
+ setupHotReload() {
85
+ if (!fs_1.default.existsSync(this.userSchemasDir)) {
86
+ Logger_1.default.warn(`User schemas directory not found for hot reload: ${this.userSchemasDir}`);
87
+ return;
88
+ }
89
+ Logger_1.default.info(`Watching user schemas directory for hot reload: ${this.userSchemasDir}`);
90
+ this.watcher = chokidar_1.default.watch(this.userSchemasDir, {
91
+ persistent: true,
92
+ ignoreInitial: true,
93
+ depth: 1,
94
+ awaitWriteFinish: {
95
+ stabilityThreshold: 200,
96
+ pollInterval: 100,
97
+ },
98
+ });
99
+ this.watcher
100
+ .on('add', (filePath) => this.handleFileChange('added', filePath))
101
+ .on('change', (filePath) => this.handleFileChange('changed', filePath))
102
+ .on('unlink', (filePath) => this.handleFileChange('removed', filePath));
103
+ }
104
+ handleFileChange(type, filePath) {
105
+ if (!filePath.endsWith('.json'))
106
+ return;
107
+ Logger_1.default.info(`Schema file ${type}: ${filePath}`);
108
+ try {
109
+ this.loadSchemas();
110
+ Logger_1.default.info('Schemas hot-reloaded successfully!');
111
+ this.emitter.emit('schemasChanged', this.getPublicSchemaList());
112
+ }
113
+ catch (err) {
114
+ Logger_1.default.error(`Error during schema hot reload for ${filePath}:`, err);
115
+ }
116
+ }
117
+ on(event, listener) {
118
+ this.emitter.on(event, listener);
119
+ }
120
+ loadSchemas() {
121
+ const schemas = {};
122
+ this.loadSchemasFromDirectory(this.packageSchemasDir, schemas, false, true);
123
+ if (fs_1.default.existsSync(this.userSchemasDir)) {
124
+ this.loadSchemasFromDirectory(this.userSchemasDir, schemas, true, false);
125
+ }
126
+ for (const schema of Object.values(schemas)) {
127
+ if (schema.extends) {
128
+ const baseSchema = schemas[schema.extends];
129
+ if (baseSchema) {
130
+ schema.attributes = {
131
+ ...baseSchema.attributes,
132
+ ...schema.attributes,
133
+ };
134
+ schema.allowedMethods = {
135
+ ...baseSchema.allowedMethods,
136
+ ...schema.allowedMethods,
137
+ };
138
+ }
139
+ else {
140
+ throw new Error(`Base schema ${schema.extends} not found for ${schema.modelName}`);
141
+ }
142
+ }
143
+ }
144
+ this.processSchemas(schemas);
145
+ if (this.isDevelopment) {
146
+ Logger_1.default.info('Schemas loaded:', Object.keys(this.schemas).join(', '));
147
+ }
148
+ }
149
+ processSchemas(schemas) {
150
+ this.schemas = Object.fromEntries(Object.entries(schemas).filter(([_, schema]) => !schema.private));
151
+ }
152
+ loadSchemasFromDirectory(directory, schemas, isUserSchema, isPackageSchema) {
153
+ if (!fs_1.default.existsSync(directory))
154
+ return;
155
+ const schemaFiles = fs_1.default
156
+ .readdirSync(directory)
157
+ .filter((file) => file.endsWith('.json'));
158
+ for (const file of schemaFiles) {
159
+ const schemaPath = path_1.default.join(directory, file);
160
+ try {
161
+ const raw = fs_1.default.readFileSync(schemaPath, 'utf-8');
162
+ const schema = JSON.parse(raw);
163
+ // VALIDATION
164
+ const missing = validateSchema(schema);
165
+ if (missing.length > 0) {
166
+ Logger_1.default.info(`Schema at ${schemaPath} is invalid. Missing/invalid fields: ${missing.join(', ')}. Skipping this schema.`);
167
+ continue;
168
+ }
169
+ const modelName = schema.modelName;
170
+ if (this.nonOverridableSchemas.has(modelName)) {
171
+ if (isPackageSchema) {
172
+ schemas[modelName] = schema;
173
+ }
174
+ else if (isUserSchema) {
175
+ // Instead of blocking, MERGE user changes into package default
176
+ const base = schemas[modelName];
177
+ if (base) {
178
+ // shallow merge + attributes deep merge with delete support
179
+ const merged = {
180
+ ...base,
181
+ ...schema,
182
+ attributes: this.mergeAttributes(base.attributes, schema.attributes),
183
+ allowedMethods: {
184
+ ...base.allowedMethods,
185
+ ...schema.allowedMethods,
186
+ },
187
+ };
188
+ schemas[modelName] = merged;
189
+ }
190
+ else {
191
+ schemas[modelName] = schema;
192
+ }
193
+ }
194
+ }
195
+ else {
196
+ // current behavior for other models
197
+ if (isUserSchema || !schemas[modelName]) {
198
+ schemas[modelName] = schema;
199
+ }
200
+ else {
201
+ Logger_1.default.warn(`Schema for '${modelName}' already exists. Skipping ${schemaPath}.`);
202
+ }
203
+ }
204
+ }
205
+ catch (error) {
206
+ Logger_1.default.error(`Error loading schema file ${schemaPath}:`, error);
207
+ }
208
+ }
209
+ }
210
+ mergeAttributes(base, patch) {
211
+ const out = { ...base };
212
+ for (const [k, v] of Object.entries(patch || {})) {
213
+ if (v &&
214
+ typeof v === 'object' &&
215
+ !Array.isArray(v) &&
216
+ v.$delete) {
217
+ delete out[k]; // allow deletions via {"$delete": true}
218
+ continue;
219
+ }
220
+ out[k] = v; // override/relax required/unique/etc.
221
+ }
222
+ return out;
223
+ }
224
+ getSchemas() {
225
+ return this.schemas;
226
+ }
227
+ /** CLIENT/API: sanitized map with private attributes removed */
228
+ getPublicSchemas() {
229
+ const out = {};
230
+ for (const [name, s] of Object.entries(this.schemas)) {
231
+ // if (this.nonOverridableSchemas.has(name)) continue;
232
+ // Clone sanitized attributes and add timestamps
233
+ const attributesWithTimestamps = {
234
+ ...this.sanitizeAttributes(s.attributes),
235
+ createdAt: { type: 'datetime' },
236
+ updatedAt: { type: 'datetime' },
237
+ };
238
+ out[name] = {
239
+ modelName: s.modelName,
240
+ allowedMethods: s.allowedMethods,
241
+ attributes: attributesWithTimestamps,
242
+ };
243
+ }
244
+ return out;
245
+ }
246
+ /** CLIENT/API convenience: array of { modelName, attributes, allowedMethods } */
247
+ getPublicSchemaList() {
248
+ const pub = this.getPublicSchemas();
249
+ return Object.values(pub);
250
+ }
251
+ /** Strip any attr marked private; also remove the `private` flag from others */
252
+ /** Keep private/sensitive flags so the UI and policy layer can decide.
253
+ * We only shallow-clone values to avoid leaking references.
254
+ */
255
+ sanitizeAttributes(attrs) {
256
+ const out = {};
257
+ if (!attrs || typeof attrs !== 'object' || Array.isArray(attrs))
258
+ return out;
259
+ for (const [key, attr] of Object.entries(attrs)) {
260
+ // Array attributes (e.g., relations) expect a single descriptor in [0]
261
+ if (Array.isArray(attr)) {
262
+ const elem = attr[0];
263
+ if (elem && typeof elem === 'object') {
264
+ // Keep as an array with a single shallow-cloned descriptor, preserving flags like `private`, `sensitive`, `writeOnly`
265
+ out[key] = [{ ...elem }];
266
+ }
267
+ else {
268
+ // Fallback: keep as-is
269
+ out[key] = attr;
270
+ }
271
+ continue;
272
+ }
273
+ // Single attribute object
274
+ if (attr && typeof attr === 'object') {
275
+ // Keep `private`, `sensitive`, `writeOnly`, etc.
276
+ out[key] = { ...attr };
277
+ continue;
278
+ }
279
+ // Unexpected primitives — pass through
280
+ out[key] = attr;
281
+ }
282
+ return out;
283
+ }
284
+ closeWatcher() {
285
+ if (this.watcher) {
286
+ this.watcher.close();
287
+ }
288
+ }
289
+ coerceIndexDir(val) {
290
+ if (val === true || val === 'asc' || val === 1)
291
+ return 1;
292
+ if (val === 'desc' || val === -1)
293
+ return -1;
294
+ return null;
295
+ }
296
+ /** Build desired single-field indexes per model from schemas.
297
+ * - respects attribute.index (true|1|-1|'asc'|'desc')
298
+ * - always adds createdAt/updatedAt (desc) to help common sorts.
299
+ */
300
+ getIndexPlan() {
301
+ const plan = {};
302
+ for (const [name, s] of Object.entries(this.schemas)) {
303
+ const spec = {};
304
+ // from declared attributes
305
+ const attrs = s.attributes || {};
306
+ for (const [field, rawAttr] of Object.entries(attrs)) {
307
+ const attr = Array.isArray(rawAttr) ? rawAttr[0] : rawAttr;
308
+ if (!attr || typeof attr !== 'object')
309
+ continue;
310
+ // allow `index` on any attribute
311
+ const dir = this.coerceIndexDir(attr.index);
312
+ if (dir)
313
+ spec[field] = dir;
314
+ }
315
+ // always add timestamps (desc). Does not require attributes to exist.
316
+ spec.createdAt = spec.createdAt ?? -1;
317
+ spec.updatedAt = spec.updatedAt ?? -1;
318
+ plan[name] = spec;
319
+ }
320
+ return plan;
321
+ }
322
+ }
323
+ exports.SchemaLoader = SchemaLoader;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generates a cryptographically strong API key.
3
+ * Uses 32 bytes (256 bits) hex string.
4
+ */
5
+ export declare function generateApiKey(): string;
@@ -0,0 +1,14 @@
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.generateApiKey = generateApiKey;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ /**
9
+ * Generates a cryptographically strong API key.
10
+ * Uses 32 bytes (256 bits) hex string.
11
+ */
12
+ function generateApiKey() {
13
+ return crypto_1.default.randomBytes(32).toString('hex');
14
+ }
@@ -0,0 +1,13 @@
1
+ export type Json = string | number | boolean | null | Json[] | {
2
+ [k: string]: Json;
3
+ };
4
+ /**
5
+ * DB-agnostic payload coercion:
6
+ * - time → "HH:mm"
7
+ * - date → "YYYY-MM-DD" (or "YYYY-MM-DDTHH:mm" when withTime)
8
+ * - range(timeOnly) → "HH:mm..HH:mm"
9
+ * - range(date[/time]) → "YYYY-MM-DD[..THH:mm]..YYYY-MM-DD[..THH:mm]"
10
+ */
11
+ export declare function coerceForStorage(modelSchema: {
12
+ attributes: Record<string, any>;
13
+ }, payload: Record<string, any>): Record<string, Json>;
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.coerceForStorage = coerceForStorage;
4
+ function toTimeString(v) {
5
+ if (v == null)
6
+ return '';
7
+ let s = String(v).trim();
8
+ // 930 / 1530 → 09:30 / 15:30
9
+ if (/^\d{3,4}$/.test(s)) {
10
+ const pad = s.padStart(4, '0');
11
+ return `${pad.slice(0, 2)}:${pad.slice(2)}`;
12
+ }
13
+ // "h:mm AM/PM"
14
+ const ampm = s.match(/\s*([AaPp][Mm])\s*$/);
15
+ if (ampm) {
16
+ const core = s.replace(/\s*[AaPp][Mm]\s*$/, '').trim();
17
+ const m = core.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/);
18
+ if (!m)
19
+ return '';
20
+ let h = Number(m[1]);
21
+ const min = Number(m[2]);
22
+ const isPM = /^[Pp]/.test(ampm[1]);
23
+ if (isPM && h < 12)
24
+ h += 12;
25
+ if (!isPM && h === 12)
26
+ h = 0;
27
+ const hh = String(h).padStart(2, '0');
28
+ const mm = String(min).padStart(2, '0');
29
+ return `${hh}:${mm}`;
30
+ }
31
+ // "H:mm" / "HH:mm" / "HH:mm:ss"
32
+ const m24 = s.match(/^(\d{1,2}):(\d{2})(?::\d{2})?$/);
33
+ if (m24) {
34
+ const hh = String(Number(m24[1])).padStart(2, '0');
35
+ const mm = String(Number(m24[2])).padStart(2, '0');
36
+ return `${hh}:${mm}`;
37
+ }
38
+ return '';
39
+ }
40
+ function toDateString(v, withTime) {
41
+ if (v == null)
42
+ return '';
43
+ const s = String(v).trim();
44
+ // Already in target formats
45
+ if (!withTime && /^\d{4}-\d{2}-\d{2}$/.test(s))
46
+ return s;
47
+ if (withTime && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(s))
48
+ return s;
49
+ // Try to parse Date-ish strings or epoch numbers
50
+ const d = new Date(s);
51
+ if (Number.isFinite(Number(s))) {
52
+ const n = Number(s);
53
+ if (n > 0)
54
+ d.setTime(n);
55
+ }
56
+ if (isNaN(d.getTime()))
57
+ return '';
58
+ const yyyy = d.getFullYear();
59
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
60
+ const dd = String(d.getDate()).padStart(2, '0');
61
+ if (!withTime)
62
+ return `${yyyy}-${mm}-${dd}`;
63
+ const hh = String(d.getHours()).padStart(2, '0');
64
+ const mi = String(d.getMinutes()).padStart(2, '0');
65
+ return `${yyyy}-${mm}-${dd}T${hh}:${mi}`;
66
+ }
67
+ function toRangeString(v, opts) {
68
+ if (v == null)
69
+ return '';
70
+ // Object {start,end}
71
+ if (typeof v === 'object' && !Array.isArray(v)) {
72
+ const anyv = v;
73
+ const s = anyv?.start ?? '';
74
+ const e = anyv?.end ?? '';
75
+ if (opts.timeOnly) {
76
+ return `${toTimeString(s)}..${toTimeString(e)}`;
77
+ }
78
+ return `${toDateString(s, !!opts.withTime)}..${toDateString(e, !!opts.withTime)}`;
79
+ }
80
+ // Array [start, end]
81
+ if (Array.isArray(v)) {
82
+ const [s, e] = v;
83
+ if (opts.timeOnly) {
84
+ return `${toTimeString(s)}..${toTimeString(e)}`;
85
+ }
86
+ return `${toDateString(s, !!opts.withTime)}..${toDateString(e, !!opts.withTime)}`;
87
+ }
88
+ // String "start..end" (leave as-is, but normalize empties)
89
+ if (typeof v === 'string') {
90
+ const [s = '', e = ''] = v.split('..');
91
+ if (opts.timeOnly)
92
+ return `${toTimeString(s)}..${toTimeString(e)}`;
93
+ return `${toDateString(s, !!opts.withTime)}..${toDateString(e, !!opts.withTime)}`;
94
+ }
95
+ return '';
96
+ }
97
+ /**
98
+ * DB-agnostic payload coercion:
99
+ * - time → "HH:mm"
100
+ * - date → "YYYY-MM-DD" (or "YYYY-MM-DDTHH:mm" when withTime)
101
+ * - range(timeOnly) → "HH:mm..HH:mm"
102
+ * - range(date[/time]) → "YYYY-MM-DD[..THH:mm]..YYYY-MM-DD[..THH:mm]"
103
+ */
104
+ function coerceForStorage(modelSchema, payload) {
105
+ const out = { ...payload };
106
+ for (const [name, attr] of Object.entries(modelSchema.attributes ?? {})) {
107
+ if (!(name in out))
108
+ continue;
109
+ const t = String(attr?.type ?? '').toLowerCase();
110
+ const withTime = Boolean(attr?.withTime);
111
+ const timeOnly = Boolean(attr?.timeOnly);
112
+ const val = out[name];
113
+ switch (t) {
114
+ case 'time': {
115
+ out[name] = toTimeString(val);
116
+ break;
117
+ }
118
+ case 'date':
119
+ case 'datetime': {
120
+ out[name] = toDateString(val, withTime);
121
+ break;
122
+ }
123
+ case 'range': {
124
+ out[name] = toRangeString(val, { timeOnly, withTime });
125
+ break;
126
+ }
127
+ default:
128
+ // leave as-is
129
+ break;
130
+ }
131
+ }
132
+ return out;
133
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@airoom/nextmin-node",
3
+ "version": "0.1.0",
4
+ "license": "SEE LICENSE IN LICENSE",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "rm -rf dist && tsc --project tsconfig.json && copyfiles -u 2 \"src/schemas/**/*\" dist/schemas",
9
+ "watch": "tsc --project tsconfig.json --watch",
10
+ "prepublishOnly": "npm run build && npm pack --dry-run | (! grep -E '\\bsrc/|\\.map$')"
11
+ },
12
+ "dependencies": {
13
+ "@aws-sdk/client-s3": "^3.864.0",
14
+ "@aws-sdk/s3-request-presigner": "^3.864.0",
15
+ "bcrypt": "^6.0.0",
16
+ "body-parser": "^2.2.0",
17
+ "chokidar": "^4.0.3",
18
+ "fast-glob": "^3.3.1",
19
+ "jsonwebtoken": "^9.0.2",
20
+ "kleur": "^4.1.5",
21
+ "mongoose": "^8.17.0",
22
+ "mongoose-autopopulate": "^1.1.0",
23
+ "multer": "^2.0.2",
24
+ "socket.io": "^4.7.5"
25
+ },
26
+ "devDependencies": {
27
+ "@types/bcrypt": "^6.0.0",
28
+ "@types/chokidar": "^2.1.7",
29
+ "@types/jsonwebtoken": "^9.0.10",
30
+ "@types/multer": "^2.0.0",
31
+ "copyfiles": "^2.4.1",
32
+ "typescript": "^5.3.3"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "package.json",
37
+ "tsconfig.json",
38
+ "LICENSE",
39
+ "README.md"
40
+ ],
41
+ "sideEffects": false,
42
+ "publishConfig": {
43
+ "access": "public"
44
+ }
45
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "sourceMap": false
6
+ },
7
+ "include": ["src"]
8
+ }