Mejora de las orders y actualizacion docs
This commit is contained in:
8
.env
8
.env
@@ -5,8 +5,8 @@ RABBITMQ_PASSWORD=guest
|
||||
|
||||
ENVIORMENT=development
|
||||
|
||||
RABBITMQ_HOST=rabbitmq-sim-broker
|
||||
# RABBITMQ_HOST=localhost
|
||||
#RABBITMQ_HOST=rabbitmq-sim-broker
|
||||
RABBITMQ_HOST=localhost
|
||||
RABBITMQ_PORT=5672
|
||||
RABBITMQ_USER=guest
|
||||
RABBITMQ_PASSWORD=guest
|
||||
@@ -14,8 +14,8 @@ RABBITMQ_SECURE=false
|
||||
RABBITMQ_VHOST=sim-vhost
|
||||
|
||||
# Hay cosas que unificar de varios servicios
|
||||
POSTGRES_HOST=postgresql-sim
|
||||
# POSTGRES_HOST=localhost
|
||||
#POSTGRES_HOST=postgresql-sim
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_DATABASE=postgres
|
||||
POSTGRES_PORT=5433
|
||||
|
||||
@@ -11,7 +11,7 @@ post {
|
||||
}
|
||||
|
||||
body:form-urlencoded {
|
||||
iccid: 8933201125065160331
|
||||
iccid: 8933201125068886692
|
||||
offer: SAVEFAMILY1
|
||||
}
|
||||
|
||||
|
||||
@@ -18,3 +18,38 @@ settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
docs {
|
||||
El endpoint recibe como body
|
||||
```
|
||||
{
|
||||
iccid: string,
|
||||
update_webhook?: string
|
||||
}
|
||||
```
|
||||
|
||||
`update_webhook` está en desarrollo, pero será donde se mande la actualizacion de la cancelación cuando haya una respuesta de la API externa.
|
||||
|
||||
Si la llamada tiene exito devuelve:
|
||||
``` json
|
||||
{
|
||||
data: {
|
||||
iccid: string,
|
||||
message_id: string,
|
||||
operation: "cancelation"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
message_id se usará para la llamada /orders/message_id/}{message_id}
|
||||
|
||||
Si la llamada falla devolvera:
|
||||
```json
|
||||
{
|
||||
errors: {
|
||||
msg: string
|
||||
... (campos extra de gestion del error)
|
||||
}
|
||||
}
|
||||
```
|
||||
}
|
||||
|
||||
34
docs/sim-api/collection.bru
Normal file
34
docs/sim-api/collection.bru
Normal file
@@ -0,0 +1,34 @@
|
||||
docs {
|
||||
Los endpoint tienen unos campos comunes de entrada:
|
||||
```ts
|
||||
{
|
||||
iccid: string,
|
||||
update_webhook?: string
|
||||
}
|
||||
```
|
||||
|
||||
`update_webhook` está en desarrollo, pero será donde se mande la actualizacion de la cancelación cuando haya una respuesta de la API externa.
|
||||
|
||||
Si la llamada tiene exito devuelve:
|
||||
```ts
|
||||
{
|
||||
data: {
|
||||
iccid: string,
|
||||
message_id: string,
|
||||
operation: string,
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
message_id se usará para la llamada /orders/message_id/}{message_id}
|
||||
|
||||
Si la llamada falla devolvera:
|
||||
```ts
|
||||
{
|
||||
errors: {
|
||||
msg: string
|
||||
... (campos extra de gestion del error)
|
||||
}
|
||||
}
|
||||
```
|
||||
}
|
||||
@@ -3,20 +3,3 @@ RABBITMQ_USER=guest
|
||||
RABBITMQ_PASSWORD=guest
|
||||
|
||||
ENVIORMENT=development
|
||||
|
||||
RABBITMQ_HOST=rabbitmq-sim-broker
|
||||
#RABBITMQ_HOST=localhost
|
||||
RABBITMQ_PORT=5672
|
||||
RABBITMQ_USER=guest
|
||||
RABBITMQ_PASSWORD=guest
|
||||
RABBITMQ_SECURE=false
|
||||
RABBITMQ_VHOST=sim-vhost
|
||||
|
||||
# Hay cosas que unificar de varios servicios
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_DATABASE=postres
|
||||
POSTGRES_HOST=postgresql-sim-1
|
||||
POSTGRES_PORT=5432
|
||||
DEV_POSTGRES_PORT=5432
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=1234
|
||||
|
||||
@@ -3,6 +3,7 @@ import { SimUsecases } from "./Sim.usecases.js"
|
||||
import { activationValidator, iccidValidator } from "./httpValidators.js"
|
||||
import { companyFromIccid } from "#domain/companies.js"
|
||||
import { BodyValidator } from "sim-shared/aplication/BodyValidator.js"
|
||||
import { tryCatch } from "packages/sim-shared/domain/Result.js"
|
||||
|
||||
|
||||
export class SimController {
|
||||
@@ -37,19 +38,21 @@ export class SimController {
|
||||
const body = req.body
|
||||
|
||||
// 1. Validacion del body
|
||||
try {
|
||||
if (args.validator != undefined)
|
||||
args.validator.validate(body)
|
||||
} catch (e) {
|
||||
if (args.onError != undefined) args.onError(body, e as string)
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
msg: e
|
||||
}
|
||||
})
|
||||
if (args.validator != undefined) {
|
||||
const validationResult = args.validator.validate(body)
|
||||
if (validationResult.error != undefined) {
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
...validationResult.error
|
||||
}
|
||||
})
|
||||
args.onError(body, validationResult.error.msg)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Transformacion del body
|
||||
// TODO: sustituir el try cach
|
||||
let data: P = body;
|
||||
try {
|
||||
if (args.mapBody != undefined)
|
||||
@@ -60,26 +63,33 @@ export class SimController {
|
||||
msg: "Error parseando el body: " + e
|
||||
}
|
||||
})
|
||||
args.onError(body, String(e))
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 3. Aplicacion del UseCase
|
||||
try {
|
||||
const usecaseResult = await args.useCase(data)
|
||||
// 4. Se devuelve al usuario el caso de exito
|
||||
res.status(200).json(
|
||||
usecaseResult
|
||||
).send()
|
||||
args.onSuccess(data)
|
||||
} catch (err) {
|
||||
// TODO: todos los use cases tienen que pasar a devolver un Result<>
|
||||
const usecaseResult = await args.useCase(data) // no deberia hacer falta el trycatch
|
||||
|
||||
// 4. Casos de error del usecase
|
||||
if (usecaseResult.error != undefined) {
|
||||
// 4.1 Error del caso de uso
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "Error general:" + err
|
||||
...usecaseResult.error
|
||||
}
|
||||
}).send()
|
||||
return;
|
||||
args.onError(body, usecaseResult.error.msg.message)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 5. Se devuelve al usuario el caso de exito
|
||||
res.status(200).json(
|
||||
usecaseResult.data
|
||||
).send()
|
||||
args.onSuccess(usecaseResult.data)
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,155 +102,64 @@ export class SimController {
|
||||
console.log("OK", data)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
public preactivation() {
|
||||
return async (req: Request, res: Response) => {
|
||||
console.warn("[!] Se deberia de usar la peticion /sim/activate directamente")
|
||||
try {
|
||||
iccidValidator.validate(req.body)
|
||||
} catch (e) {
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
msg: e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const { iccid } = req.body
|
||||
const compañia = companyFromIccid(iccid)
|
||||
|
||||
try {
|
||||
await this.simUseCases.preActivation({ iccid, compañia })
|
||||
|
||||
res.status(200).json({
|
||||
iccid: iccid,
|
||||
operation: "activation"
|
||||
}).send()
|
||||
} catch (err) {
|
||||
console.error("Error activando la sim ", req.body)
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "Error general de activation"
|
||||
}
|
||||
}).send()
|
||||
return;
|
||||
}
|
||||
}
|
||||
return this.controllerGenerator<{ iccid: string, offer: string }, { iccid: string, offer: string, compañia: string }>({
|
||||
validator: activationValidator,
|
||||
mapBody: (b) => {
|
||||
const { iccid, offer } = b
|
||||
const compañia = companyFromIccid(iccid)
|
||||
return { iccid, compañia, offer }
|
||||
},
|
||||
useCase: (args) => this.simUseCases.preActivation(args),
|
||||
onError: (d, e) => console.error("[x] Error preactivation: ", d, e),
|
||||
onSuccess: console.log
|
||||
})
|
||||
}
|
||||
|
||||
public activation() {
|
||||
return async (req: Request, res: Response) => {
|
||||
try {
|
||||
activationValidator.validate(req.body)
|
||||
} catch (e) {
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
msg: e
|
||||
}
|
||||
})
|
||||
console.error("[!] Error validando mensaje")
|
||||
return;
|
||||
}
|
||||
|
||||
const { iccid, offer } = req.body
|
||||
|
||||
const compañia = companyFromIccid(iccid)
|
||||
|
||||
if (compañia == undefined) {
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "El iccid no pertenece a una compañia conocida"
|
||||
}
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
await this.simUseCases.activation({ iccid, compañia, offer })
|
||||
|
||||
res.status(200).json({
|
||||
iccid: iccid,
|
||||
operation: "activation"
|
||||
}).send()
|
||||
return;
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error activando la sim ", req.body)
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "Error general de activation"
|
||||
}
|
||||
}).send()
|
||||
return;
|
||||
}
|
||||
}
|
||||
return this.controllerGenerator<{ iccid: string, offer: string }, { iccid: string, offer: string, compañia: string }>({
|
||||
validator: activationValidator,
|
||||
mapBody: (b) => {
|
||||
const { iccid, offer } = b
|
||||
const compañia = companyFromIccid(iccid)
|
||||
return { iccid, compañia, offer }
|
||||
},
|
||||
useCase: (args) => this.simUseCases.activation(args),
|
||||
onError: (d, e) => console.error("[x] Error activacion: ", d, e),
|
||||
onSuccess: console.log
|
||||
})
|
||||
}
|
||||
|
||||
public cancelation() {
|
||||
return async (req: Request, res: Response) => {
|
||||
try {
|
||||
iccidValidator.validate(req.body)
|
||||
} catch (e) {
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
msg: e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const { iccid } = req.body
|
||||
const compañia = companyFromIccid(iccid)
|
||||
|
||||
try {
|
||||
await this.simUseCases.cancelation({ iccid, compañia })
|
||||
res.status(200).json({
|
||||
iccid: iccid,
|
||||
operation: "cancelation"
|
||||
})
|
||||
} catch (err) {
|
||||
console.error("Error cancelando la sim ", req.body)
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "Error general de cancelacion"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return this.controllerGenerator<{ iccid: string }, { iccid: string, compañia: string }>({
|
||||
validator: iccidValidator,
|
||||
mapBody: (b) => {
|
||||
const { iccid } = b
|
||||
const compañia = companyFromIccid(iccid)
|
||||
return { iccid, compañia }
|
||||
},
|
||||
useCase: (args) => this.simUseCases.cancelation(args),
|
||||
// TODO: Meter en los mensajes el nombre de la operacion
|
||||
onError: (d, e) => console.error("[x] Error cancelacion: ", d, e),
|
||||
onSuccess: console.log
|
||||
})
|
||||
}
|
||||
|
||||
public pause() {
|
||||
return async (req: Request, res: Response) => {
|
||||
try {
|
||||
iccidValidator.validate(req.body)
|
||||
} catch (e) {
|
||||
res.status(422).json({
|
||||
errors: {
|
||||
msg: e
|
||||
}
|
||||
})
|
||||
}
|
||||
return this.controllerGenerator<{ iccid: string }, { iccid: string, compañia: string }>({
|
||||
validator: iccidValidator,
|
||||
mapBody: (b) => {
|
||||
const { iccid } = b
|
||||
const compañia = companyFromIccid(iccid)
|
||||
return { iccid, compañia }
|
||||
},
|
||||
useCase: (args) => this.simUseCases.pause(args),
|
||||
onError: (d, e) => console.error("[x] Error pausa: ", d, e),
|
||||
onSuccess: console.log
|
||||
})
|
||||
|
||||
const { iccid } = req.body
|
||||
const compañia = companyFromIccid(iccid)
|
||||
|
||||
try {
|
||||
await this.simUseCases.pause({ iccid, compañia })
|
||||
res.status(200).json({
|
||||
iccid: iccid,
|
||||
operation: "cancelation"
|
||||
})
|
||||
} catch (err) {
|
||||
console.error("Error pausando la sim ", req.body)
|
||||
res.status(500).json({
|
||||
errors: {
|
||||
msg: "Error pausando la sim"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public free() {
|
||||
|
||||
@@ -24,7 +24,7 @@ export class SimUsecases {
|
||||
}
|
||||
|
||||
/**
|
||||
* Añade un id de mensaje (correlation_id en ala base de datos)
|
||||
* Añade un id de mensaje (correlation_id en la base de datos) a los mensajes que van a entrar en la cola
|
||||
*/
|
||||
private addMessage_id(event: SimEvents.general): SimEvents.general & { headers: { message_id: string } } {
|
||||
const uuid = uuidv7()
|
||||
@@ -65,7 +65,6 @@ export class SimUsecases {
|
||||
|
||||
const result = await this.orderRepository.createOrder<T>(order)
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
async test(args: { iccid: string }) {
|
||||
@@ -84,7 +83,7 @@ export class SimUsecases {
|
||||
}
|
||||
|
||||
/**
|
||||
* WIP
|
||||
* TODO:
|
||||
* Crea una nueva sim de la que no se tenia registro anteriormente
|
||||
* Si ya existia se modifican los campos pero no se hace un cambio
|
||||
* de estado.
|
||||
@@ -101,8 +100,8 @@ export class SimUsecases {
|
||||
return this.eventBus.publish([activationEvent])
|
||||
}
|
||||
|
||||
async activation(args: { iccid: string, compañia: string, offer: string }) {
|
||||
|
||||
async activation(args: { iccid: string, compañia: string, offer: string }):
|
||||
Promise<Result<string, { iccid: string, message_id: string, operation: "activation" }>> {
|
||||
const activationEvent = <SimEvents.activation>{
|
||||
key: `sim.${args.compañia}.activate`,
|
||||
payload: {
|
||||
@@ -110,14 +109,29 @@ export class SimUsecases {
|
||||
offer: args.offer
|
||||
}
|
||||
}
|
||||
|
||||
const activationWithId = this.addMessage_id(activationEvent)
|
||||
console.log("[d] Activation ", activationWithId)
|
||||
await this.eventBus.publish([activationWithId])
|
||||
await this.saveOrder(activationWithId)
|
||||
const createdOrder = await this.saveOrder<SimEvents.activation>(activationWithId)
|
||||
|
||||
if (createdOrder.error != undefined) {
|
||||
console.error(createdOrder.error)
|
||||
return {
|
||||
error: createdOrder.error
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
iccid: args.iccid,
|
||||
operation: "activation",
|
||||
message_id: createdOrder.data?.correlation_id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async preActivation(args: { iccid: string, compañia: string }) {
|
||||
async preActivation(args: { iccid: string, compañia: string }):
|
||||
Promise<Result<string, { iccid: string, message_id: string, operation: "preactivation" }>> {
|
||||
|
||||
const preActivationEvent = <SimEvents.preActivation>{
|
||||
key: `sim.${args.compañia}.preActivate`,
|
||||
@@ -126,13 +140,30 @@ export class SimUsecases {
|
||||
}
|
||||
}
|
||||
console.log("[d] Pre - activation ", preActivationEvent)
|
||||
return this.eventBus.publish([preActivationEvent])
|
||||
await this.eventBus.publish([preActivationEvent])
|
||||
const preactivationWithId = this.addMessage_id(preActivationEvent)
|
||||
const createdOrder = await this.saveOrder<SimEvents.preActivation>(preactivationWithId)
|
||||
if (createdOrder.error != undefined) {
|
||||
console.error(createdOrder.error)
|
||||
return {
|
||||
error: createdOrder.error
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
iccid: args.iccid,
|
||||
operation: "preactivation",
|
||||
message_id: createdOrder.data?.correlation_id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Para objenious es terminate
|
||||
*/
|
||||
async cancelation(args: { iccid: string, compañia: string }) {
|
||||
async cancelation(args: { iccid: string, compañia: string }):
|
||||
Promise<Result<string, { iccid: string, message_id: string, operation: "cancelation" }>> {
|
||||
|
||||
const cancelationEvent = <SimEvents.cancel>{
|
||||
key: `sim.${args.compañia}.cancel`,
|
||||
@@ -144,8 +175,21 @@ export class SimUsecases {
|
||||
const cancelationWithId = this.addMessage_id(cancelationEvent)
|
||||
console.log("[d] Cancelation ", cancelationWithId)
|
||||
await this.eventBus.publish([cancelationWithId])
|
||||
await this.saveOrder(cancelationWithId)
|
||||
return cancelationWithId
|
||||
const savedOrder = await this.saveOrder(cancelationWithId)
|
||||
if (savedOrder.error != undefined) {
|
||||
console.error(savedOrder.error)
|
||||
return {
|
||||
error: savedOrder.error
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
iccid: args.iccid,
|
||||
message_id: savedOrder.data.correlation_id,
|
||||
operation: "cancelation"
|
||||
}
|
||||
}
|
||||
}
|
||||
// alias por si acaso
|
||||
public terminate = this.cancelation;
|
||||
@@ -153,7 +197,8 @@ export class SimUsecases {
|
||||
/**
|
||||
* alias de bloquear / suspender en objenious
|
||||
*/
|
||||
async pause(args: { iccid: string, compañia: string }) {
|
||||
async pause(args: { iccid: string, compañia: string }):
|
||||
Promise<Result<string, { iccid: string, message_id: string, operation: "cancelation" }>> {
|
||||
const pauseEvent = <SimEvents.pause>{
|
||||
key: `sim.${args.compañia}.pause`,
|
||||
payload: {
|
||||
@@ -161,10 +206,25 @@ export class SimUsecases {
|
||||
}
|
||||
}
|
||||
const pauseWithId = this.addMessage_id(pauseEvent)
|
||||
console.log("[d] Cancelation ", pauseWithId)
|
||||
console.log("[d] Pause", pauseWithId)
|
||||
await this.eventBus.publish([pauseWithId])
|
||||
await this.saveOrder(pauseWithId)
|
||||
return pauseWithId
|
||||
const savedOrder = await this.saveOrder(pauseWithId)
|
||||
|
||||
if (savedOrder.error != undefined) {
|
||||
console.error(savedOrder.error)
|
||||
return {
|
||||
error: savedOrder.error
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
iccid: args.iccid,
|
||||
message_id: savedOrder.data.correlation_id,
|
||||
operation: "cancelation"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async free(args: { iccid: string, compañia: string }) {
|
||||
|
||||
@@ -8,9 +8,10 @@ describe("test validators", () => {
|
||||
iccid: "8933201125068886692"
|
||||
}
|
||||
const res = iccidValidator.validate(validBody)
|
||||
assert(res == true)
|
||||
assert(res.error == undefined)
|
||||
}),
|
||||
|
||||
// TODO: Nada de esto es valido, a partir de ahora los validadores no lanzan excepcion sino Result
|
||||
it("shouldnt validate empty string iccid", () => {
|
||||
const validBody = {
|
||||
iccid: ""
|
||||
|
||||
@@ -3,7 +3,9 @@ import { BodyValidator, Validator } from "sim-shared/aplication/BodyValidator.js
|
||||
|
||||
const offers = new Map([
|
||||
["mensual", "SAVEFAMILY1"],
|
||||
["anual", "SAVEFAMILY2"]
|
||||
["anual", "SAVEFAMILY2"],
|
||||
["SAVEFAMILY1", "SAVEFAMILY1"],
|
||||
["SAVEFAMILY2", "SAVEFAMILY2"],
|
||||
])
|
||||
|
||||
const iccidLongitudValidator = <Validator<{ iccid: string }>>{
|
||||
|
||||
@@ -46,5 +46,4 @@ if (env.ENVIRONMENT == "production") {
|
||||
assert(env.RABBITMQ_HOST != "localhost")
|
||||
}
|
||||
|
||||
console.log("CRON: ENV", env)
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Result } from "../domain/Result.js"
|
||||
|
||||
export type Validator<T extends Object> = {
|
||||
field: keyof T,
|
||||
errorMsg: string,
|
||||
@@ -16,10 +18,18 @@ export class BodyValidator<T extends Object> {
|
||||
this.validatorList = validators
|
||||
}
|
||||
|
||||
public validate(obj: T) {
|
||||
public validate(obj: T): Result<{ msg: string, field: string }, boolean> {
|
||||
for (const validator of this.validatorList) {
|
||||
if (validator.validationFunc(obj) == false) throw new Error(validator.errorMsg)
|
||||
if (validator.validationFunc(obj) == false)
|
||||
return {
|
||||
error: {
|
||||
msg: validator.errorMsg,
|
||||
field: String(validator.field)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return {
|
||||
data: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,31 @@
|
||||
|
||||
export type Success<D> = {
|
||||
error?: undefined | null,
|
||||
data: D
|
||||
}
|
||||
|
||||
export type Failure<E = Error> = {
|
||||
data?: undefined | null,
|
||||
error: E
|
||||
}
|
||||
|
||||
/**
|
||||
* Result<Error,Data>
|
||||
*/
|
||||
export type Result<E, D> =
|
||||
{
|
||||
error: E,
|
||||
data?: undefined
|
||||
}
|
||||
|
|
||||
{
|
||||
error?: undefined,
|
||||
data: D
|
||||
}
|
||||
export type Result<E, D> = Failure<E> | Success<D>
|
||||
|
||||
export async function tryCatch<T>(func: Promise<T>): Promise<Result<{ msg: Error }, T>> {
|
||||
try {
|
||||
const res = await func;
|
||||
return {
|
||||
data: res
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
return {
|
||||
error: {
|
||||
msg: e as Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user