@exyconn/common 2.1.0 → 2.3.3
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/README.md +969 -261
- package/dist/client/hooks/index.d.mts +1042 -0
- package/dist/client/hooks/index.d.ts +1042 -0
- package/dist/client/hooks/index.js +2276 -0
- package/dist/client/hooks/index.js.map +1 -0
- package/dist/client/hooks/index.mjs +2217 -0
- package/dist/client/hooks/index.mjs.map +1 -0
- package/dist/client/http/index.d.mts +217 -49
- package/dist/client/http/index.d.ts +217 -49
- package/dist/client/http/index.js +473 -94
- package/dist/client/http/index.js.map +1 -1
- package/dist/client/http/index.mjs +441 -84
- package/dist/client/http/index.mjs.map +1 -1
- package/dist/client/index.d.mts +6 -4
- package/dist/client/index.d.ts +6 -4
- package/dist/client/index.js +481 -319
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +449 -290
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/utils/index.d.mts +3 -279
- package/dist/client/utils/index.d.ts +3 -279
- package/dist/client/web/index.d.mts +1461 -0
- package/dist/client/web/index.d.ts +1461 -0
- package/dist/client/web/index.js +2681 -0
- package/dist/client/web/index.js.map +1 -0
- package/dist/client/web/index.mjs +2618 -0
- package/dist/client/web/index.mjs.map +1 -0
- package/dist/data/brand-identity.d.mts +149 -0
- package/dist/data/brand-identity.d.ts +149 -0
- package/dist/data/brand-identity.js +235 -0
- package/dist/data/brand-identity.js.map +1 -0
- package/dist/data/brand-identity.mjs +220 -0
- package/dist/data/brand-identity.mjs.map +1 -0
- package/dist/data/countries.d.mts +61 -0
- package/dist/data/countries.d.ts +61 -0
- package/dist/data/countries.js +987 -0
- package/dist/data/countries.js.map +1 -0
- package/dist/data/countries.mjs +971 -0
- package/dist/data/countries.mjs.map +1 -0
- package/dist/data/currencies.d.mts +19 -0
- package/dist/data/currencies.d.ts +19 -0
- package/dist/data/currencies.js +162 -0
- package/dist/data/currencies.js.map +1 -0
- package/dist/data/currencies.mjs +153 -0
- package/dist/data/currencies.mjs.map +1 -0
- package/dist/data/index.d.mts +7 -0
- package/dist/data/index.d.ts +7 -0
- package/dist/data/index.js +2087 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/index.mjs +1948 -0
- package/dist/data/index.mjs.map +1 -0
- package/dist/data/phone-codes.d.mts +15 -0
- package/dist/data/phone-codes.d.ts +15 -0
- package/dist/data/phone-codes.js +219 -0
- package/dist/data/phone-codes.js.map +1 -0
- package/dist/data/phone-codes.mjs +211 -0
- package/dist/data/phone-codes.mjs.map +1 -0
- package/dist/data/regex.d.mts +287 -0
- package/dist/data/regex.d.ts +287 -0
- package/dist/data/regex.js +306 -0
- package/dist/data/regex.js.map +1 -0
- package/dist/data/regex.mjs +208 -0
- package/dist/data/regex.mjs.map +1 -0
- package/dist/data/timezones.d.mts +16 -0
- package/dist/data/timezones.d.ts +16 -0
- package/dist/data/timezones.js +98 -0
- package/dist/data/timezones.js.map +1 -0
- package/dist/data/timezones.mjs +89 -0
- package/dist/data/timezones.mjs.map +1 -0
- package/dist/index-BZf42T3R.d.mts +305 -0
- package/dist/index-CF0D8PGE.d.ts +305 -0
- package/dist/index-Ckhm_HaX.d.mts +138 -0
- package/dist/index-DKn4raO7.d.ts +222 -0
- package/dist/index-NS8dS0p9.d.mts +222 -0
- package/dist/index-Nqm5_lwT.d.ts +188 -0
- package/dist/index-br6POSyA.d.ts +138 -0
- package/dist/index-jBi3V6e5.d.mts +188 -0
- package/dist/index.d.mts +21 -580
- package/dist/index.d.ts +21 -580
- package/dist/index.js +1839 -347
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1850 -359
- package/dist/index.mjs.map +1 -1
- package/dist/packageCheck-B_qfsD6R.d.ts +280 -0
- package/dist/packageCheck-C2_FT_Rl.d.mts +280 -0
- package/dist/server/configs/index.d.mts +602 -0
- package/dist/server/configs/index.d.ts +602 -0
- package/dist/server/configs/index.js +707 -0
- package/dist/server/configs/index.js.map +1 -0
- package/dist/server/configs/index.mjs +665 -0
- package/dist/server/configs/index.mjs.map +1 -0
- package/dist/server/index.d.mts +4 -1
- package/dist/server/index.d.ts +4 -1
- package/dist/server/index.js +1330 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1286 -2
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/middleware/index.d.mts +283 -2
- package/dist/server/middleware/index.d.ts +283 -2
- package/dist/server/middleware/index.js +761 -0
- package/dist/server/middleware/index.js.map +1 -1
- package/dist/server/middleware/index.mjs +751 -1
- package/dist/server/middleware/index.mjs.map +1 -1
- package/dist/shared/config/index.d.mts +40 -0
- package/dist/shared/config/index.d.ts +40 -0
- package/dist/shared/config/index.js +58 -0
- package/dist/shared/config/index.js.map +1 -0
- package/dist/shared/config/index.mjs +51 -0
- package/dist/shared/config/index.mjs.map +1 -0
- package/dist/shared/constants/index.d.mts +593 -0
- package/dist/shared/constants/index.d.ts +593 -0
- package/dist/shared/constants/index.js +391 -0
- package/dist/shared/constants/index.js.map +1 -0
- package/dist/shared/constants/index.mjs +360 -0
- package/dist/shared/constants/index.mjs.map +1 -0
- package/dist/shared/index.d.mts +5 -1
- package/dist/shared/index.d.ts +5 -1
- package/dist/shared/types/index.d.mts +140 -0
- package/dist/shared/types/index.d.ts +140 -0
- package/dist/shared/types/index.js +4 -0
- package/dist/shared/types/index.js.map +1 -0
- package/dist/shared/types/index.mjs +3 -0
- package/dist/shared/types/index.mjs.map +1 -0
- package/dist/shared/utils/index.d.mts +255 -0
- package/dist/shared/utils/index.d.ts +255 -0
- package/dist/shared/utils/index.js +623 -0
- package/dist/shared/utils/index.js.map +1 -0
- package/dist/shared/utils/index.mjs +324 -0
- package/dist/shared/utils/index.mjs.map +1 -0
- package/dist/shared/validation/index.d.mts +258 -0
- package/dist/shared/validation/index.d.ts +258 -0
- package/dist/shared/validation/index.js +185 -0
- package/dist/shared/validation/index.js.map +1 -0
- package/dist/shared/validation/index.mjs +172 -0
- package/dist/shared/validation/index.mjs.map +1 -0
- package/package.json +127 -62
- package/dist/index-BcxL4_V4.d.ts +0 -2946
- package/dist/index-DEzgM15j.d.ts +0 -67
- package/dist/index-DNFVgQx8.d.ts +0 -1375
- package/dist/index-DbV04Dx8.d.mts +0 -67
- package/dist/index-DfqEP6Oe.d.mts +0 -1375
- package/dist/index-bvvCev9Q.d.mts +0 -2946
|
@@ -1,14 +1,53 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jwt = require('jsonwebtoken');
|
|
4
|
+
var mongoose = require('mongoose');
|
|
5
|
+
var winston = require('winston');
|
|
6
|
+
var DailyRotateFile = require('winston-daily-rotate-file');
|
|
7
|
+
var path = require('path');
|
|
4
8
|
|
|
5
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
10
|
|
|
7
11
|
var jwt__default = /*#__PURE__*/_interopDefault(jwt);
|
|
12
|
+
var winston__default = /*#__PURE__*/_interopDefault(winston);
|
|
13
|
+
var DailyRotateFile__default = /*#__PURE__*/_interopDefault(DailyRotateFile);
|
|
14
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
8
15
|
|
|
9
16
|
// src/server/middleware/auth.middleware.ts
|
|
10
17
|
|
|
11
18
|
// src/server/response/response-object.ts
|
|
19
|
+
var successResponse = (res, data, message = "Operation successful") => {
|
|
20
|
+
return res.status(200 /* SUCCESS */).json({
|
|
21
|
+
message,
|
|
22
|
+
data,
|
|
23
|
+
status: "success" /* SUCCESS */,
|
|
24
|
+
statusCode: 200 /* SUCCESS */
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
var createdResponse = (res, data, message = "Resource created successfully") => {
|
|
28
|
+
return res.status(201 /* CREATED */).json({
|
|
29
|
+
message,
|
|
30
|
+
data,
|
|
31
|
+
status: "created" /* CREATED */,
|
|
32
|
+
statusCode: 201 /* CREATED */
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
var noContentResponse = (res, data = null, message = "No data found") => {
|
|
36
|
+
return res.status(200 /* SUCCESS */).json({
|
|
37
|
+
message,
|
|
38
|
+
data,
|
|
39
|
+
status: "no-data-found" /* NO_CONTENT */,
|
|
40
|
+
statusCode: 204 /* NO_CONTENT */
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
var badRequestResponse = (res, message = "Bad request", errors = null) => {
|
|
44
|
+
return res.status(400 /* BAD_REQUEST */).json({
|
|
45
|
+
message,
|
|
46
|
+
data: errors,
|
|
47
|
+
status: "bad-request" /* BAD_REQUEST */,
|
|
48
|
+
statusCode: 400 /* BAD_REQUEST */
|
|
49
|
+
});
|
|
50
|
+
};
|
|
12
51
|
var unauthorizedResponse = (res, message = "Unauthorized access") => {
|
|
13
52
|
return res.status(401 /* UNAUTHORIZED */).json({
|
|
14
53
|
message,
|
|
@@ -25,6 +64,22 @@ var forbiddenResponse = (res, message = "Access forbidden") => {
|
|
|
25
64
|
statusCode: 403 /* FORBIDDEN */
|
|
26
65
|
});
|
|
27
66
|
};
|
|
67
|
+
var notFoundResponse = (res, message = "Resource not found") => {
|
|
68
|
+
return res.status(404 /* NOT_FOUND */).json({
|
|
69
|
+
message,
|
|
70
|
+
data: null,
|
|
71
|
+
status: "not-found" /* NOT_FOUND */,
|
|
72
|
+
statusCode: 404 /* NOT_FOUND */
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
var errorResponse = (res, error = null, message = "Something went wrong") => {
|
|
76
|
+
return res.status(500 /* INTERNAL_ERROR */).json({
|
|
77
|
+
message,
|
|
78
|
+
data: error,
|
|
79
|
+
status: "error" /* INTERNAL_ERROR */,
|
|
80
|
+
statusCode: 500 /* INTERNAL_ERROR */
|
|
81
|
+
});
|
|
82
|
+
};
|
|
28
83
|
|
|
29
84
|
// src/server/middleware/auth.middleware.ts
|
|
30
85
|
var authenticateJWT = (secretKey) => {
|
|
@@ -119,10 +174,716 @@ var requireOrganization = (req, res, next) => {
|
|
|
119
174
|
next();
|
|
120
175
|
};
|
|
121
176
|
|
|
177
|
+
// src/server/middleware/queryParser.middleware.ts
|
|
178
|
+
var queryParser = (req, _, next) => {
|
|
179
|
+
const { page, limit, sort, sortBy, sortOrder, search, filter, ...otherParams } = req.query;
|
|
180
|
+
const parsed = {
|
|
181
|
+
page: Math.max(Number(page) || 1, 1),
|
|
182
|
+
limit: Math.min(Number(limit) || 10, 100),
|
|
183
|
+
filter: {}
|
|
184
|
+
};
|
|
185
|
+
if (typeof sort === "string") {
|
|
186
|
+
const [field, order] = sort.split(":");
|
|
187
|
+
parsed.sort = {
|
|
188
|
+
field,
|
|
189
|
+
order: order === "asc" ? "asc" : "desc"
|
|
190
|
+
};
|
|
191
|
+
} else if (typeof sortBy === "string") {
|
|
192
|
+
parsed.sort = {
|
|
193
|
+
field: sortBy,
|
|
194
|
+
order: sortOrder === "asc" ? "asc" : "desc"
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (typeof search === "string") {
|
|
198
|
+
parsed.search = search;
|
|
199
|
+
}
|
|
200
|
+
if (typeof filter === "object" && filter !== null) {
|
|
201
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
202
|
+
if (value !== "all") {
|
|
203
|
+
parsed.filter[key] = value;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
Object.entries(otherParams).forEach(([key, value]) => {
|
|
208
|
+
if (typeof value === "string" && value !== "all" && !["page", "limit", "sort", "sortBy", "sortOrder", "search"].includes(key)) {
|
|
209
|
+
parsed.filter[key] = value;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
req.parsedQuery = parsed;
|
|
213
|
+
next();
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// src/server/middleware/utils/schemaMeta.util.ts
|
|
217
|
+
var getZodTypeName = (schema) => {
|
|
218
|
+
const typeName = schema._def?.typeName;
|
|
219
|
+
switch (typeName) {
|
|
220
|
+
case "ZodString":
|
|
221
|
+
return "string";
|
|
222
|
+
case "ZodNumber":
|
|
223
|
+
return "number";
|
|
224
|
+
case "ZodBoolean":
|
|
225
|
+
return "boolean";
|
|
226
|
+
case "ZodDate":
|
|
227
|
+
return "date";
|
|
228
|
+
case "ZodArray":
|
|
229
|
+
return "array";
|
|
230
|
+
case "ZodObject":
|
|
231
|
+
return "object";
|
|
232
|
+
case "ZodOptional":
|
|
233
|
+
case "ZodNullable":
|
|
234
|
+
return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
|
|
235
|
+
case "ZodDefault":
|
|
236
|
+
return schema._def?.innerType ? getZodTypeName(schema._def.innerType) : "unknown";
|
|
237
|
+
case "ZodEnum":
|
|
238
|
+
return "enum";
|
|
239
|
+
case "ZodUnion":
|
|
240
|
+
return "union";
|
|
241
|
+
default:
|
|
242
|
+
return "unknown";
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
var isZodRequired = (schema) => {
|
|
246
|
+
const typeName = schema._def?.typeName;
|
|
247
|
+
return typeName !== "ZodOptional" && typeName !== "ZodNullable";
|
|
248
|
+
};
|
|
249
|
+
var extractSchemaMeta = (model, zodSchema) => {
|
|
250
|
+
const columns = [];
|
|
251
|
+
if (zodSchema && zodSchema.shape) {
|
|
252
|
+
const shape = zodSchema.shape;
|
|
253
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
254
|
+
if (key.startsWith("_")) continue;
|
|
255
|
+
columns.push({
|
|
256
|
+
name: key,
|
|
257
|
+
datatype: getZodTypeName(value),
|
|
258
|
+
required: isZodRequired(value)
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
return columns;
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const schema = model.schema;
|
|
265
|
+
const paths = schema.paths;
|
|
266
|
+
for (const [key, pathInfo] of Object.entries(paths)) {
|
|
267
|
+
if (key.startsWith("_") || key === "__v") continue;
|
|
268
|
+
const schemaType = pathInfo;
|
|
269
|
+
columns.push({
|
|
270
|
+
name: key,
|
|
271
|
+
datatype: (schemaType.instance || "unknown").toLowerCase(),
|
|
272
|
+
required: schemaType.isRequired || false
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
return columns;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// src/server/middleware/pagination.middleware.ts
|
|
281
|
+
var queryPagination = (model, options = {}, withOrgId = true) => {
|
|
282
|
+
return async (req, res, next) => {
|
|
283
|
+
try {
|
|
284
|
+
const { page, limit, sort, search, filter } = req.parsedQuery;
|
|
285
|
+
const query = {};
|
|
286
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
287
|
+
if (options.regexFilterFields?.includes(key)) {
|
|
288
|
+
query[key] = { $regex: value, $options: "i" };
|
|
289
|
+
} else {
|
|
290
|
+
query[key] = value;
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
const organizationId = req.headers["x-organization-id"];
|
|
294
|
+
if (organizationId && typeof organizationId === "string" && withOrgId) {
|
|
295
|
+
query.organizationId = organizationId;
|
|
296
|
+
}
|
|
297
|
+
if (search && options.searchFields?.length) {
|
|
298
|
+
query.$or = options.searchFields.map((field) => ({
|
|
299
|
+
[field]: { $regex: search, $options: "i" }
|
|
300
|
+
}));
|
|
301
|
+
}
|
|
302
|
+
const sortQuery = sort ? { [sort.field]: sort.order } : { createdAt: "desc" };
|
|
303
|
+
const skip = (page - 1) * limit;
|
|
304
|
+
const [data, total] = await Promise.all([
|
|
305
|
+
model.find(query).sort(sortQuery).skip(skip).limit(limit),
|
|
306
|
+
model.countDocuments(query)
|
|
307
|
+
]);
|
|
308
|
+
res.paginatedResult = {
|
|
309
|
+
data,
|
|
310
|
+
meta: {
|
|
311
|
+
page,
|
|
312
|
+
limit,
|
|
313
|
+
total,
|
|
314
|
+
totalPages: Math.ceil(total / limit)
|
|
315
|
+
},
|
|
316
|
+
columns: extractSchemaMeta(model, options.validatorSchema)
|
|
317
|
+
};
|
|
318
|
+
next();
|
|
319
|
+
} catch (error) {
|
|
320
|
+
next(error);
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
var defaultConfig = {
|
|
325
|
+
level: process.env.LOG_LEVEL || "info",
|
|
326
|
+
logsDir: "logs",
|
|
327
|
+
maxSize: "20m",
|
|
328
|
+
maxFiles: "14d",
|
|
329
|
+
errorMaxFiles: "30d"
|
|
330
|
+
};
|
|
331
|
+
var levels = {
|
|
332
|
+
error: 0,
|
|
333
|
+
warn: 1,
|
|
334
|
+
info: 2,
|
|
335
|
+
http: 3,
|
|
336
|
+
debug: 4
|
|
337
|
+
};
|
|
338
|
+
var colors = {
|
|
339
|
+
error: "red",
|
|
340
|
+
warn: "yellow",
|
|
341
|
+
info: "green",
|
|
342
|
+
http: "magenta",
|
|
343
|
+
debug: "blue"
|
|
344
|
+
};
|
|
345
|
+
winston__default.default.addColors(colors);
|
|
346
|
+
var fileFormat = winston__default.default.format.combine(
|
|
347
|
+
winston__default.default.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
|
348
|
+
winston__default.default.format.errors({ stack: true }),
|
|
349
|
+
winston__default.default.format.splat(),
|
|
350
|
+
winston__default.default.format.json()
|
|
351
|
+
);
|
|
352
|
+
var consoleFormat = winston__default.default.format.combine(
|
|
353
|
+
winston__default.default.format.colorize({ all: true }),
|
|
354
|
+
winston__default.default.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
|
355
|
+
winston__default.default.format.printf((info) => {
|
|
356
|
+
const timestamp = info.timestamp;
|
|
357
|
+
const level = info.level;
|
|
358
|
+
const message = info.message;
|
|
359
|
+
const stack = info.stack;
|
|
360
|
+
return `${timestamp} [${level}]: ${message}${stack ? "\n" + stack : ""}`;
|
|
361
|
+
})
|
|
362
|
+
);
|
|
363
|
+
var createLogger = (config = {}) => {
|
|
364
|
+
const finalConfig = { ...defaultConfig, ...config };
|
|
365
|
+
const transports = [
|
|
366
|
+
// Console transport
|
|
367
|
+
new winston__default.default.transports.Console({
|
|
368
|
+
format: consoleFormat
|
|
369
|
+
}),
|
|
370
|
+
// Combined logs (all levels)
|
|
371
|
+
new DailyRotateFile__default.default({
|
|
372
|
+
filename: path__default.default.join(finalConfig.logsDir, "combined-%DATE%.log"),
|
|
373
|
+
datePattern: "YYYY-MM-DD",
|
|
374
|
+
maxSize: finalConfig.maxSize,
|
|
375
|
+
maxFiles: finalConfig.maxFiles,
|
|
376
|
+
format: fileFormat
|
|
377
|
+
}),
|
|
378
|
+
// Error logs only
|
|
379
|
+
new DailyRotateFile__default.default({
|
|
380
|
+
filename: path__default.default.join(finalConfig.logsDir, "error-%DATE%.log"),
|
|
381
|
+
datePattern: "YYYY-MM-DD",
|
|
382
|
+
level: "error",
|
|
383
|
+
maxSize: finalConfig.maxSize,
|
|
384
|
+
maxFiles: finalConfig.errorMaxFiles,
|
|
385
|
+
format: fileFormat
|
|
386
|
+
})
|
|
387
|
+
];
|
|
388
|
+
return winston__default.default.createLogger({
|
|
389
|
+
level: finalConfig.level,
|
|
390
|
+
levels,
|
|
391
|
+
format: fileFormat,
|
|
392
|
+
transports,
|
|
393
|
+
exitOnError: false
|
|
394
|
+
});
|
|
395
|
+
};
|
|
396
|
+
var logger = createLogger();
|
|
397
|
+
|
|
398
|
+
// src/server/middleware/crud.middleware.ts
|
|
399
|
+
var isZodError = (error) => {
|
|
400
|
+
return error !== null && typeof error === "object" && "errors" in error && Array.isArray(error.errors);
|
|
401
|
+
};
|
|
402
|
+
var getOrgId = (req, orgField = "organizationId") => {
|
|
403
|
+
const orgReq = req;
|
|
404
|
+
return orgReq.organizationId || req.headers["x-organization-id"] || req.query[orgField];
|
|
405
|
+
};
|
|
406
|
+
var buildOrgFilter = (req, config) => {
|
|
407
|
+
const filter = {};
|
|
408
|
+
if (config.withOrganization !== false) {
|
|
409
|
+
const orgId = getOrgId(req, config.orgField);
|
|
410
|
+
if (orgId) {
|
|
411
|
+
filter[config.orgField || "organizationId"] = orgId;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return filter;
|
|
415
|
+
};
|
|
416
|
+
var formatZodError = (error) => {
|
|
417
|
+
return error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
418
|
+
};
|
|
419
|
+
function createCrudControllers(config) {
|
|
420
|
+
const {
|
|
421
|
+
model,
|
|
422
|
+
resourceName,
|
|
423
|
+
createSchema,
|
|
424
|
+
updateSchema,
|
|
425
|
+
searchFields = [],
|
|
426
|
+
regexFilterFields = [],
|
|
427
|
+
withOrganization = true,
|
|
428
|
+
orgField = "organizationId",
|
|
429
|
+
transformCreate,
|
|
430
|
+
transformUpdate,
|
|
431
|
+
afterCreate,
|
|
432
|
+
afterUpdate,
|
|
433
|
+
afterDelete,
|
|
434
|
+
excludeFields = [],
|
|
435
|
+
populateFields = [],
|
|
436
|
+
buildQuery
|
|
437
|
+
} = config;
|
|
438
|
+
const getAll = async (req, res, _next) => {
|
|
439
|
+
try {
|
|
440
|
+
const paginatedRes = res;
|
|
441
|
+
if (paginatedRes.paginatedResult) {
|
|
442
|
+
successResponse(res, paginatedRes.paginatedResult, `${resourceName} list fetched successfully`);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const page = parseInt(req.query.page) || 1;
|
|
446
|
+
const limit = parseInt(req.query.limit) || 10;
|
|
447
|
+
const sortField = req.query.sortBy || "createdAt";
|
|
448
|
+
const sortOrder = req.query.sortOrder || "desc";
|
|
449
|
+
const search = req.query.search;
|
|
450
|
+
let query = {};
|
|
451
|
+
if (withOrganization) {
|
|
452
|
+
const orgId = getOrgId(req, orgField);
|
|
453
|
+
if (orgId) {
|
|
454
|
+
query[orgField] = orgId;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (search && searchFields.length > 0) {
|
|
458
|
+
query.$or = searchFields.map((field) => ({
|
|
459
|
+
[field]: { $regex: search, $options: "i" }
|
|
460
|
+
}));
|
|
461
|
+
}
|
|
462
|
+
const filterableParams = Object.keys(req.query).filter(
|
|
463
|
+
(key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
|
|
464
|
+
);
|
|
465
|
+
filterableParams.forEach((key) => {
|
|
466
|
+
const value = req.query[key];
|
|
467
|
+
if (value !== void 0 && value !== "" && value !== "all") {
|
|
468
|
+
if (regexFilterFields.includes(key)) {
|
|
469
|
+
query[key] = { $regex: value, $options: "i" };
|
|
470
|
+
} else {
|
|
471
|
+
query[key] = value;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
if (buildQuery) {
|
|
476
|
+
query = buildQuery(req, query);
|
|
477
|
+
}
|
|
478
|
+
const sortQuery = { [sortField]: sortOrder };
|
|
479
|
+
const skip = (page - 1) * limit;
|
|
480
|
+
let projection = {};
|
|
481
|
+
if (excludeFields.length > 0) {
|
|
482
|
+
projection = excludeFields.reduce(
|
|
483
|
+
(acc, field) => ({ ...acc, [field]: 0 }),
|
|
484
|
+
{}
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
let dbQuery = model.find(query, projection);
|
|
488
|
+
if (populateFields.length > 0) {
|
|
489
|
+
populateFields.forEach((field) => {
|
|
490
|
+
dbQuery = dbQuery.populate(field);
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
const [data, total] = await Promise.all([
|
|
494
|
+
dbQuery.sort(sortQuery).skip(skip).limit(limit),
|
|
495
|
+
model.countDocuments(query)
|
|
496
|
+
]);
|
|
497
|
+
successResponse(
|
|
498
|
+
res,
|
|
499
|
+
{
|
|
500
|
+
data,
|
|
501
|
+
meta: {
|
|
502
|
+
page,
|
|
503
|
+
limit,
|
|
504
|
+
total,
|
|
505
|
+
totalPages: Math.ceil(total / limit)
|
|
506
|
+
},
|
|
507
|
+
columns: extractSchemaMeta(model, createSchema)
|
|
508
|
+
},
|
|
509
|
+
`${resourceName} list fetched successfully`
|
|
510
|
+
);
|
|
511
|
+
} catch (error) {
|
|
512
|
+
logger.error(`Error in getAll ${resourceName}`, {
|
|
513
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
514
|
+
});
|
|
515
|
+
errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()} list`);
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
const getById = async (req, res, _next) => {
|
|
519
|
+
try {
|
|
520
|
+
const { id } = req.params;
|
|
521
|
+
if (!id || !mongoose.Types.ObjectId.isValid(id)) {
|
|
522
|
+
badRequestResponse(res, "Invalid ID format");
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
const query = {
|
|
526
|
+
_id: new mongoose.Types.ObjectId(id),
|
|
527
|
+
...buildOrgFilter(req, { ...config, withOrganization, orgField })
|
|
528
|
+
};
|
|
529
|
+
let dbQuery = model.findOne(query);
|
|
530
|
+
if (populateFields.length > 0) {
|
|
531
|
+
populateFields.forEach((field) => {
|
|
532
|
+
dbQuery = dbQuery.populate(field);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
const doc = await dbQuery;
|
|
536
|
+
if (!doc) {
|
|
537
|
+
notFoundResponse(res, `${resourceName} not found`);
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
successResponse(res, doc, `${resourceName} fetched successfully`);
|
|
541
|
+
} catch (error) {
|
|
542
|
+
logger.error(`Error in getById ${resourceName}`, {
|
|
543
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
544
|
+
id: req.params.id
|
|
545
|
+
});
|
|
546
|
+
errorResponse(res, `Failed to fetch ${resourceName.toLowerCase()}`);
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
const create = async (req, res, _next) => {
|
|
550
|
+
try {
|
|
551
|
+
let input = req.body;
|
|
552
|
+
if (createSchema) {
|
|
553
|
+
try {
|
|
554
|
+
input = createSchema.parse(input);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
if (isZodError(error)) {
|
|
557
|
+
badRequestResponse(res, formatZodError(error));
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
throw error;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (transformCreate) {
|
|
564
|
+
input = transformCreate(input, req);
|
|
565
|
+
}
|
|
566
|
+
if (withOrganization) {
|
|
567
|
+
const orgId = getOrgId(req, orgField);
|
|
568
|
+
if (orgId) {
|
|
569
|
+
input[orgField] = orgId;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
const doc = new model(input);
|
|
573
|
+
await doc.save();
|
|
574
|
+
if (afterCreate) {
|
|
575
|
+
await afterCreate(doc, req);
|
|
576
|
+
}
|
|
577
|
+
logger.info(`${resourceName} created successfully`, {
|
|
578
|
+
id: doc._id,
|
|
579
|
+
[orgField]: input[orgField]
|
|
580
|
+
});
|
|
581
|
+
createdResponse(res, doc, `${resourceName} created successfully`);
|
|
582
|
+
} catch (error) {
|
|
583
|
+
logger.error(`Error in create ${resourceName}`, {
|
|
584
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
585
|
+
});
|
|
586
|
+
if (error.code === 11e3) {
|
|
587
|
+
badRequestResponse(res, `A ${resourceName.toLowerCase()} with this data already exists`);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
errorResponse(res, `Failed to create ${resourceName.toLowerCase()}`);
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
const update = async (req, res, _next) => {
|
|
594
|
+
try {
|
|
595
|
+
const { id } = req.params;
|
|
596
|
+
if (!id || !mongoose.Types.ObjectId.isValid(id)) {
|
|
597
|
+
badRequestResponse(res, "Invalid ID format");
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
let input = req.body;
|
|
601
|
+
if (updateSchema) {
|
|
602
|
+
try {
|
|
603
|
+
input = updateSchema.parse(input);
|
|
604
|
+
} catch (error) {
|
|
605
|
+
if (isZodError(error)) {
|
|
606
|
+
badRequestResponse(res, formatZodError(error));
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
throw error;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (transformUpdate) {
|
|
613
|
+
input = transformUpdate(input, req);
|
|
614
|
+
}
|
|
615
|
+
const query = {
|
|
616
|
+
_id: new mongoose.Types.ObjectId(id),
|
|
617
|
+
...buildOrgFilter(req, { ...config, withOrganization, orgField })
|
|
618
|
+
};
|
|
619
|
+
const doc = await model.findOneAndUpdate(query, { $set: input }, { new: true });
|
|
620
|
+
if (!doc) {
|
|
621
|
+
notFoundResponse(res, `${resourceName} not found`);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (afterUpdate) {
|
|
625
|
+
await afterUpdate(doc, req);
|
|
626
|
+
}
|
|
627
|
+
logger.info(`${resourceName} updated successfully`, { id });
|
|
628
|
+
successResponse(res, doc, `${resourceName} updated successfully`);
|
|
629
|
+
} catch (error) {
|
|
630
|
+
logger.error(`Error in update ${resourceName}`, {
|
|
631
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
632
|
+
id: req.params.id
|
|
633
|
+
});
|
|
634
|
+
errorResponse(res, `Failed to update ${resourceName.toLowerCase()}`);
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
const deleteOne = async (req, res, _next) => {
|
|
638
|
+
try {
|
|
639
|
+
const { id } = req.params;
|
|
640
|
+
if (!id || !mongoose.Types.ObjectId.isValid(id)) {
|
|
641
|
+
badRequestResponse(res, "Invalid ID format");
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const query = {
|
|
645
|
+
_id: new mongoose.Types.ObjectId(id),
|
|
646
|
+
...buildOrgFilter(req, { ...config, withOrganization, orgField })
|
|
647
|
+
};
|
|
648
|
+
const result = await model.deleteOne(query);
|
|
649
|
+
if (result.deletedCount === 0) {
|
|
650
|
+
notFoundResponse(res, `${resourceName} not found`);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (afterDelete) {
|
|
654
|
+
await afterDelete(id, req);
|
|
655
|
+
}
|
|
656
|
+
logger.info(`${resourceName} deleted successfully`, { id });
|
|
657
|
+
noContentResponse(res, null, `${resourceName} deleted successfully`);
|
|
658
|
+
} catch (error) {
|
|
659
|
+
logger.error(`Error in delete ${resourceName}`, {
|
|
660
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
661
|
+
id: req.params.id
|
|
662
|
+
});
|
|
663
|
+
errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}`);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
const bulkDelete = async (req, res, _next) => {
|
|
667
|
+
try {
|
|
668
|
+
const bulkReq = req;
|
|
669
|
+
const { deleteIds = [], deleteAll = false } = bulkReq;
|
|
670
|
+
const baseFilter = buildOrgFilter(req, { ...config, withOrganization, orgField });
|
|
671
|
+
let filter;
|
|
672
|
+
if (deleteAll) {
|
|
673
|
+
filter = baseFilter;
|
|
674
|
+
} else if (deleteIds.length > 0) {
|
|
675
|
+
filter = {
|
|
676
|
+
...baseFilter,
|
|
677
|
+
_id: { $in: deleteIds.map((id) => new mongoose.Types.ObjectId(id)) }
|
|
678
|
+
};
|
|
679
|
+
} else {
|
|
680
|
+
badRequestResponse(res, "No IDs provided for deletion");
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const result = await model.deleteMany(filter);
|
|
684
|
+
if (afterDelete && deleteIds.length > 0) {
|
|
685
|
+
await Promise.all(deleteIds.map((id) => afterDelete(id, req)));
|
|
686
|
+
}
|
|
687
|
+
logger.info(`${resourceName}(s) bulk deleted successfully`, {
|
|
688
|
+
deletedCount: result.deletedCount,
|
|
689
|
+
deleteAll
|
|
690
|
+
});
|
|
691
|
+
successResponse(
|
|
692
|
+
res,
|
|
693
|
+
{ deletedCount: result.deletedCount },
|
|
694
|
+
`${result.deletedCount} ${resourceName.toLowerCase()}(s) deleted successfully`
|
|
695
|
+
);
|
|
696
|
+
} catch (error) {
|
|
697
|
+
logger.error(`Error in bulkDelete ${resourceName}`, {
|
|
698
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
699
|
+
});
|
|
700
|
+
errorResponse(res, `Failed to delete ${resourceName.toLowerCase()}(s)`);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
return {
|
|
704
|
+
getAll,
|
|
705
|
+
getById,
|
|
706
|
+
create,
|
|
707
|
+
update,
|
|
708
|
+
deleteOne,
|
|
709
|
+
bulkDelete
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
function createPaginationMiddleware(model, config = {}) {
|
|
713
|
+
const {
|
|
714
|
+
searchFields = [],
|
|
715
|
+
regexFilterFields = [],
|
|
716
|
+
withOrganization = true,
|
|
717
|
+
orgField = "organizationId"
|
|
718
|
+
} = config;
|
|
719
|
+
return async (req, res, next) => {
|
|
720
|
+
try {
|
|
721
|
+
const page = parseInt(req.query.page) || 1;
|
|
722
|
+
const limit = parseInt(req.query.limit) || 10;
|
|
723
|
+
const sortField = req.query.sortBy || "createdAt";
|
|
724
|
+
const sortOrder = req.query.sortOrder || "desc";
|
|
725
|
+
const search = req.query.search;
|
|
726
|
+
const query = {};
|
|
727
|
+
if (withOrganization) {
|
|
728
|
+
const orgId = getOrgId(req, orgField);
|
|
729
|
+
if (orgId) {
|
|
730
|
+
query[orgField] = orgId;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
if (search && searchFields.length > 0) {
|
|
734
|
+
query.$or = searchFields.map((field) => ({
|
|
735
|
+
[field]: { $regex: search, $options: "i" }
|
|
736
|
+
}));
|
|
737
|
+
}
|
|
738
|
+
const filterableParams = Object.keys(req.query).filter(
|
|
739
|
+
(key) => !["page", "limit", "sortBy", "sortOrder", "search"].includes(key)
|
|
740
|
+
);
|
|
741
|
+
filterableParams.forEach((key) => {
|
|
742
|
+
const value = req.query[key];
|
|
743
|
+
if (value !== void 0 && value !== "" && value !== "all") {
|
|
744
|
+
if (regexFilterFields.includes(key)) {
|
|
745
|
+
query[key] = { $regex: value, $options: "i" };
|
|
746
|
+
} else {
|
|
747
|
+
query[key] = value;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
const sortQuery = { [sortField]: sortOrder };
|
|
752
|
+
const skip = (page - 1) * limit;
|
|
753
|
+
const [data, total] = await Promise.all([
|
|
754
|
+
model.find(query).sort(sortQuery).skip(skip).limit(limit),
|
|
755
|
+
model.countDocuments(query)
|
|
756
|
+
]);
|
|
757
|
+
const paginatedRes = res;
|
|
758
|
+
paginatedRes.paginatedResult = {
|
|
759
|
+
data,
|
|
760
|
+
meta: {
|
|
761
|
+
page,
|
|
762
|
+
limit,
|
|
763
|
+
total,
|
|
764
|
+
totalPages: Math.ceil(total / limit)
|
|
765
|
+
},
|
|
766
|
+
columns: extractSchemaMeta(model, config.createSchema)
|
|
767
|
+
};
|
|
768
|
+
next();
|
|
769
|
+
} catch (error) {
|
|
770
|
+
next(error);
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
var parseBulkDelete = (req, res, next) => {
|
|
775
|
+
try {
|
|
776
|
+
const bulkReq = req;
|
|
777
|
+
let ids = [];
|
|
778
|
+
if (Array.isArray(req.body)) {
|
|
779
|
+
ids = req.body;
|
|
780
|
+
} else if (req.body && Array.isArray(req.body.ids)) {
|
|
781
|
+
ids = req.body.ids;
|
|
782
|
+
} else if (req.body && typeof req.body === "object") {
|
|
783
|
+
if (Array.isArray(req.body.data)) {
|
|
784
|
+
ids = req.body.data;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
if (ids.length === 0) {
|
|
788
|
+
return badRequestResponse(
|
|
789
|
+
res,
|
|
790
|
+
'Request body must contain an array of IDs. Use ["*"] to delete all records or ["id1", "id2"] to delete specific records.'
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
if (ids.length === 1 && ids[0] === "*") {
|
|
794
|
+
bulkReq.deleteAll = true;
|
|
795
|
+
bulkReq.deleteIds = [];
|
|
796
|
+
logger.info("Bulk delete: Deleting all records");
|
|
797
|
+
return next();
|
|
798
|
+
}
|
|
799
|
+
const validIds = [];
|
|
800
|
+
const invalidIds = [];
|
|
801
|
+
for (const id of ids) {
|
|
802
|
+
if (typeof id === "string" && mongoose.Types.ObjectId.isValid(id)) {
|
|
803
|
+
validIds.push(id);
|
|
804
|
+
} else {
|
|
805
|
+
invalidIds.push(id);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
if (invalidIds.length > 0) {
|
|
809
|
+
return badRequestResponse(
|
|
810
|
+
res,
|
|
811
|
+
`Invalid ID format(s): ${invalidIds.slice(0, 5).join(", ")}${invalidIds.length > 5 ? "..." : ""}. All IDs must be valid MongoDB ObjectIds.`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
if (validIds.length === 0) {
|
|
815
|
+
return badRequestResponse(res, "No valid IDs provided for deletion.");
|
|
816
|
+
}
|
|
817
|
+
bulkReq.deleteAll = false;
|
|
818
|
+
bulkReq.deleteIds = validIds;
|
|
819
|
+
logger.info(`Bulk delete: Deleting ${validIds.length} record(s)`);
|
|
820
|
+
next();
|
|
821
|
+
} catch (error) {
|
|
822
|
+
logger.error("Error in parseBulkDelete middleware", error);
|
|
823
|
+
return badRequestResponse(res, "Failed to parse delete request");
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
var buildDeleteFilter = (req, organizationId) => {
|
|
827
|
+
const filter = {
|
|
828
|
+
organizationId: new mongoose.Types.ObjectId(organizationId)
|
|
829
|
+
};
|
|
830
|
+
if (!req.deleteAll && req.deleteIds && req.deleteIds.length > 0) {
|
|
831
|
+
filter._id = {
|
|
832
|
+
$in: req.deleteIds.map((id) => new mongoose.Types.ObjectId(id))
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
return filter;
|
|
836
|
+
};
|
|
837
|
+
var createBulkDeleteHandler = (Model2, modelName) => {
|
|
838
|
+
return async (req, res) => {
|
|
839
|
+
const bulkReq = req;
|
|
840
|
+
const organizationId = req.headers["x-organization-id"];
|
|
841
|
+
if (!organizationId) {
|
|
842
|
+
return badRequestResponse(res, "Organization ID is required");
|
|
843
|
+
}
|
|
844
|
+
try {
|
|
845
|
+
const filter = buildDeleteFilter(bulkReq, organizationId);
|
|
846
|
+
const result = await Model2.deleteMany(filter);
|
|
847
|
+
const deletedCount = result.deletedCount || 0;
|
|
848
|
+
logger.info(`Bulk delete completed: ${deletedCount} ${modelName}(s) deleted`, {
|
|
849
|
+
organizationId,
|
|
850
|
+
deleteAll: bulkReq.deleteAll,
|
|
851
|
+
requestedIds: bulkReq.deleteIds?.length || "all",
|
|
852
|
+
deletedCount
|
|
853
|
+
});
|
|
854
|
+
return res.status(200).json({
|
|
855
|
+
message: `Successfully deleted ${deletedCount} ${modelName}(s)`,
|
|
856
|
+
data: {
|
|
857
|
+
deletedCount,
|
|
858
|
+
deleteAll: bulkReq.deleteAll
|
|
859
|
+
},
|
|
860
|
+
status: "success",
|
|
861
|
+
statusCode: 200
|
|
862
|
+
});
|
|
863
|
+
} catch (error) {
|
|
864
|
+
logger.error(`Error in bulk delete ${modelName}`, error);
|
|
865
|
+
return res.status(500).json({
|
|
866
|
+
message: `Failed to delete ${modelName}(s)`,
|
|
867
|
+
data: null,
|
|
868
|
+
status: "error",
|
|
869
|
+
statusCode: 500
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
};
|
|
874
|
+
|
|
122
875
|
exports.authenticateApiKey = authenticateApiKey;
|
|
123
876
|
exports.authenticateJWT = authenticateJWT;
|
|
877
|
+
exports.buildDeleteFilter = buildDeleteFilter;
|
|
878
|
+
exports.createBulkDeleteHandler = createBulkDeleteHandler;
|
|
879
|
+
exports.createCrudControllers = createCrudControllers;
|
|
880
|
+
exports.createPaginationMiddleware = createPaginationMiddleware;
|
|
124
881
|
exports.extractOrganization = extractOrganization;
|
|
882
|
+
exports.extractSchemaMeta = extractSchemaMeta;
|
|
125
883
|
exports.optionalAuthenticateJWT = optionalAuthenticateJWT;
|
|
884
|
+
exports.parseBulkDelete = parseBulkDelete;
|
|
885
|
+
exports.queryPagination = queryPagination;
|
|
886
|
+
exports.queryParser = queryParser;
|
|
126
887
|
exports.requireOrganization = requireOrganization;
|
|
127
888
|
//# sourceMappingURL=index.js.map
|
|
128
889
|
//# sourceMappingURL=index.js.map
|