try-catch-cloud
Version:
Advanced error logging for your app with low code integration
1 lines • 18.4 kB
Source Map (JSON)
{"version":3,"sources":["../../src/hono/factory.ts","../../src/helpers.ts","../../src/core/types.ts","../../src/core/baseUtility.ts","../../src/hono/utility.ts","../../src/hono/index.ts"],"sourcesContent":["import type { MiddlewareHandler } from \"hono\";\nimport type { MiddlewareOptions } from \"./types\";\nimport type { HonoErrorUtility } from \"./utility\";\n\ninterface FactoryContext<\n TInstance extends HonoErrorUtility\n> {\n instance: TInstance;\n}\n\nexport type HonoMiddlewareSetup<\n TMiddlewareOptions extends MiddlewareOptions = MiddlewareOptions\n> = (options: TMiddlewareOptions) => MiddlewareHandler\n\nexport const tryCatchFactory = <\n TInstance extends HonoErrorUtility,\n TFactoryContext extends FactoryContext<TInstance>,\n>(factoryOptions: {\n createContext: (options: MiddlewareOptions) => TFactoryContext;\n handler: (context: TFactoryContext) => MiddlewareHandler;\n}): HonoMiddlewareSetup => {\n return (options: MiddlewareOptions): MiddlewareHandler => {\n const context = factoryOptions.createContext(options);\n\n return factoryOptions.handler(context);\n };\n};\n","import type { AxiosError } from 'axios';\n\nexport function isAxiosError(e: unknown): e is AxiosError {\n return (\n e !== null &&\n typeof e === \"object\" &&\n (e as Pick<AxiosError, \"isAxiosError\">).isAxiosError === true\n );\n}\n","export type SendErrorResponse =\n\t| {\n\t\t\tid: string;\n\t }\n\t| undefined;\n\nexport interface ErrorUtilityMethods<TRequest> {\n\tsendError(\n\t\terror: Error | unknown,\n\t\tuserContext?: Record<string, unknown>,\n\t): Promise<SendErrorResponse>;\n\tsendErrorFromEndPoint(\n\t\terror: Error | unknown,\n\t\trequest: TRequest,\n\t\tuserContext?: Record<string, unknown>,\n\t): Promise<SendErrorResponse>;\n}\n\nexport class WrappedError extends Error {\n\treadonly value: unknown;\n\tconstructor(message: string, value: unknown) {\n\t\tsuper(message);\n\n\t\tthis.value = value;\n\t}\n}\n\nexport interface HttpRequest {\n\turl?: string;\n\tmethod?: string;\n\tpath?: string;\n\tbody?: unknown;\n\tquery?: Record<string, unknown>;\n\theaders?: Record<string, unknown>;\n}\n\nexport interface MappedHttpRequest {\n\tmethod: string | null;\n\turl: string | null;\n\trequestBody: unknown | null;\n\tquery: Record<string, unknown> | null;\n\theaders: Record<string, unknown> | null;\n}\n\nexport type ErrorDetails<\n\tT extends Record<string, unknown> = Record<string, unknown>,\n> = {\n\tname: string;\n\tmessage: string;\n} & T;\n\nexport type ErrorRequestContext = Record<string, unknown> | null;\n\nexport interface ErrorRequest<\n\tTDetails extends Record<string, unknown> = Record<string, unknown>,\n> {\n\terrorName: string;\n\terrorDetails: ErrorDetails<TDetails>;\n\tstack: string | null;\n\tcontext: ErrorRequestContext;\n\tuser: string;\n\tprojectName: string;\n}\n\nexport type AxiosErrorRequest = ErrorRequest<{\n\turl: string | null;\n\tquery: Record<string, string | string[] | undefined> | null;\n\tparams: unknown | null;\n\tmethod: string | null;\n\tstatusCode: number;\n\trequestBody: unknown | null;\n\tresponseBody: unknown | null;\n}>;\n","import { isAxiosError } from \"../helpers\";\nimport type {\n\tMappedHttpRequest,\n\tErrorRequest,\n\tAxiosErrorRequest,\n\tErrorUtilityMethods,\n\tErrorDetails,\n\tErrorRequestContext,\n} from \"./types\";\nimport { WrappedError } from \"./types\";\nimport type { AxiosError } from \"axios\";\n\nexport abstract class BaseErrorUtility<TRequest>\n\timplements ErrorUtilityMethods<TRequest>\n{\n\tconstructor(\n\t\tprotected readonly projectName: string,\n\t\tprotected readonly apiKey: string,\n\t\tprotected readonly debug?: boolean,\n\t) {\n\t\tif (!projectName.length) {\n\t\t\tthrow new Error(\"Invalid project name\");\n\t\t}\n\n\t\tif (!apiKey.length) {\n\t\t\tthrow new Error(\"Invalid API key\");\n\t\t}\n\t}\n\n\tprotected abstract mapRequest(\n\t\trequest: TRequest,\n\t): Promise<MappedHttpRequest> | MappedHttpRequest;\n\n\tasync sendError(\n\t\terror: Error | unknown,\n\t\tuserContext?: Record<string, unknown>,\n\t) {\n\t\ttry {\n\t\t\tconst payload = await this.mapErrorRequestPayload(\n\t\t\t\terror,\n\t\t\t\tundefined,\n\t\t\t\tuserContext,\n\t\t\t);\n\n\t\t\treturn this.send(payload);\n\t\t} catch (err) {\n\t\t\tif (this.debug) {\n\t\t\t\tconsole.log(err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Sends error and request details to try-catch-cloud service.\n\t * You can manually map details from your route to request object.\n\t *\n\t * ```\n\t * errorTrack.sendErrorFromEndpoint(\n\t * error,\n\t * {\n\t * url: req.originalUrl.split(\"?\")[0],\n\t * method: req.method,\n\t * headers: req.headers,\n\t * query: req.query,\n\t * body,\n\t * },\n\t * { ...context }\n\t * );\n\t * ```\n\t */\n\tasync sendErrorFromEndPoint(\n\t\terror: Error | unknown,\n\t\trequest: TRequest,\n\t\tuserContext?: Record<string, unknown>,\n\t) {\n\t\ttry {\n\t\t\tconst payload = await this.mapErrorRequestPayload(\n\t\t\t\terror,\n\t\t\t\trequest,\n\t\t\t\tuserContext,\n\t\t\t);\n\n\t\t\treturn this.send(payload);\n\t\t} catch (err) {\n\t\t\tif (this.debug) {\n\t\t\t\tconsole.log(err);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected async send(payload: ErrorRequest): Promise<{ id: string }> {\n\t\tconst result = await fetch(\"https://oleksiikilevoi.site/api/err-log/new\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(payload),\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t});\n\n\t\tif (this.debug) {\n\t\t\tconsole.info(\"Send result\", await result.text());\n\t\t}\n\n const data: { id: string } = await result.json();\n\n return data;\n\t}\n\n\t/**\n\t * It has to return Promise to be compatible with different implementations\n\t * e.g. Hono returns Promise when accessing req.json()\n\t */\n\tprotected async mapErrorRequestPayload(\n\t\terror: Error | unknown,\n\t\trequest?: TRequest,\n\t\tcontext?: Record<string, unknown>,\n\t): Promise<ErrorRequest> {\n\t\tif (!(error instanceof Error)) {\n\t\t\treturn this.mapErrorRequestPayload(\n\t\t\t\tnew WrappedError(\"An unexpected value was thrown\", error),\n\t\t\t\trequest,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t}\n\n\t\tif (isAxiosError(error)) {\n\t\t\treturn this.mapAxiosError(error, request, context);\n\t\t}\n\n\t\tconst { stack, ...restErrorDetails } = error;\n\n\t\treturn {\n\t\t\t...(request ? await this.mapRequest(request) : {}),\n\t\t\terrorName: error.name,\n\t\t\terrorDetails: this.sanitizeValue({\n\t\t\t\t...restErrorDetails,\n\t\t\t\tname: error.name,\n\t\t\t\tmessage: error.message,\n\t\t\t}) as ErrorDetails,\n\t\t\tstack: error.stack ?? null,\n\t\t\tcontext: this.sanitizeValue(context ?? null) as ErrorRequestContext,\n\t\t\tuser: this.apiKey,\n\t\t\tprojectName: this.projectName,\n\t\t};\n\t}\n\n\tprotected mapAxiosRequestBody(error: AxiosError) {\n\t\ttry {\n\t\t\tconst config = error.config;\n\t\t\tconst headers: Record<string, string> = config?.headers ?? {};\n\t\t\tconst contentType: string =\n\t\t\t\theaders[\"content-type\"] ?? headers[\"Content-Type\"] ?? \"\";\n\n\t\t\tif (!contentType.length) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (contentType.startsWith(\"multipart/form-data\")) {\n\t\t\t\treturn \"#form-data\";\n\t\t\t}\n\n\t\t\tif (contentType === \"application/json\") {\n\t\t\t\treturn JSON.parse(config?.data);\n\t\t\t}\n\n\t\t\tif (contentType.match(/^text\\/.+$/)) {\n\t\t\t\treturn config?.data as string;\n\t\t\t}\n\n\t\t\tif (contentType === \"application/x-www-form-urlencoded\") {\n\t\t\t\treturn new URLSearchParams(config?.data).toString();\n\t\t\t}\n\n\t\t\tif (contentType === \"application/xml\") {\n\t\t\t\treturn decodeURIComponent(config?.data); // Assuming data is already a string\n\t\t\t}\n\n\t\t\tif (contentType === \"application/octet-stream\") {\n\t\t\t\treturn \"#binary-data\";\n\t\t\t}\n\n\t\t\treturn \"#tcc/mapping-failed\";\n\t\t} catch (e) {\n\t\t\tif (this.debug) {\n\t\t\t\tconsole.error(e);\n\t\t\t}\n\n\t\t\treturn \"#tcc/mapping-failed\";\n\t\t}\n\t}\n\n\tprotected async mapAxiosError(\n\t\terror: AxiosError,\n\t\trequest?: TRequest,\n\t\tcontext?: ErrorRequestContext,\n\t): Promise<AxiosErrorRequest> {\n\t\tconst { config, response } = error;\n\t\tconst requestBody = this.mapAxiosRequestBody(error);\n\t\tconst responseBody = response?.data;\n\n\t\tconst rawUrl = config?.url ?? \"\";\n\t\tconst query = Object.fromEntries([\n\t\t\t...(URL.canParse(rawUrl) ? new URL(rawUrl).searchParams.entries() : []),\n\t\t]);\n\n\t\tconst axiosDetails = {\n\t\t\turl: config?.url ?? null,\n\t\t\tquery: Object.keys(query).length ? query : null,\n\t\t\tparams: config?.params ?? null,\n\t\t\tmethod: config?.method?.toUpperCase() || null,\n\t\t\tstatusCode: response?.status ?? 0,\n\t\t\trequestBody,\n\t\t\tresponseBody: responseBody ?? null,\n\t\t\theaders: config?.headers ?? {},\n\t\t};\n\n\t\treturn {\n\t\t\t...(request ? await this.mapRequest(request) : {}),\n\t\t\terrorName: error.constructor.name ?? error.name,\n\t\t\terrorDetails: this.sanitizeValue({\n\t\t\t\t...axiosDetails,\n\t\t\t\tname: error.name,\n\t\t\t\tmessage: error.message,\n\t\t\t}) as ErrorDetails<typeof axiosDetails>,\n\t\t\tstack: error.stack ?? null,\n\t\t\tcontext: context ?? null,\n\t\t\tuser: this.apiKey,\n\t\t\tprojectName: this.projectName,\n\t\t};\n\t}\n\n\tprotected sanitizeValue(value: unknown, level = 1): unknown {\n\t\tif (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n\t\t\tconst result: Record<string, unknown> = {};\n\n\t\t\tfor (const [key, objValue] of Object.entries(value)) {\n\t\t\t\tresult[key] = this.sanitizeValue(objValue, level + 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tif (typeof value === \"object\" && Array.isArray(value)) {\n\t\t\treturn value.map((item) => this.sanitizeValue(item, level + 1));\n\t\t}\n\n\t\tif (typeof value === \"function\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn value;\n\t}\n}\n","import { BaseErrorUtility } from \"../core/baseUtility\";\nimport type { MappedHttpRequest, SendErrorResponse } from \"../core/types\";\nimport type { HonoRequest } from \"hono\";\nimport { URL } from \"node:url\";\n\n/**\n * Implements request mapping for Hono.\n * See `sendErrorFromEndPoint` method.\n */\nexport class HonoErrorUtility extends BaseErrorUtility<HonoRequest> {\n\tprotected async mapRequest<TRequest extends HonoRequest = HonoRequest>(\n\t\treq: TRequest,\n\t): Promise<MappedHttpRequest> {\n\t\tconst parsedUrl = new URL(req.url);\n\n\t\tconst [url] = parsedUrl.pathname.split(\"?\");\n\n\t\tlet requestBody: unknown;\n\t\ttry {\n\t\t\t// TODO: It will lose requestBody if server expects text instead of json\n\t\t\trequestBody = await req.json();\n\t\t} catch (e) {\n\t\t\trequestBody = null;\n\t\t}\n\n\t\tconst query = req.query();\n\n\t\tconst result = {\n\t\t\tmethod: req.method.toUpperCase(),\n\t\t\turl,\n\t\t\trequestBody,\n\t\t\theaders: req.header(),\n\t\t\tquery: Object.keys(query).length ? query : null,\n\t\t};\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Sends error and Hono request details to try-catch-cloud service.\n\t * ```\n\t * app.onError(async (err, ctx) => {\n\t * errorUtility.sendErrorFromEndPoint(err, ctx.req, { ...errorContext })\n\t * .catch((e) => { ... });\n\t *\n\t * return ctx.json({ message: 'Internal server error' }, 500);\n\t * });\n\t * ```\n\t */\n\tasync sendErrorFromEndPoint(\n\t\terror: unknown,\n\t\trequest: HonoRequest,\n\t\tuserContext?: Record<string, unknown> | undefined,\n\t): Promise<SendErrorResponse> {\n\t\treturn super.sendErrorFromEndPoint(error, request, userContext);\n\t};\n}\n","import { tryCatchFactory } from \"./factory\";\nimport type { ErrorContext, TryCatchContext } from \"./types\";\nimport { HonoErrorUtility } from \"./utility\";\n\nexport { HonoErrorUtility };\n\ndeclare module \"hono\" {\n\tinterface ContextVariableMap {\n\t\ttryCatch: TryCatchContext;\n\t}\n}\n\nexport const tryCatch = tryCatchFactory({\n\tcreateContext: (options) => ({\n\t\tinstance: new HonoErrorUtility(\n\t\t\toptions.projectName,\n\t\t\toptions.apiKey,\n\t\t\toptions.debug,\n\t\t),\n\t}),\n\thandler: ({ instance }) => {\n\t\treturn async (ctx, next) => {\n\t\t\tlet errorContext: ErrorContext = {};\n\n\t\t\tctx.set(\"tryCatch\", {\n\t\t\t\taddContext: (errCtx: ErrorContext) => {\n\t\t\t\t\terrorContext = {\n\t\t\t\t\t\t...errorContext,\n\t\t\t\t\t\t...errCtx,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t} satisfies TryCatchContext);\n\n\t\t\tawait next();\n\n\t\t\tif (ctx.error) {\n\t\t\t\tconst error = ctx.error;\n\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\tconst ctrName = error.constructor.name;\n\n // Do not use HTTPException class itself, Hono is only a peer dependency of tcc\n\t\t\t\t\tif (ctrName === \"HTTPException\") {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tinstance\n\t\t\t\t\t.sendErrorFromEndPoint(ctx.error, ctx.req, errorContext)\n\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t// console.log('error sent');\n\t\t\t\t\t})\n\t\t\t\t\t.catch((e) => {\n\t\t\t\t\t\t// console.error('error', e);\n\t\t\t\t\t});\n\t\t\t}\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["URL","URL"]}