@maysun/common 3.0.0 → 3.0.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/build/auth/src/config/main.config.d.ts +4 -0
- package/build/auth/src/config/main.config.js +7 -0
- package/build/auth/src/types/interfaces.d.ts +16 -0
- package/build/auth/src/types/interfaces.js +2 -0
- package/build/common/src/errors/bad-request-error.d.ts +10 -0
- package/build/common/src/errors/bad-request-error.js +17 -0
- package/build/common/src/errors/custom-error.d.ts +10 -0
- package/build/common/src/errors/custom-error.js +10 -0
- package/build/common/src/errors/database-connection-error.d.ts +8 -0
- package/build/common/src/errors/database-connection-error.js +15 -0
- package/build/common/src/errors/graphql/graphql-error-handler.d.ts +1 -0
- package/build/common/src/errors/graphql/graphql-error-handler.js +12 -0
- package/build/common/src/errors/graphql/validationError.d.ts +2 -0
- package/build/common/src/errors/graphql/validationError.js +17 -0
- package/build/common/src/errors/invalid-credentials-error.d.ts +9 -0
- package/build/common/src/errors/invalid-credentials-error.js +16 -0
- package/build/common/src/errors/not-found-error.d.ts +9 -0
- package/build/common/src/errors/not-found-error.js +16 -0
- package/build/common/src/errors/request-validation-error.d.ts +12 -0
- package/build/common/src/errors/request-validation-error.js +24 -0
- package/build/common/src/index.d.ts +8 -0
- package/build/common/src/index.js +24 -0
- package/build/common/src/middleware/current-user.d.ts +10 -0
- package/build/common/src/middleware/current-user.js +22 -0
- package/build/common/src/middleware/error-handler.d.ts +2 -0
- package/build/common/src/middleware/error-handler.js +15 -0
- package/build/common/src/middleware/rateLimit.d.ts +2 -0
- package/build/common/src/middleware/rateLimit.js +12 -0
- package/build/common/src/middleware/validate-request.d.ts +3 -0
- package/build/common/src/middleware/validate-request.js +13 -0
- package/build/common/src/middleware/validation.d.ts +12 -0
- package/build/common/src/middleware/validation.js +22 -0
- package/build/common/src/middleware/xssSanitize.d.ts +2 -0
- package/build/common/src/middleware/xssSanitize.js +32 -0
- package/package.json +26 -4
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OTP_COOLDOWN = exports.SMS_COOLDOWN = exports.WINDOW_MS = exports.RATE_LIMIT = void 0;
|
|
4
|
+
exports.RATE_LIMIT = 100;
|
|
5
|
+
exports.WINDOW_MS = 10;
|
|
6
|
+
exports.SMS_COOLDOWN = 2 * 60 * 1000;
|
|
7
|
+
exports.OTP_COOLDOWN = 10 * 60 * 1000;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SignupInput {
|
|
2
|
+
phoneNumber: string;
|
|
3
|
+
domain: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SignupInputWrapper {
|
|
6
|
+
input: SignupInput;
|
|
7
|
+
}
|
|
8
|
+
export interface User {
|
|
9
|
+
id: string;
|
|
10
|
+
phoneNumber: string;
|
|
11
|
+
domain: string;
|
|
12
|
+
}
|
|
13
|
+
export interface IContext {
|
|
14
|
+
domain: string;
|
|
15
|
+
currentUser: User | null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BadRequestError = void 0;
|
|
4
|
+
const custom_error_1 = require("./custom-error");
|
|
5
|
+
class BadRequestError extends custom_error_1.CustomError {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.message = message;
|
|
9
|
+
this.status = 'fail';
|
|
10
|
+
this.statusCode = 400;
|
|
11
|
+
Object.setPrototypeOf(this, BadRequestError.prototype);
|
|
12
|
+
}
|
|
13
|
+
serializeErrors() {
|
|
14
|
+
return [{ message: this.message }];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.BadRequestError = BadRequestError;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CustomError = void 0;
|
|
4
|
+
class CustomError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
Object.setPrototypeOf(this, CustomError.prototype);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.CustomError = CustomError;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DatabaseConnectionError = void 0;
|
|
4
|
+
class DatabaseConnectionError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
this.statusCode = 500;
|
|
8
|
+
this.reason = 'Error connecting to database';
|
|
9
|
+
Object.setPrototypeOf(this, DatabaseConnectionError.prototype);
|
|
10
|
+
}
|
|
11
|
+
serializeErrors() {
|
|
12
|
+
return [{ message: this.reason }];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.DatabaseConnectionError = DatabaseConnectionError;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatGraphQLError(err: unknown): never;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatGraphQLError = formatGraphQLError;
|
|
4
|
+
// errors/graphqlErrorHandler.ts
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const validationError_1 = require("./validationError");
|
|
7
|
+
function formatGraphQLError(err) {
|
|
8
|
+
if (err instanceof zod_1.ZodError)
|
|
9
|
+
return (0, validationError_1.handleValidationError)(err);
|
|
10
|
+
// اینجا بعداً میتونی بقیه خطاها رو هم هندل کنی
|
|
11
|
+
throw err;
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleValidationError = handleValidationError;
|
|
4
|
+
// errors/validationError.ts
|
|
5
|
+
const graphql_1 = require("graphql");
|
|
6
|
+
function handleValidationError(err) {
|
|
7
|
+
const validationErrors = err.issues.map((issue) => ({
|
|
8
|
+
field: issue.path.join('.'),
|
|
9
|
+
message: issue.message,
|
|
10
|
+
}));
|
|
11
|
+
throw new graphql_1.GraphQLError('Validation failed', {
|
|
12
|
+
extensions: {
|
|
13
|
+
code: 'BAD_USER_INPUT',
|
|
14
|
+
validationErrors,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidCredentialsError = void 0;
|
|
4
|
+
const custom_error_1 = require("./custom-error");
|
|
5
|
+
class InvalidCredentialsError extends custom_error_1.CustomError {
|
|
6
|
+
constructor() {
|
|
7
|
+
super('Route not found');
|
|
8
|
+
this.status = 'fail';
|
|
9
|
+
this.statusCode = 401;
|
|
10
|
+
Object.setPrototypeOf(this, InvalidCredentialsError.prototype);
|
|
11
|
+
}
|
|
12
|
+
serializeErrors() {
|
|
13
|
+
return [{ message: 'Invalid credentials' }];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.InvalidCredentialsError = InvalidCredentialsError;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotFoundError = void 0;
|
|
4
|
+
const custom_error_1 = require("./custom-error");
|
|
5
|
+
class NotFoundError extends custom_error_1.CustomError {
|
|
6
|
+
constructor() {
|
|
7
|
+
super('Route not found');
|
|
8
|
+
this.status = 'fail';
|
|
9
|
+
this.statusCode = 404;
|
|
10
|
+
Object.setPrototypeOf(this, NotFoundError.prototype);
|
|
11
|
+
}
|
|
12
|
+
serializeErrors() {
|
|
13
|
+
return [{ message: 'Not found!' }];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.NotFoundError = NotFoundError;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ZodError } from 'zod';
|
|
2
|
+
import { CustomError } from './custom-error';
|
|
3
|
+
export declare class RequestValidationError extends CustomError {
|
|
4
|
+
error: ZodError;
|
|
5
|
+
status: "fail";
|
|
6
|
+
statusCode: number;
|
|
7
|
+
constructor(error: ZodError);
|
|
8
|
+
serializeErrors(): {
|
|
9
|
+
message: string;
|
|
10
|
+
field: string;
|
|
11
|
+
}[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequestValidationError = void 0;
|
|
4
|
+
const custom_error_1 = require("./custom-error");
|
|
5
|
+
class RequestValidationError extends custom_error_1.CustomError {
|
|
6
|
+
constructor(error) {
|
|
7
|
+
super('Invalid Request parameters');
|
|
8
|
+
this.error = error;
|
|
9
|
+
this.status = 'fail';
|
|
10
|
+
this.statusCode = 404;
|
|
11
|
+
Object.setPrototypeOf(this, RequestValidationError.prototype);
|
|
12
|
+
}
|
|
13
|
+
serializeErrors() {
|
|
14
|
+
return this.error.issues.map((err) => {
|
|
15
|
+
var _a;
|
|
16
|
+
return {
|
|
17
|
+
message: err.message,
|
|
18
|
+
field: (_a = err.path[0]) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
// return [{ message: 'Not found!' }];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.RequestValidationError = RequestValidationError;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./errors/bad-request-error";
|
|
2
|
+
export * from "./errors/custom-error";
|
|
3
|
+
export * from "./errors/database-connection-error";
|
|
4
|
+
export * from "./errors/invalid-credentials-error";
|
|
5
|
+
export * from "./errors/not-found-error";
|
|
6
|
+
export * from "./errors/request-validation-error";
|
|
7
|
+
export * from "./errors/graphql/graphql-error-handler";
|
|
8
|
+
export * from "./errors/graphql/validationError";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./errors/bad-request-error"), exports);
|
|
18
|
+
__exportStar(require("./errors/custom-error"), exports);
|
|
19
|
+
__exportStar(require("./errors/database-connection-error"), exports);
|
|
20
|
+
__exportStar(require("./errors/invalid-credentials-error"), exports);
|
|
21
|
+
__exportStar(require("./errors/not-found-error"), exports);
|
|
22
|
+
__exportStar(require("./errors/request-validation-error"), exports);
|
|
23
|
+
__exportStar(require("./errors/graphql/graphql-error-handler"), exports);
|
|
24
|
+
__exportStar(require("./errors/graphql/validationError"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { User } from "../../../auth/src/types/interfaces";
|
|
2
|
+
import { Request, Response, NextFunction } from "express";
|
|
3
|
+
declare global {
|
|
4
|
+
namespace Express {
|
|
5
|
+
interface Request {
|
|
6
|
+
currentUser?: User;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare const currentUser: (req: Request, res: Response, next: NextFunction) => void;
|
|
@@ -0,0 +1,22 @@
|
|
|
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.currentUser = void 0;
|
|
7
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
const currentUser = (req, res, next) => {
|
|
9
|
+
var _a;
|
|
10
|
+
if (!((_a = req.session) === null || _a === void 0 ? void 0 : _a.jwt)) {
|
|
11
|
+
return next();
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const payload = jsonwebtoken_1.default.verify(req.session.jwt, process.env.JWT_KEY);
|
|
15
|
+
req.currentUser = payload;
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
console.log(err);
|
|
19
|
+
}
|
|
20
|
+
next();
|
|
21
|
+
};
|
|
22
|
+
exports.currentUser = currentUser;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.errorHandler = void 0;
|
|
4
|
+
const custom_error_1 = require("../errors/custom-error");
|
|
5
|
+
const errorHandler = (err, req, res, next) => {
|
|
6
|
+
if (err instanceof custom_error_1.CustomError) {
|
|
7
|
+
return res.status(err.statusCode).send({
|
|
8
|
+
status: err.status,
|
|
9
|
+
data: {
|
|
10
|
+
errors: err.serializeErrors(),
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
exports.errorHandler = errorHandler;
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
const main_config_1 = require("../../../auth/src/config/main.config");
|
|
7
|
+
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
8
|
+
exports.default = (0, express_rate_limit_1.default)({
|
|
9
|
+
max: main_config_1.RATE_LIMIT,
|
|
10
|
+
windowMs: main_config_1.WINDOW_MS * 60 * 1000,
|
|
11
|
+
message: `Too many request per ip, in ${main_config_1.WINDOW_MS} minutes!`,
|
|
12
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateRequest = void 0;
|
|
4
|
+
const request_validation_error_1 = require("../errors/request-validation-error");
|
|
5
|
+
require("express-async-errors");
|
|
6
|
+
const validation_1 = require("./validation");
|
|
7
|
+
const validateRequest = (req, res, next) => {
|
|
8
|
+
const result = validation_1.signinSchema.safeParse(req.body);
|
|
9
|
+
if (!result.success)
|
|
10
|
+
throw new request_validation_error_1.RequestValidationError(result.error);
|
|
11
|
+
next();
|
|
12
|
+
};
|
|
13
|
+
exports.validateRequest = validateRequest;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const signupSchema: z.ZodObject<{
|
|
3
|
+
domain: z.ZodString;
|
|
4
|
+
phoneNumber: z.ZodString;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export declare const signinSchema: z.ZodObject<{
|
|
7
|
+
domain: z.ZodString;
|
|
8
|
+
phoneNumber: z.ZodString;
|
|
9
|
+
otp: z.ZodString;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type SignupInput = z.infer<typeof signupSchema>;
|
|
12
|
+
export type SigninInput = z.infer<typeof signinSchema>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.signinSchema = exports.signupSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const phoneNumberSchema = zod_1.z
|
|
6
|
+
.string()
|
|
7
|
+
.length(11, 'Phone number must be 11 digits long')
|
|
8
|
+
.regex(/^09\d{9}$/, 'The phone number must start with 09');
|
|
9
|
+
const domainSchema = zod_1.z
|
|
10
|
+
.string()
|
|
11
|
+
.trim()
|
|
12
|
+
.max(50, 'Domain too long')
|
|
13
|
+
.regex(/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i, 'Domain is not valid (e.g., octolab.ir)');
|
|
14
|
+
exports.signupSchema = zod_1.z.object({
|
|
15
|
+
domain: domainSchema,
|
|
16
|
+
phoneNumber: phoneNumberSchema,
|
|
17
|
+
});
|
|
18
|
+
exports.signinSchema = zod_1.z.object({
|
|
19
|
+
domain: domainSchema,
|
|
20
|
+
phoneNumber: phoneNumberSchema,
|
|
21
|
+
otp: zod_1.z.string().trim().min(4, 'OTP must be at least 4 chars').max(100, 'OTP too long'),
|
|
22
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
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.xssSanitizeMiddleware = xssSanitizeMiddleware;
|
|
7
|
+
const xss_1 = __importDefault(require("xss"));
|
|
8
|
+
function sanitizeObject(obj) {
|
|
9
|
+
if (typeof obj !== 'object' || obj === null)
|
|
10
|
+
return obj;
|
|
11
|
+
if (Array.isArray(obj)) {
|
|
12
|
+
return obj.map((item) => sanitizeObject(item));
|
|
13
|
+
}
|
|
14
|
+
for (const key in obj) {
|
|
15
|
+
if (typeof obj[key] === 'string') {
|
|
16
|
+
obj[key] = (0, xss_1.default)(obj[key]);
|
|
17
|
+
}
|
|
18
|
+
else if (typeof obj[key] === 'object') {
|
|
19
|
+
obj[key] = sanitizeObject(obj[key]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return obj;
|
|
23
|
+
}
|
|
24
|
+
function xssSanitizeMiddleware(req, res, next) {
|
|
25
|
+
if (req.body)
|
|
26
|
+
req.body = sanitizeObject(req.body);
|
|
27
|
+
if (req.params)
|
|
28
|
+
req.params = sanitizeObject(req.params);
|
|
29
|
+
if (req.query)
|
|
30
|
+
req.query = sanitizeObject(req.query);
|
|
31
|
+
next();
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maysun/common",
|
|
3
|
-
"version": "3.0.
|
|
4
|
-
"main": "index.js",
|
|
3
|
+
"version": "3.0.3",
|
|
4
|
+
"main": "./build/index.js",
|
|
5
|
+
"types": "./build/index.t.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"build/**/*"
|
|
8
|
+
],
|
|
5
9
|
"scripts": {
|
|
6
|
-
"
|
|
10
|
+
"clean": "del /q build",
|
|
11
|
+
"build": "npm run clean && tsc",
|
|
12
|
+
"pub": "git add . && git commit -m \"Updates\" && npm version patch && npm run build && npm publish"
|
|
7
13
|
},
|
|
8
14
|
"keywords": [],
|
|
9
15
|
"author": "",
|
|
10
16
|
"license": "ISC",
|
|
11
|
-
"description": ""
|
|
17
|
+
"description": "",
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/cookie-session": "^2.0.49",
|
|
20
|
+
"@types/express": "^4.17.23",
|
|
21
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
22
|
+
"del-cli": "^6.0.0",
|
|
23
|
+
"typescript": "^5.9.2"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"cookie-session": "^2.1.1",
|
|
27
|
+
"express": "^4.21.2",
|
|
28
|
+
"express-rate-limit": "^8.0.1",
|
|
29
|
+
"graphql": "^16.11.0",
|
|
30
|
+
"jsonwebtoken": "^9.0.2",
|
|
31
|
+
"xss": "^1.0.15",
|
|
32
|
+
"zod": "^4.1.5"
|
|
33
|
+
}
|
|
12
34
|
}
|