@opble/core 1.0.1 → 1.0.2
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/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var types=require('@opble/types'),hono=require('hono'),toolkit=require('@opble/toolkit'),factory=require('hono/factory')
|
|
2
|
-
exports.AppFactory=je;exports.BaseController=w;exports.CorsModule=
|
|
1
|
+
'use strict';var types=require('@opble/types'),hono=require('hono'),toolkit=require('@opble/toolkit'),factory=require('hono/factory'),$=require('zod'),debug=require('@opble/debug'),m=require('winston'),auth0=require('@opble/auth0'),entityAuth=require('@opble/entity-auth'),cors=require('hono/cors'),honoRateLimiter=require('hono-rate-limiter');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var $__default=/*#__PURE__*/_interopDefault($);var m__namespace=/*#__PURE__*/_interopNamespace(m);var w=class{};var T=class extends w{constructor(t,o){super();this.factory=t;this.repository=o;}createItem=async(t,o)=>{let s=await t.req.json(),i=await o.schema.safeParseAsync(s);if(!i.success)throw i.error;let d=await this.repository.save(this.factory.create(i.data));return t.json(o.view?o.view(d):d,201)};updateItem=async(t,o)=>{let s=await t.req.json(),i=await o.schema.safeParseAsync(s);if(!i.success)throw i.error;let d=o.parseRequestId(t),l=await this.repository.get(d);if(!l)throw types.ResourceNotFoundError;if(o.allow&&!o.allow(t,l))throw types.ForbiddenError;return l=await this.repository.save(this.factory.create({...l,...i.data})),t.json(o.view?o.view(l):l)};getItem=async(t,o)=>{let s=o.parseRequestId(t),i=await this.repository.get(s);if(!i)throw types.ResourceNotFoundError;if(o.allow&&!o.allow(t,i))throw types.ForbiddenError;return t.json(o.view?o.view(i):i)};deleteItem=async(t,o)=>{let s=o.parseRequestId(t),i=await this.repository.get(s);if(!i)throw types.ResourceNotFoundError;if(o.allow&&!o.allow(t,i))throw types.ForbiddenError;return await this.repository.delete(s),t.json(o.view?o.view(i):i)}};var c=debug.createDebug("opble:core");var R=r=>typeof r=="string"?r.split(",").map(t=>t.trim()).filter(t=>t.length>0):[],H=$.z.object({LOGGER_TRANSPORT_DEFAULT:$.z.enum(["console","file"]).default("console"),LOGGER_TRANSPORT_FILE:$.z.string().optional(),APP_BASE_PATH:$.z.string().optional(),CORS_ALLOW_ORIGIN:$.z.preprocess(R,$.z.array($.z.string())).default(["*"]),CORS_ALLOW_HEADERS:$.z.preprocess(R,$.z.array($.z.string())).default(["Content-Type","Authorization"]),CORS_ALLOW_METHODS:$.z.preprocess(R,$.z.array($.z.string())).default(["GET","POST","PUT","PATCH","DELETE","OPTIONS"]),USE_RATE_LIMIT:$.z.transform(r=>r==="true"||r==="1"?true:r==="false"||r==="0"?false:!!r).default(false),RATE_LIMIT_WINDOW:$.z.preprocess(r=>{let e=Number(r);return isNaN(e)?900*1e3:e},$.z.number()).default(900*1e3),RATE_LIMIT:$.z.preprocess(r=>{let e=Number(r);return isNaN(e)?100:e},$.z.number()).default(100)}),n=H.parse(process.env);var N=()=>n.LOGGER_TRANSPORT_DEFAULT==="file"&&n.LOGGER_TRANSPORT_FILE?new m__namespace.transports.File({filename:n.LOGGER_TRANSPORT_FILE}):new m__namespace.transports.Console,D=(...r)=>m__namespace.createLogger({level:"info",format:m__namespace.format.combine(m__namespace.format.splat(),m__namespace.format.timestamp(),m__namespace.format.json()),transports:r.length?r:[N()]}),k=D(),x=class{logger;traceId;metadata;timer;constructor(e={}){let t=crypto.randomUUID();this.traceId=t,this.metadata={traceId:t,...e},this.logger=k.child(this.metadata),this.timer=new toolkit.Timer;}log(e,t,...o){this.logger.log(e,t,...o,{duration:this.timer.tock()});}debug(e,...t){this.log("debug",e,...t);}info(e,...t){this.log("info",e,...t);}warn(e,...t){this.log("warn",e,...t);}error(e,...t){this.log("error",e,...t);}},q={create(r){return new x(r)}};function u(r){let e=r.get("logger");return e||(e=q.create({}),r.set("logger",e)),e}function z(r,e){let t;return e instanceof $.ZodError?(t=types.BadRequestError,t.message=$__default.default.prettifyError(e)):types.isHttpError(e)?t=e:(t=types.InternalServerError,u(r).error("Catch an error. Details: %s",e)),t}var L=factory.createMiddleware(async(r,e)=>{let t=new toolkit.Timer;t.tick();try{u(r).info("[start] %s %s",r.req.method,r.req.path),await e(),u(r).info("[end]",{status:r.res.status,duration:t.tock()});}catch(o){let s=f(o,r);return u(r).info("[end]",{status:s.status,duration:t.tock()}),s}}),f=(r,e)=>{c("Tear down with error:",r);let{code:t,message:o,status:s}=z(e,r);return e.json({code:t,message:o},s)};var g=class r{modules;constructor(e){this.modules=e;}static load(e,...t){new r(t).modules.forEach(s=>{s.install(e),c("Module is loaded => %s",`${Object.getPrototypeOf(s).constructor.name}`);});}};function _(...r){let e;return n.APP_BASE_PATH?(e=new hono.Hono().basePath(n.APP_BASE_PATH),c(`App base path set to '${n.APP_BASE_PATH}'`)):e=new hono.Hono,e.use(L),g.load(e,...r),e.onError(f),e}var je={create:r=>r&&Array.isArray(r)?_(...r):_()};function ze(r){let e=r.get("user");if(!e)throw new Error("User not found");return e}var ee=entityAuth.PublicUserFactory.create({id:"system",name:"System",email:"system@wewise.net",role:"admin",emailVerified:true}),y=r=>({get:e=>r.req.header(e)});function A(r){let e=r.get("user");return e?entityAuth.PublicUserSchema.safeParse(e).success:false}var rt=factory.createMiddleware(async(r,e)=>{if(!A(r))try{let t=await auth0.requireUser(y(r));r.set("user",t);}catch(t){return f(t,r)}await e();}),ot=(...r)=>factory.createMiddleware(async(e,t)=>{A(e)||e.set("user",await auth0.requireUserRole(y(e),...r)),await t();}),st=(...r)=>factory.createMiddleware(async(e,t)=>{A(e)||e.set("user",await auth0.requireUserPermission(y(e),...r)),await t();}),nt=(...r)=>factory.createMiddleware(async(e,t)=>{if(!A(e)){let o=auth0.extractBearerToken(y(e));o&&r.includes(o)&&e.set("user",ee);}await t();});var P=class{options;constructor(e={}){this.options=e;}install(e){let t=new C;e.get("/health",t.checkHealth);}},C=class{checkHealth=e=>e.json({status:"UP"})};var se=r=>{let e=r.indexOf("://")!==-1,o=r.replace(/[.+?^${}()|[\]\\]/g,i=>`\\${i}`).replace(/\*/g,".*"),s=e?`^${o}$`:`^https?://${o}$`;return new RegExp(s)},ne=debug.createDebug("opble:core:CorsModule"),M=class{install(e){ne("CORS_ALLOW_ORIGIN:",n.CORS_ALLOW_ORIGIN),e.use("/*",cors.cors({origin:t=>{for(let o of n.CORS_ALLOW_ORIGIN){if(o==="*")return t??"";if(t===o)return t;if(o.indexOf("*")!==-1){let s=se(o);if(t&&s.test(t))return t}}return ""},allowHeaders:n.CORS_ALLOW_HEADERS,allowMethods:n.CORS_ALLOW_METHODS}));}};var I=debug.createDebug("opble:core:rate-limiter"),S=class{constructor(e={paths:["/*"]}){this.options=e;}install(e){if(I("Use Rate Limiter:",n.USE_RATE_LIMIT),!n.USE_RATE_LIMIT)return;I("Installing RateLimiterModule with options:",this.options),I(`Rate limiting: ${n.RATE_LIMIT} requests per ${n.RATE_LIMIT_WINDOW} ms`);let t=honoRateLimiter.rateLimiter({windowMs:n.RATE_LIMIT_WINDOW,limit:n.RATE_LIMIT,standardHeaders:"draft-7",keyGenerator:o=>o.req.header("x-forwarded-for")??"anonymous"});for(let o of this.options.paths)e.use(o,t);}};
|
|
2
|
+
exports.AppFactory=je;exports.BaseController=w;exports.CorsModule=M;exports.CrudController=T;exports.LoggerFactory=q;exports.ModuleLoader=g;exports.RateLimiterModule=S;exports.ServiceStatusModule=P;exports.auth=rt;exports.authAllowKeys=nt;exports.authAllowPermission=st;exports.authAllowRole=ot;exports.getCurrentUser=ze;exports.log=u;exports.setUp=L;exports.tearDown=f;//# sourceMappingURL=index.cjs.map
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/controller/base.ts","../src/controller/crud.ts","../src/lib/debugger.ts","../src/lib/env.ts","../src/lib/logger.ts","../src/middleware/app.ts","../src/lib/loader.ts","../src/lib/app.ts","../src/lib/auth.ts","../src/middleware/auth.ts","../src/module/service-status.ts","../src/module/cors.ts","../src/module/rate-limiter.ts"],"names":["BaseController","CrudController","factory","repository","context","options","body","result","item","requestId","ResourceNotFoundError","ForbiddenError","debug","createDebug","commaSeparatedToArray","value","s","envSchema","z","val","n","env","createDefaultWinstonTransport","m","createWinstonLogger","transports","winstonLogger","CoreLogger","metadata","traceId","Timer","level","message","args","LoggerFactory","data","log","logger","toHttpError","err","ZodError","BadRequestError","isHttpError","InternalServerError","setUp","createMiddleware","next","timer","response","tearDown","code","status","ModuleLoader","_ModuleLoader","modules","app","module","createApp","Hono","AppFactory","getCurrentUser","user","systemUser","PublicUserFactory","toHeaderGetter","name","isAuthenticated","PublicUserSchema","auth","requireUser","e","authAllowRole","roles","requireUserRole","authAllowPermission","permissions","requireUserPermission","authAllowKeys","keys","token","extractBearerToken","ServiceStatusModule","handler","ServiceStatusHandler","wildcardToRegExp","pattern","hasScheme","wildcardReplaced","regexStr","CorsModule","cors","origin","allowedOrigin","re","RateLimiterModule","limiter","rateLimiter","c","path"],"mappings":"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","file":"index.cjs","sourcesContent":["export class BaseController {}\n","import { DynamoDBRepository, TableKey } from '@opble/repository-dynamodb';\nimport {\n Factory,\n ForbiddenError,\n HashMap,\n ResourceNotFoundError,\n} from '@opble/types';\nimport { z } from 'zod';\n\nimport { AppContext } from '../lib/types';\n\nimport { BaseController } from './base';\n\ntype View = (data: unknown) => HashMap;\n\ntype BaseOptions = {\n view?: View;\n};\n\ntype PayloadOptions = BaseOptions & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: z.ZodType<unknown, unknown, any>;\n};\n\ntype RequestIdOptions = {\n parseRequestId: (context: AppContext) => TableKey;\n};\n\ntype ResourcePolicyOptions<T extends HashMap> = {\n allow?: (context: AppContext, item: T) => boolean;\n};\n\ntype GetItemOptions = BaseOptions & RequestIdOptions;\ntype DeleteItemOptions = GetItemOptions;\n\ntype CreateItemOptions = PayloadOptions;\ntype UpdateItemOptions = PayloadOptions & RequestIdOptions;\n\nexport class CrudController<T extends HashMap> extends BaseController {\n constructor(\n protected factory: Factory<T>,\n private repository: DynamoDBRepository<T>\n ) {\n super();\n }\n\n createItem = async (context: AppContext, options: CreateItemOptions) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const item = await this.repository.save(this.factory.create(result.data));\n\n return context.json(options.view ? options.view(item) : item, 201);\n };\n\n updateItem = async (\n context: AppContext,\n options: UpdateItemOptions & ResourcePolicyOptions<T>\n ) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const requestId = options.parseRequestId(context);\n let item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n item = await this.repository.save(\n this.factory.create({\n ...item,\n ...result.data,\n })\n );\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n getItem = async (\n context: AppContext,\n options: GetItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n deleteItem = async (\n context: AppContext,\n options: DeleteItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n await this.repository.delete(requestId);\n return context.json(options.view ? options.view(item) : item);\n };\n}\n","import { createDebug } from '@opble/debug';\n\nexport const debug = createDebug('opble:core');\n","import { z } from 'zod';\n\nconst commaSeparatedToArray = (value: unknown) => {\n if (typeof value === 'string') {\n const items = value\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return items;\n }\n\n // If undefined or not a string, return empty array by default\n return [] as string[];\n};\n\nconst envSchema = z.object({\n LOGGER_TRANSPORT_DEFAULT: z.enum(['console', 'file']).default('console'),\n LOGGER_TRANSPORT_FILE: z.string().optional(),\n\n APP_BASE_PATH: z.string().optional(),\n\n CORS_ALLOW_ORIGIN: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['*']),\n CORS_ALLOW_HEADERS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['Content-Type', 'Authorization']),\n CORS_ALLOW_METHODS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),\n\n USE_RATE_LIMIT: z\n .transform((val) => {\n if (val === 'true' || val === '1') return true;\n if (val === 'false' || val === '0') return false;\n return Boolean(val);\n })\n .default(false),\n RATE_LIMIT_WINDOW: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 15 * 60 * 1000 : n; // default 15 minutes\n }, z.number())\n .default(15 * 60 * 1000),\n RATE_LIMIT: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 100 : n; // default 100 requests\n }, z.number())\n .default(100),\n});\n\nexport const env = envSchema.parse(process.env);\n","import { Timer } from '@opble/toolkit';\nimport { Factory, StringHashMap } from '@opble/types';\nimport { Logger } from '@opble/types';\nimport { Context } from 'hono';\nimport * as winston from 'winston';\n\nimport { env } from './env';\nimport { CoreEnv } from './types';\n\nconst createDefaultWinstonTransport = (): winston.transport => {\n if (env.LOGGER_TRANSPORT_DEFAULT === 'file' && env.LOGGER_TRANSPORT_FILE) {\n return new winston.transports.File({\n filename: env.LOGGER_TRANSPORT_FILE,\n });\n }\n\n return new winston.transports.Console();\n};\n\nconst createWinstonLogger = (...transports: winston.transport[]) =>\n winston.createLogger({\n level: 'info',\n format: winston.format.combine(\n winston.format.splat(),\n winston.format.timestamp(),\n winston.format.json()\n ),\n transports: transports.length\n ? transports\n : [createDefaultWinstonTransport()],\n });\n\nconst winstonLogger: winston.Logger = createWinstonLogger();\n\nclass CoreLogger implements Logger {\n private readonly logger: winston.Logger;\n private readonly traceId: string;\n private metadata: StringHashMap;\n private readonly timer: Timer;\n\n constructor(metadata: StringHashMap = {}) {\n const traceId = crypto.randomUUID();\n this.traceId = traceId;\n this.metadata = {\n traceId,\n ...metadata,\n };\n this.logger = winstonLogger.child(this.metadata);\n this.timer = new Timer();\n }\n\n private log(level: string, message: string, ...args: unknown[]): void {\n this.logger.log(level, message, ...args, { duration: this.timer.tock() });\n }\n\n debug(message: string, ...args: unknown[]): void {\n this.log('debug', message, ...args);\n }\n\n info(message: string, ...args: unknown[]): void {\n this.log('info', message, ...args);\n }\n\n warn(message: string, ...args: unknown[]): void {\n this.log('warn', message, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n this.log('error', message, ...args);\n }\n}\n\nexport const LoggerFactory: Factory<Logger> = {\n create(data: unknown): Logger {\n return new CoreLogger(data as StringHashMap);\n },\n};\n\nexport function log(context: Context<CoreEnv>): Logger {\n let logger = context.get('logger');\n if (!logger) {\n logger = LoggerFactory.create({});\n context.set('logger', logger);\n }\n\n return logger;\n}\n","import { Timer } from '@opble/toolkit';\nimport {\n BadRequestError,\n HttpError,\n InternalServerError,\n isHttpError,\n} from '@opble/types';\nimport { Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\nimport { ContentfulStatusCode } from 'hono/utils/http-status';\nimport z, { ZodError } from 'zod';\n\nimport { debug } from '../lib/debugger.js';\nimport { log } from '../lib/logger';\nimport { AppContext } from '../lib/types';\n\nfunction toHttpError(context: AppContext, e: unknown): HttpError {\n let err: HttpError;\n if (e instanceof ZodError) {\n err = BadRequestError;\n err.message = z.prettifyError(e);\n } else if (isHttpError(e)) {\n err = e as HttpError;\n } else {\n err = InternalServerError;\n log(context).error('Catch an error. Details: %s', e);\n }\n\n return err;\n}\n\nexport const setUp = createMiddleware(\n async (context: AppContext, next: Next) => {\n const timer = new Timer();\n timer.tick();\n\n try {\n log(context).info('[start] %s %s', context.req.method, context.req.path);\n await next();\n log(context).info('[end]', {\n status: context.res.status,\n duration: timer.tock(),\n });\n } catch (err) {\n const response = tearDown(err, context);\n log(context).info('[end]', {\n status: response.status,\n duration: timer.tock(),\n });\n\n return response;\n }\n }\n);\n\nexport const tearDown = (err: unknown, context: AppContext) => {\n debug('Tear down with error:', err);\n const { code, message, status } = toHttpError(context, err);\n return context.json({ code, message }, status as ContentfulStatusCode);\n};\n","import { debug } from './debugger.js';\nimport { App } from './types';\n\nexport interface Module {\n install(app: App): void;\n}\n\nexport class ModuleLoader {\n private modules: Module[];\n\n constructor(modules: Module[]) {\n this.modules = modules;\n }\n\n static load(app: App, ...modules: Module[]) {\n const loader = new ModuleLoader(modules);\n loader.modules.forEach((module) => {\n module.install(app);\n debug(\n 'Module is loaded => %s',\n `${Object.getPrototypeOf(module).constructor.name}`\n );\n });\n }\n}\n","import { Factory } from '@opble/types';\nimport { Hono } from 'hono';\n\nimport { setUp, tearDown } from '../middleware/app';\n\nimport { debug } from './debugger';\nimport { env } from './env';\nimport { Module, ModuleLoader } from './loader';\nimport { App, CoreEnv } from './types';\n\nfunction createApp(...modules: Module[]) {\n let app: App;\n if (env.APP_BASE_PATH) {\n app = new Hono<CoreEnv>().basePath(env.APP_BASE_PATH);\n debug(`App base path set to '${env.APP_BASE_PATH}'`);\n } else {\n app = new Hono<CoreEnv>();\n }\n\n app.use(setUp);\n ModuleLoader.load(app, ...modules);\n app.onError(tearDown);\n\n return app;\n}\n\nexport const AppFactory: Factory<App> = {\n create: (data: unknown) => {\n if (data && Array.isArray(data)) {\n return createApp(...data);\n }\n\n return new Hono<CoreEnv>();\n },\n};\n","import { PublicUser } from '@opble/entity-auth';\nimport { Context } from 'hono';\n\nimport { CoreEnv } from './types';\n\nexport function getCurrentUser(context: Context<CoreEnv>): PublicUser {\n const user = context.get('user');\n if (!user) {\n throw new Error('User not found');\n }\n return user;\n}\n","import {\n requireUser,\n requireUserRole,\n requireUserPermission,\n extractBearerToken,\n} from '@opble/auth0';\nimport { PublicUserFactory, PublicUserSchema } from '@opble/entity-auth';\nimport { Context, Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\n\nimport { CoreEnv } from '../lib/types';\n\nimport { tearDown } from './app';\n\nconst systemUser = PublicUserFactory.create({\n id: 'system',\n name: 'System',\n email: 'system@wewise.net',\n role: 'admin',\n emailVerified: true,\n});\nconst toHeaderGetter = (context: Context<CoreEnv>) => {\n return {\n get: (name: string) => context.req.header(name),\n };\n};\n\nfunction isAuthenticated(context: Context<CoreEnv>): boolean {\n const user = context.get('user');\n if (!user) {\n return false;\n }\n\n return PublicUserSchema.safeParse(user).success;\n}\n\nexport const auth = createMiddleware(\n async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n try {\n const user = await requireUser(toHeaderGetter(context));\n context.set('user', user);\n } catch (e) {\n return tearDown(e, context);\n }\n }\n\n await next();\n }\n);\n\nexport const authAllowRole = (...roles: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserRole(toHeaderGetter(context), ...roles)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowPermission = (...permissions: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserPermission(toHeaderGetter(context), ...permissions)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowKeys = (...keys: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n const token = extractBearerToken(toHeaderGetter(context));\n if (token && keys.includes(token)) {\n context.set('user', systemUser);\n }\n }\n\n await next();\n });\n};\n","import { HashMap } from '@opble/types';\n\nimport { UP } from '../lib/constant';\nimport { Module } from '../lib/loader';\nimport { App, AppContext } from '../lib/types';\n\nexport type ServiceStatusOptions = HashMap;\n\nexport class ServiceStatusModule implements Module {\n private options: ServiceStatusOptions;\n\n constructor(options: ServiceStatusOptions = {}) {\n this.options = options;\n }\n\n install(app: App) {\n const handler = new ServiceStatusHandler();\n app.get('/health', handler.checkHealth);\n }\n}\n\nclass ServiceStatusHandler {\n checkHealth = (context: AppContext) => {\n return context.json({\n status: UP,\n });\n };\n}\n","import { createDebug } from '@opble/debug';\nimport { cors } from 'hono/cors';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\n// Convert wildcard pattern like \"https://*.wewise.net\" into a RegExp\nconst wildcardToRegExp = (pattern: string): RegExp => {\n // If pattern doesn't include scheme, allow http(s)\n const hasScheme = pattern.indexOf('://') !== -1;\n // Escape regexp special chars except '*'\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, (m) => `\\\\${m}`);\n // Now replace escaped '*' (which would be '\\*') with '.*'\n const wildcardReplaced = escaped.replace(/\\*/g, '.*');\n const regexStr = hasScheme\n ? `^${wildcardReplaced}$`\n : `^https?://${wildcardReplaced}$`;\n return new RegExp(regexStr);\n};\n\nconst debug = createDebug('opble:core:CorsModule');\n\nexport class CorsModule implements Module {\n install(app: App) {\n debug('CORS_ALLOW_ORIGIN:', env.CORS_ALLOW_ORIGIN);\n app.use(\n '/*',\n cors({\n origin: (origin) => {\n for (const allowedOrigin of env.CORS_ALLOW_ORIGIN) {\n if (allowedOrigin === '*') {\n return origin ?? '';\n }\n\n // Direct match\n if (origin === allowedOrigin) {\n return origin;\n }\n\n // Wildcard matching\n if (allowedOrigin.indexOf('*') !== -1) {\n const re = wildcardToRegExp(allowedOrigin);\n if (origin && re.test(origin)) {\n return origin;\n }\n }\n }\n\n return '';\n },\n allowHeaders: env.CORS_ALLOW_HEADERS,\n allowMethods: env.CORS_ALLOW_METHODS,\n })\n );\n }\n}\n","import { createDebug } from '@opble/debug';\nimport { rateLimiter } from 'hono-rate-limiter';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\nconst debug = createDebug('opble:core:rate-limiter');\n\nexport type RateLimiterModuleOptions = {\n paths: string[];\n};\n\nexport class RateLimiterModule implements Module {\n constructor(private options: RateLimiterModuleOptions = { paths: ['/*'] }) {}\n\n install(app: App) {\n debug('Use Rate Limiter:', env.USE_RATE_LIMIT);\n if (!env.USE_RATE_LIMIT) {\n return;\n }\n\n debug('Installing RateLimiterModule with options:', this.options);\n debug(\n `Rate limiting: ${env.RATE_LIMIT} requests per ${env.RATE_LIMIT_WINDOW} ms`\n );\n\n /**\n * Notes:\n * - The rate limiter is applied to the specified paths.\n * - The limit and window are configurable via environment variables.\n * - The key generator uses the \"x-forwarded-for\" header to identify clients behind proxies.\n *\n * Important:\n * - RateLimiterModule must be installed before other modules so it could be executed first.\n */\n const limiter = rateLimiter({\n windowMs: env.RATE_LIMIT_WINDOW,\n limit: env.RATE_LIMIT,\n standardHeaders: 'draft-7',\n keyGenerator: (c) => c.req.header('x-forwarded-for') ?? 'anonymous',\n });\n for (const path of this.options.paths) {\n app.use(path, limiter);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/controller/base.ts","../src/controller/crud.ts","../src/lib/debugger.ts","../src/lib/env.ts","../src/lib/logger.ts","../src/middleware/app.ts","../src/lib/loader.ts","../src/lib/app.ts","../src/lib/auth.ts","../src/middleware/auth.ts","../src/module/service-status.ts","../src/module/cors.ts","../src/module/rate-limiter.ts"],"names":["BaseController","CrudController","factory","repository","context","options","body","result","item","requestId","ResourceNotFoundError","ForbiddenError","debug","createDebug","commaSeparatedToArray","value","s","envSchema","z","val","n","env","createDefaultWinstonTransport","m","createWinstonLogger","transports","winstonLogger","CoreLogger","metadata","traceId","Timer","level","message","args","LoggerFactory","data","log","logger","toHttpError","err","ZodError","BadRequestError","isHttpError","InternalServerError","setUp","createMiddleware","next","timer","response","tearDown","code","status","ModuleLoader","_ModuleLoader","modules","app","module","createApp","Hono","AppFactory","getCurrentUser","user","systemUser","PublicUserFactory","toHeaderGetter","name","isAuthenticated","PublicUserSchema","auth","requireUser","e","authAllowRole","roles","requireUserRole","authAllowPermission","permissions","requireUserPermission","authAllowKeys","keys","token","extractBearerToken","ServiceStatusModule","handler","ServiceStatusHandler","wildcardToRegExp","pattern","hasScheme","wildcardReplaced","regexStr","CorsModule","cors","origin","allowedOrigin","re","RateLimiterModule","limiter","rateLimiter","c","path"],"mappings":"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","file":"index.cjs","sourcesContent":["export class BaseController {}\n","import { DynamoDBRepository, TableKey } from '@opble/repository-dynamodb';\nimport {\n Factory,\n ForbiddenError,\n HashMap,\n ResourceNotFoundError,\n} from '@opble/types';\nimport { z } from 'zod';\n\nimport { AppContext } from '../lib/types';\n\nimport { BaseController } from './base';\n\ntype View = (data: unknown) => HashMap;\n\ntype BaseOptions = {\n view?: View;\n};\n\ntype PayloadOptions = BaseOptions & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: z.ZodType<unknown, unknown, any>;\n};\n\ntype RequestIdOptions = {\n parseRequestId: (context: AppContext) => TableKey;\n};\n\ntype ResourcePolicyOptions<T extends HashMap> = {\n allow?: (context: AppContext, item: T) => boolean;\n};\n\ntype GetItemOptions = BaseOptions & RequestIdOptions;\ntype DeleteItemOptions = GetItemOptions;\n\ntype CreateItemOptions = PayloadOptions;\ntype UpdateItemOptions = PayloadOptions & RequestIdOptions;\n\nexport class CrudController<T extends HashMap> extends BaseController {\n constructor(\n protected factory: Factory<T>,\n private repository: DynamoDBRepository<T>\n ) {\n super();\n }\n\n createItem = async (context: AppContext, options: CreateItemOptions) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const item = await this.repository.save(this.factory.create(result.data));\n\n return context.json(options.view ? options.view(item) : item, 201);\n };\n\n updateItem = async (\n context: AppContext,\n options: UpdateItemOptions & ResourcePolicyOptions<T>\n ) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const requestId = options.parseRequestId(context);\n let item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n item = await this.repository.save(\n this.factory.create({\n ...item,\n ...result.data,\n })\n );\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n getItem = async (\n context: AppContext,\n options: GetItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n deleteItem = async (\n context: AppContext,\n options: DeleteItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n await this.repository.delete(requestId);\n return context.json(options.view ? options.view(item) : item);\n };\n}\n","import { createDebug } from '@opble/debug';\n\nexport const debug = createDebug('opble:core');\n","import { z } from 'zod';\n\nconst commaSeparatedToArray = (value: unknown) => {\n if (typeof value === 'string') {\n const items = value\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return items;\n }\n\n // If undefined or not a string, return empty array by default\n return [] as string[];\n};\n\nconst envSchema = z.object({\n LOGGER_TRANSPORT_DEFAULT: z.enum(['console', 'file']).default('console'),\n LOGGER_TRANSPORT_FILE: z.string().optional(),\n\n APP_BASE_PATH: z.string().optional(),\n\n CORS_ALLOW_ORIGIN: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['*']),\n CORS_ALLOW_HEADERS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['Content-Type', 'Authorization']),\n CORS_ALLOW_METHODS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),\n\n USE_RATE_LIMIT: z\n .transform((val) => {\n if (val === 'true' || val === '1') return true;\n if (val === 'false' || val === '0') return false;\n return Boolean(val);\n })\n .default(false),\n RATE_LIMIT_WINDOW: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 15 * 60 * 1000 : n; // default 15 minutes\n }, z.number())\n .default(15 * 60 * 1000),\n RATE_LIMIT: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 100 : n; // default 100 requests\n }, z.number())\n .default(100),\n});\n\nexport const env = envSchema.parse(process.env);\n","import { Timer } from '@opble/toolkit';\nimport { Factory, StringHashMap } from '@opble/types';\nimport { Logger } from '@opble/types';\nimport { Context } from 'hono';\nimport * as winston from 'winston';\n\nimport { env } from './env';\nimport { CoreEnv } from './types';\n\nconst createDefaultWinstonTransport = (): winston.transport => {\n if (env.LOGGER_TRANSPORT_DEFAULT === 'file' && env.LOGGER_TRANSPORT_FILE) {\n return new winston.transports.File({\n filename: env.LOGGER_TRANSPORT_FILE,\n });\n }\n\n return new winston.transports.Console();\n};\n\nconst createWinstonLogger = (...transports: winston.transport[]) =>\n winston.createLogger({\n level: 'info',\n format: winston.format.combine(\n winston.format.splat(),\n winston.format.timestamp(),\n winston.format.json()\n ),\n transports: transports.length\n ? transports\n : [createDefaultWinstonTransport()],\n });\n\nconst winstonLogger: winston.Logger = createWinstonLogger();\n\nclass CoreLogger implements Logger {\n private readonly logger: winston.Logger;\n private readonly traceId: string;\n private metadata: StringHashMap;\n private readonly timer: Timer;\n\n constructor(metadata: StringHashMap = {}) {\n const traceId = crypto.randomUUID();\n this.traceId = traceId;\n this.metadata = {\n traceId,\n ...metadata,\n };\n this.logger = winstonLogger.child(this.metadata);\n this.timer = new Timer();\n }\n\n private log(level: string, message: string, ...args: unknown[]): void {\n this.logger.log(level, message, ...args, { duration: this.timer.tock() });\n }\n\n debug(message: string, ...args: unknown[]): void {\n this.log('debug', message, ...args);\n }\n\n info(message: string, ...args: unknown[]): void {\n this.log('info', message, ...args);\n }\n\n warn(message: string, ...args: unknown[]): void {\n this.log('warn', message, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n this.log('error', message, ...args);\n }\n}\n\nexport const LoggerFactory: Factory<Logger> = {\n create(data: unknown): Logger {\n return new CoreLogger(data as StringHashMap);\n },\n};\n\nexport function log(context: Context<CoreEnv>): Logger {\n let logger = context.get('logger');\n if (!logger) {\n logger = LoggerFactory.create({});\n context.set('logger', logger);\n }\n\n return logger;\n}\n","import { Timer } from '@opble/toolkit';\nimport {\n BadRequestError,\n HttpError,\n InternalServerError,\n isHttpError,\n} from '@opble/types';\nimport { Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\nimport { ContentfulStatusCode } from 'hono/utils/http-status';\nimport z, { ZodError } from 'zod';\n\nimport { debug } from '../lib/debugger.js';\nimport { log } from '../lib/logger';\nimport { AppContext } from '../lib/types';\n\nfunction toHttpError(context: AppContext, e: unknown): HttpError {\n let err: HttpError;\n if (e instanceof ZodError) {\n err = BadRequestError;\n err.message = z.prettifyError(e);\n } else if (isHttpError(e)) {\n err = e as HttpError;\n } else {\n err = InternalServerError;\n log(context).error('Catch an error. Details: %s', e);\n }\n\n return err;\n}\n\nexport const setUp = createMiddleware(\n async (context: AppContext, next: Next) => {\n const timer = new Timer();\n timer.tick();\n\n try {\n log(context).info('[start] %s %s', context.req.method, context.req.path);\n await next();\n log(context).info('[end]', {\n status: context.res.status,\n duration: timer.tock(),\n });\n } catch (err) {\n const response = tearDown(err, context);\n log(context).info('[end]', {\n status: response.status,\n duration: timer.tock(),\n });\n\n return response;\n }\n }\n);\n\nexport const tearDown = (err: unknown, context: AppContext) => {\n debug('Tear down with error:', err);\n const { code, message, status } = toHttpError(context, err);\n return context.json({ code, message }, status as ContentfulStatusCode);\n};\n","import { debug } from './debugger.js';\nimport { App } from './types';\n\nexport interface Module {\n install(app: App): void;\n}\n\nexport class ModuleLoader {\n private modules: Module[];\n\n constructor(modules: Module[]) {\n this.modules = modules;\n }\n\n static load(app: App, ...modules: Module[]) {\n const loader = new ModuleLoader(modules);\n loader.modules.forEach((module) => {\n module.install(app);\n debug(\n 'Module is loaded => %s',\n `${Object.getPrototypeOf(module).constructor.name}`\n );\n });\n }\n}\n","import { Factory } from '@opble/types';\nimport { Hono } from 'hono';\n\nimport { setUp, tearDown } from '../middleware/app';\n\nimport { debug } from './debugger';\nimport { env } from './env';\nimport { Module, ModuleLoader } from './loader';\nimport { App, CoreEnv } from './types';\n\nfunction createApp(...modules: Module[]): App {\n let app;\n if (env.APP_BASE_PATH) {\n app = new Hono<CoreEnv>().basePath(env.APP_BASE_PATH);\n debug(`App base path set to '${env.APP_BASE_PATH}'`);\n } else {\n app = new Hono<CoreEnv>();\n }\n\n app.use(setUp);\n ModuleLoader.load(app, ...modules);\n app.onError(tearDown);\n\n return app;\n}\n\nexport const AppFactory: Factory<App> = {\n create: (data: unknown): App => {\n if (data && Array.isArray(data)) {\n return createApp(...data);\n }\n\n return createApp();\n },\n};\n","import { PublicUser } from '@opble/entity-auth';\nimport { Context } from 'hono';\n\nimport { CoreEnv } from './types';\n\nexport function getCurrentUser(context: Context<CoreEnv>): PublicUser {\n const user = context.get('user');\n if (!user) {\n throw new Error('User not found');\n }\n return user;\n}\n","import {\n requireUser,\n requireUserRole,\n requireUserPermission,\n extractBearerToken,\n} from '@opble/auth0';\nimport { PublicUserFactory, PublicUserSchema } from '@opble/entity-auth';\nimport { Context, Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\n\nimport { CoreEnv } from '../lib/types';\n\nimport { tearDown } from './app';\n\nconst systemUser = PublicUserFactory.create({\n id: 'system',\n name: 'System',\n email: 'system@wewise.net',\n role: 'admin',\n emailVerified: true,\n});\nconst toHeaderGetter = (context: Context<CoreEnv>) => {\n return {\n get: (name: string) => context.req.header(name),\n };\n};\n\nfunction isAuthenticated(context: Context<CoreEnv>): boolean {\n const user = context.get('user');\n if (!user) {\n return false;\n }\n\n return PublicUserSchema.safeParse(user).success;\n}\n\nexport const auth = createMiddleware(\n async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n try {\n const user = await requireUser(toHeaderGetter(context));\n context.set('user', user);\n } catch (e) {\n return tearDown(e, context);\n }\n }\n\n await next();\n }\n);\n\nexport const authAllowRole = (...roles: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserRole(toHeaderGetter(context), ...roles)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowPermission = (...permissions: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserPermission(toHeaderGetter(context), ...permissions)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowKeys = (...keys: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n const token = extractBearerToken(toHeaderGetter(context));\n if (token && keys.includes(token)) {\n context.set('user', systemUser);\n }\n }\n\n await next();\n });\n};\n","import { HashMap } from '@opble/types';\n\nimport { UP } from '../lib/constant';\nimport { Module } from '../lib/loader';\nimport { App, AppContext } from '../lib/types';\n\nexport type ServiceStatusOptions = HashMap;\n\nexport class ServiceStatusModule implements Module {\n private options: ServiceStatusOptions;\n\n constructor(options: ServiceStatusOptions = {}) {\n this.options = options;\n }\n\n install(app: App) {\n const handler = new ServiceStatusHandler();\n app.get('/health', handler.checkHealth);\n }\n}\n\nclass ServiceStatusHandler {\n checkHealth = (context: AppContext) => {\n return context.json({\n status: UP,\n });\n };\n}\n","import { createDebug } from '@opble/debug';\nimport { cors } from 'hono/cors';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\n// Convert wildcard pattern like \"https://*.wewise.net\" into a RegExp\nconst wildcardToRegExp = (pattern: string): RegExp => {\n // If pattern doesn't include scheme, allow http(s)\n const hasScheme = pattern.indexOf('://') !== -1;\n // Escape regexp special chars except '*'\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, (m) => `\\\\${m}`);\n // Now replace escaped '*' (which would be '\\*') with '.*'\n const wildcardReplaced = escaped.replace(/\\*/g, '.*');\n const regexStr = hasScheme\n ? `^${wildcardReplaced}$`\n : `^https?://${wildcardReplaced}$`;\n return new RegExp(regexStr);\n};\n\nconst debug = createDebug('opble:core:CorsModule');\n\nexport class CorsModule implements Module {\n install(app: App) {\n debug('CORS_ALLOW_ORIGIN:', env.CORS_ALLOW_ORIGIN);\n app.use(\n '/*',\n cors({\n origin: (origin) => {\n for (const allowedOrigin of env.CORS_ALLOW_ORIGIN) {\n if (allowedOrigin === '*') {\n return origin ?? '';\n }\n\n // Direct match\n if (origin === allowedOrigin) {\n return origin;\n }\n\n // Wildcard matching\n if (allowedOrigin.indexOf('*') !== -1) {\n const re = wildcardToRegExp(allowedOrigin);\n if (origin && re.test(origin)) {\n return origin;\n }\n }\n }\n\n return '';\n },\n allowHeaders: env.CORS_ALLOW_HEADERS,\n allowMethods: env.CORS_ALLOW_METHODS,\n })\n );\n }\n}\n","import { createDebug } from '@opble/debug';\nimport { rateLimiter } from 'hono-rate-limiter';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\nconst debug = createDebug('opble:core:rate-limiter');\n\nexport type RateLimiterModuleOptions = {\n paths: string[];\n};\n\nexport class RateLimiterModule implements Module {\n constructor(private options: RateLimiterModuleOptions = { paths: ['/*'] }) {}\n\n install(app: App) {\n debug('Use Rate Limiter:', env.USE_RATE_LIMIT);\n if (!env.USE_RATE_LIMIT) {\n return;\n }\n\n debug('Installing RateLimiterModule with options:', this.options);\n debug(\n `Rate limiting: ${env.RATE_LIMIT} requests per ${env.RATE_LIMIT_WINDOW} ms`\n );\n\n /**\n * Notes:\n * - The rate limiter is applied to the specified paths.\n * - The limit and window are configurable via environment variables.\n * - The key generator uses the \"x-forwarded-for\" header to identify clients behind proxies.\n *\n * Important:\n * - RateLimiterModule must be installed before other modules so it could be executed first.\n */\n const limiter = rateLimiter({\n windowMs: env.RATE_LIMIT_WINDOW,\n limit: env.RATE_LIMIT,\n standardHeaders: 'draft-7',\n keyGenerator: (c) => c.req.header('x-forwarded-for') ?? 'anonymous',\n });\n for (const path of this.options.paths) {\n app.use(path, limiter);\n }\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {BadRequestError,isHttpError,InternalServerError,ResourceNotFoundError,ForbiddenError}from'@opble/types';import {Hono}from'hono';import {Timer}from'@opble/toolkit';import {createMiddleware}from'hono/factory';import
|
|
2
|
-
export{$e as AppFactory,g as BaseController,
|
|
1
|
+
import {BadRequestError,isHttpError,InternalServerError,ResourceNotFoundError,ForbiddenError}from'@opble/types';import {Hono}from'hono';import {Timer}from'@opble/toolkit';import {createMiddleware}from'hono/factory';import V,{z,ZodError}from'zod';import {createDebug}from'@opble/debug';import*as l from'winston';import {requireUser,requireUserRole,requireUserPermission,extractBearerToken}from'@opble/auth0';import {PublicUserFactory,PublicUserSchema}from'@opble/entity-auth';import {cors}from'hono/cors';import {rateLimiter}from'hono-rate-limiter';var g=class{};var L=class extends g{constructor(t,o){super();this.factory=t;this.repository=o;}createItem=async(t,o)=>{let s=await t.req.json(),i=await o.schema.safeParseAsync(s);if(!i.success)throw i.error;let w=await this.repository.save(this.factory.create(i.data));return t.json(o.view?o.view(w):w,201)};updateItem=async(t,o)=>{let s=await t.req.json(),i=await o.schema.safeParseAsync(s);if(!i.success)throw i.error;let w=o.parseRequestId(t),c=await this.repository.get(w);if(!c)throw ResourceNotFoundError;if(o.allow&&!o.allow(t,c))throw ForbiddenError;return c=await this.repository.save(this.factory.create({...c,...i.data})),t.json(o.view?o.view(c):c)};getItem=async(t,o)=>{let s=o.parseRequestId(t),i=await this.repository.get(s);if(!i)throw ResourceNotFoundError;if(o.allow&&!o.allow(t,i))throw ForbiddenError;return t.json(o.view?o.view(i):i)};deleteItem=async(t,o)=>{let s=o.parseRequestId(t),i=await this.repository.get(s);if(!i)throw ResourceNotFoundError;if(o.allow&&!o.allow(t,i))throw ForbiddenError;return await this.repository.delete(s),t.json(o.view?o.view(i):i)}};var u=createDebug("opble:core");var x=r=>typeof r=="string"?r.split(",").map(t=>t.trim()).filter(t=>t.length>0):[],U=z.object({LOGGER_TRANSPORT_DEFAULT:z.enum(["console","file"]).default("console"),LOGGER_TRANSPORT_FILE:z.string().optional(),APP_BASE_PATH:z.string().optional(),CORS_ALLOW_ORIGIN:z.preprocess(x,z.array(z.string())).default(["*"]),CORS_ALLOW_HEADERS:z.preprocess(x,z.array(z.string())).default(["Content-Type","Authorization"]),CORS_ALLOW_METHODS:z.preprocess(x,z.array(z.string())).default(["GET","POST","PUT","PATCH","DELETE","OPTIONS"]),USE_RATE_LIMIT:z.transform(r=>r==="true"||r==="1"?true:r==="false"||r==="0"?false:!!r).default(false),RATE_LIMIT_WINDOW:z.preprocess(r=>{let e=Number(r);return isNaN(e)?900*1e3:e},z.number()).default(900*1e3),RATE_LIMIT:z.preprocess(r=>{let e=Number(r);return isNaN(e)?100:e},z.number()).default(100)}),n=U.parse(process.env);var D=()=>n.LOGGER_TRANSPORT_DEFAULT==="file"&&n.LOGGER_TRANSPORT_FILE?new l.transports.File({filename:n.LOGGER_TRANSPORT_FILE}):new l.transports.Console,k=(...r)=>l.createLogger({level:"info",format:l.format.combine(l.format.splat(),l.format.timestamp(),l.format.json()),transports:r.length?r:[D()]}),q=k(),C=class{logger;traceId;metadata;timer;constructor(e={}){let t=crypto.randomUUID();this.traceId=t,this.metadata={traceId:t,...e},this.logger=q.child(this.metadata),this.timer=new Timer;}log(e,t,...o){this.logger.log(e,t,...o,{duration:this.timer.tock()});}debug(e,...t){this.log("debug",e,...t);}info(e,...t){this.log("info",e,...t);}warn(e,...t){this.log("warn",e,...t);}error(e,...t){this.log("error",e,...t);}},G={create(r){return new C(r)}};function f(r){let e=r.get("logger");return e||(e=G.create({}),r.set("logger",e)),e}function K(r,e){let t;return e instanceof ZodError?(t=BadRequestError,t.message=V.prettifyError(e)):isHttpError(e)?t=e:(t=InternalServerError,f(r).error("Catch an error. Details: %s",e)),t}var v=createMiddleware(async(r,e)=>{let t=new Timer;t.tick();try{f(r).info("[start] %s %s",r.req.method,r.req.path),await e(),f(r).info("[end]",{status:r.res.status,duration:t.tock()});}catch(o){let s=d(o,r);return f(r).info("[end]",{status:s.status,duration:t.tock()}),s}}),d=(r,e)=>{u("Tear down with error:",r);let{code:t,message:o,status:s}=K(e,r);return e.json({code:t,message:o},s)};var h=class r{modules;constructor(e){this.modules=e;}static load(e,...t){new r(t).modules.forEach(s=>{s.install(e),u("Module is loaded => %s",`${Object.getPrototypeOf(s).constructor.name}`);});}};function P(...r){let e;return n.APP_BASE_PATH?(e=new Hono().basePath(n.APP_BASE_PATH),u(`App base path set to '${n.APP_BASE_PATH}'`)):e=new Hono,e.use(v),h.load(e,...r),e.onError(d),e}var $e={create:r=>r&&Array.isArray(r)?P(...r):P()};function Ke(r){let e=r.get("user");if(!e)throw new Error("User not found");return e}var te=PublicUserFactory.create({id:"system",name:"System",email:"system@wewise.net",role:"admin",emailVerified:true}),A=r=>({get:e=>r.req.header(e)});function E(r){let e=r.get("user");return e?PublicUserSchema.safeParse(e).success:false}var ot=createMiddleware(async(r,e)=>{if(!E(r))try{let t=await requireUser(A(r));r.set("user",t);}catch(t){return d(t,r)}await e();}),st=(...r)=>createMiddleware(async(e,t)=>{E(e)||e.set("user",await requireUserRole(A(e),...r)),await t();}),nt=(...r)=>createMiddleware(async(e,t)=>{E(e)||e.set("user",await requireUserPermission(A(e),...r)),await t();}),it=(...r)=>createMiddleware(async(e,t)=>{if(!E(e)){let o=extractBearerToken(A(e));o&&r.includes(o)&&e.set("user",te);}await t();});var M=class{options;constructor(e={}){this.options=e;}install(e){let t=new I;e.get("/health",t.checkHealth);}},I=class{checkHealth=e=>e.json({status:"UP"})};var ne=r=>{let e=r.indexOf("://")!==-1,o=r.replace(/[.+?^${}()|[\]\\]/g,i=>`\\${i}`).replace(/\*/g,".*"),s=e?`^${o}$`:`^https?://${o}$`;return new RegExp(s)},ie=createDebug("opble:core:CorsModule"),S=class{install(e){ie("CORS_ALLOW_ORIGIN:",n.CORS_ALLOW_ORIGIN),e.use("/*",cors({origin:t=>{for(let o of n.CORS_ALLOW_ORIGIN){if(o==="*")return t??"";if(t===o)return t;if(o.indexOf("*")!==-1){let s=ne(o);if(t&&s.test(t))return t}}return ""},allowHeaders:n.CORS_ALLOW_HEADERS,allowMethods:n.CORS_ALLOW_METHODS}));}};var T=createDebug("opble:core:rate-limiter"),b=class{constructor(e={paths:["/*"]}){this.options=e;}install(e){if(T("Use Rate Limiter:",n.USE_RATE_LIMIT),!n.USE_RATE_LIMIT)return;T("Installing RateLimiterModule with options:",this.options),T(`Rate limiting: ${n.RATE_LIMIT} requests per ${n.RATE_LIMIT_WINDOW} ms`);let t=rateLimiter({windowMs:n.RATE_LIMIT_WINDOW,limit:n.RATE_LIMIT,standardHeaders:"draft-7",keyGenerator:o=>o.req.header("x-forwarded-for")??"anonymous"});for(let o of this.options.paths)e.use(o,t);}};
|
|
2
|
+
export{$e as AppFactory,g as BaseController,S as CorsModule,L as CrudController,G as LoggerFactory,h as ModuleLoader,b as RateLimiterModule,M as ServiceStatusModule,ot as auth,it as authAllowKeys,nt as authAllowPermission,st as authAllowRole,Ke as getCurrentUser,f as log,v as setUp,d as tearDown};//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/controller/base.ts","../src/controller/crud.ts","../src/lib/debugger.ts","../src/lib/env.ts","../src/lib/logger.ts","../src/middleware/app.ts","../src/lib/loader.ts","../src/lib/app.ts","../src/lib/auth.ts","../src/middleware/auth.ts","../src/module/service-status.ts","../src/module/cors.ts","../src/module/rate-limiter.ts"],"names":["BaseController","CrudController","factory","repository","context","options","body","result","item","requestId","ResourceNotFoundError","ForbiddenError","debug","createDebug","commaSeparatedToArray","value","s","envSchema","z","val","n","env","createDefaultWinstonTransport","createWinstonLogger","transports","winstonLogger","CoreLogger","metadata","traceId","Timer","level","message","args","LoggerFactory","data","log","logger","toHttpError","err","ZodError","BadRequestError","isHttpError","InternalServerError","setUp","createMiddleware","next","timer","response","tearDown","code","status","ModuleLoader","_ModuleLoader","modules","app","module","createApp","Hono","AppFactory","getCurrentUser","user","systemUser","PublicUserFactory","toHeaderGetter","name","isAuthenticated","PublicUserSchema","auth","requireUser","e","authAllowRole","roles","requireUserRole","authAllowPermission","permissions","requireUserPermission","authAllowKeys","keys","token","extractBearerToken","ServiceStatusModule","handler","ServiceStatusHandler","wildcardToRegExp","pattern","hasScheme","wildcardReplaced","m","regexStr","CorsModule","cors","origin","allowedOrigin","re","RateLimiterModule","limiter","rateLimiter","c","path"],"mappings":"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","file":"index.js","sourcesContent":["export class BaseController {}\n","import { DynamoDBRepository, TableKey } from '@opble/repository-dynamodb';\nimport {\n Factory,\n ForbiddenError,\n HashMap,\n ResourceNotFoundError,\n} from '@opble/types';\nimport { z } from 'zod';\n\nimport { AppContext } from '../lib/types';\n\nimport { BaseController } from './base';\n\ntype View = (data: unknown) => HashMap;\n\ntype BaseOptions = {\n view?: View;\n};\n\ntype PayloadOptions = BaseOptions & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: z.ZodType<unknown, unknown, any>;\n};\n\ntype RequestIdOptions = {\n parseRequestId: (context: AppContext) => TableKey;\n};\n\ntype ResourcePolicyOptions<T extends HashMap> = {\n allow?: (context: AppContext, item: T) => boolean;\n};\n\ntype GetItemOptions = BaseOptions & RequestIdOptions;\ntype DeleteItemOptions = GetItemOptions;\n\ntype CreateItemOptions = PayloadOptions;\ntype UpdateItemOptions = PayloadOptions & RequestIdOptions;\n\nexport class CrudController<T extends HashMap> extends BaseController {\n constructor(\n protected factory: Factory<T>,\n private repository: DynamoDBRepository<T>\n ) {\n super();\n }\n\n createItem = async (context: AppContext, options: CreateItemOptions) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const item = await this.repository.save(this.factory.create(result.data));\n\n return context.json(options.view ? options.view(item) : item, 201);\n };\n\n updateItem = async (\n context: AppContext,\n options: UpdateItemOptions & ResourcePolicyOptions<T>\n ) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const requestId = options.parseRequestId(context);\n let item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n item = await this.repository.save(\n this.factory.create({\n ...item,\n ...result.data,\n })\n );\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n getItem = async (\n context: AppContext,\n options: GetItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n deleteItem = async (\n context: AppContext,\n options: DeleteItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n await this.repository.delete(requestId);\n return context.json(options.view ? options.view(item) : item);\n };\n}\n","import { createDebug } from '@opble/debug';\n\nexport const debug = createDebug('opble:core');\n","import { z } from 'zod';\n\nconst commaSeparatedToArray = (value: unknown) => {\n if (typeof value === 'string') {\n const items = value\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return items;\n }\n\n // If undefined or not a string, return empty array by default\n return [] as string[];\n};\n\nconst envSchema = z.object({\n LOGGER_TRANSPORT_DEFAULT: z.enum(['console', 'file']).default('console'),\n LOGGER_TRANSPORT_FILE: z.string().optional(),\n\n APP_BASE_PATH: z.string().optional(),\n\n CORS_ALLOW_ORIGIN: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['*']),\n CORS_ALLOW_HEADERS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['Content-Type', 'Authorization']),\n CORS_ALLOW_METHODS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),\n\n USE_RATE_LIMIT: z\n .transform((val) => {\n if (val === 'true' || val === '1') return true;\n if (val === 'false' || val === '0') return false;\n return Boolean(val);\n })\n .default(false),\n RATE_LIMIT_WINDOW: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 15 * 60 * 1000 : n; // default 15 minutes\n }, z.number())\n .default(15 * 60 * 1000),\n RATE_LIMIT: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 100 : n; // default 100 requests\n }, z.number())\n .default(100),\n});\n\nexport const env = envSchema.parse(process.env);\n","import { Timer } from '@opble/toolkit';\nimport { Factory, StringHashMap } from '@opble/types';\nimport { Logger } from '@opble/types';\nimport { Context } from 'hono';\nimport * as winston from 'winston';\n\nimport { env } from './env';\nimport { CoreEnv } from './types';\n\nconst createDefaultWinstonTransport = (): winston.transport => {\n if (env.LOGGER_TRANSPORT_DEFAULT === 'file' && env.LOGGER_TRANSPORT_FILE) {\n return new winston.transports.File({\n filename: env.LOGGER_TRANSPORT_FILE,\n });\n }\n\n return new winston.transports.Console();\n};\n\nconst createWinstonLogger = (...transports: winston.transport[]) =>\n winston.createLogger({\n level: 'info',\n format: winston.format.combine(\n winston.format.splat(),\n winston.format.timestamp(),\n winston.format.json()\n ),\n transports: transports.length\n ? transports\n : [createDefaultWinstonTransport()],\n });\n\nconst winstonLogger: winston.Logger = createWinstonLogger();\n\nclass CoreLogger implements Logger {\n private readonly logger: winston.Logger;\n private readonly traceId: string;\n private metadata: StringHashMap;\n private readonly timer: Timer;\n\n constructor(metadata: StringHashMap = {}) {\n const traceId = crypto.randomUUID();\n this.traceId = traceId;\n this.metadata = {\n traceId,\n ...metadata,\n };\n this.logger = winstonLogger.child(this.metadata);\n this.timer = new Timer();\n }\n\n private log(level: string, message: string, ...args: unknown[]): void {\n this.logger.log(level, message, ...args, { duration: this.timer.tock() });\n }\n\n debug(message: string, ...args: unknown[]): void {\n this.log('debug', message, ...args);\n }\n\n info(message: string, ...args: unknown[]): void {\n this.log('info', message, ...args);\n }\n\n warn(message: string, ...args: unknown[]): void {\n this.log('warn', message, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n this.log('error', message, ...args);\n }\n}\n\nexport const LoggerFactory: Factory<Logger> = {\n create(data: unknown): Logger {\n return new CoreLogger(data as StringHashMap);\n },\n};\n\nexport function log(context: Context<CoreEnv>): Logger {\n let logger = context.get('logger');\n if (!logger) {\n logger = LoggerFactory.create({});\n context.set('logger', logger);\n }\n\n return logger;\n}\n","import { Timer } from '@opble/toolkit';\nimport {\n BadRequestError,\n HttpError,\n InternalServerError,\n isHttpError,\n} from '@opble/types';\nimport { Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\nimport { ContentfulStatusCode } from 'hono/utils/http-status';\nimport z, { ZodError } from 'zod';\n\nimport { debug } from '../lib/debugger.js';\nimport { log } from '../lib/logger';\nimport { AppContext } from '../lib/types';\n\nfunction toHttpError(context: AppContext, e: unknown): HttpError {\n let err: HttpError;\n if (e instanceof ZodError) {\n err = BadRequestError;\n err.message = z.prettifyError(e);\n } else if (isHttpError(e)) {\n err = e as HttpError;\n } else {\n err = InternalServerError;\n log(context).error('Catch an error. Details: %s', e);\n }\n\n return err;\n}\n\nexport const setUp = createMiddleware(\n async (context: AppContext, next: Next) => {\n const timer = new Timer();\n timer.tick();\n\n try {\n log(context).info('[start] %s %s', context.req.method, context.req.path);\n await next();\n log(context).info('[end]', {\n status: context.res.status,\n duration: timer.tock(),\n });\n } catch (err) {\n const response = tearDown(err, context);\n log(context).info('[end]', {\n status: response.status,\n duration: timer.tock(),\n });\n\n return response;\n }\n }\n);\n\nexport const tearDown = (err: unknown, context: AppContext) => {\n debug('Tear down with error:', err);\n const { code, message, status } = toHttpError(context, err);\n return context.json({ code, message }, status as ContentfulStatusCode);\n};\n","import { debug } from './debugger.js';\nimport { App } from './types';\n\nexport interface Module {\n install(app: App): void;\n}\n\nexport class ModuleLoader {\n private modules: Module[];\n\n constructor(modules: Module[]) {\n this.modules = modules;\n }\n\n static load(app: App, ...modules: Module[]) {\n const loader = new ModuleLoader(modules);\n loader.modules.forEach((module) => {\n module.install(app);\n debug(\n 'Module is loaded => %s',\n `${Object.getPrototypeOf(module).constructor.name}`\n );\n });\n }\n}\n","import { Factory } from '@opble/types';\nimport { Hono } from 'hono';\n\nimport { setUp, tearDown } from '../middleware/app';\n\nimport { debug } from './debugger';\nimport { env } from './env';\nimport { Module, ModuleLoader } from './loader';\nimport { App, CoreEnv } from './types';\n\nfunction createApp(...modules: Module[]) {\n let app: App;\n if (env.APP_BASE_PATH) {\n app = new Hono<CoreEnv>().basePath(env.APP_BASE_PATH);\n debug(`App base path set to '${env.APP_BASE_PATH}'`);\n } else {\n app = new Hono<CoreEnv>();\n }\n\n app.use(setUp);\n ModuleLoader.load(app, ...modules);\n app.onError(tearDown);\n\n return app;\n}\n\nexport const AppFactory: Factory<App> = {\n create: (data: unknown) => {\n if (data && Array.isArray(data)) {\n return createApp(...data);\n }\n\n return new Hono<CoreEnv>();\n },\n};\n","import { PublicUser } from '@opble/entity-auth';\nimport { Context } from 'hono';\n\nimport { CoreEnv } from './types';\n\nexport function getCurrentUser(context: Context<CoreEnv>): PublicUser {\n const user = context.get('user');\n if (!user) {\n throw new Error('User not found');\n }\n return user;\n}\n","import {\n requireUser,\n requireUserRole,\n requireUserPermission,\n extractBearerToken,\n} from '@opble/auth0';\nimport { PublicUserFactory, PublicUserSchema } from '@opble/entity-auth';\nimport { Context, Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\n\nimport { CoreEnv } from '../lib/types';\n\nimport { tearDown } from './app';\n\nconst systemUser = PublicUserFactory.create({\n id: 'system',\n name: 'System',\n email: 'system@wewise.net',\n role: 'admin',\n emailVerified: true,\n});\nconst toHeaderGetter = (context: Context<CoreEnv>) => {\n return {\n get: (name: string) => context.req.header(name),\n };\n};\n\nfunction isAuthenticated(context: Context<CoreEnv>): boolean {\n const user = context.get('user');\n if (!user) {\n return false;\n }\n\n return PublicUserSchema.safeParse(user).success;\n}\n\nexport const auth = createMiddleware(\n async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n try {\n const user = await requireUser(toHeaderGetter(context));\n context.set('user', user);\n } catch (e) {\n return tearDown(e, context);\n }\n }\n\n await next();\n }\n);\n\nexport const authAllowRole = (...roles: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserRole(toHeaderGetter(context), ...roles)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowPermission = (...permissions: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserPermission(toHeaderGetter(context), ...permissions)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowKeys = (...keys: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n const token = extractBearerToken(toHeaderGetter(context));\n if (token && keys.includes(token)) {\n context.set('user', systemUser);\n }\n }\n\n await next();\n });\n};\n","import { HashMap } from '@opble/types';\n\nimport { UP } from '../lib/constant';\nimport { Module } from '../lib/loader';\nimport { App, AppContext } from '../lib/types';\n\nexport type ServiceStatusOptions = HashMap;\n\nexport class ServiceStatusModule implements Module {\n private options: ServiceStatusOptions;\n\n constructor(options: ServiceStatusOptions = {}) {\n this.options = options;\n }\n\n install(app: App) {\n const handler = new ServiceStatusHandler();\n app.get('/health', handler.checkHealth);\n }\n}\n\nclass ServiceStatusHandler {\n checkHealth = (context: AppContext) => {\n return context.json({\n status: UP,\n });\n };\n}\n","import { createDebug } from '@opble/debug';\nimport { cors } from 'hono/cors';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\n// Convert wildcard pattern like \"https://*.wewise.net\" into a RegExp\nconst wildcardToRegExp = (pattern: string): RegExp => {\n // If pattern doesn't include scheme, allow http(s)\n const hasScheme = pattern.indexOf('://') !== -1;\n // Escape regexp special chars except '*'\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, (m) => `\\\\${m}`);\n // Now replace escaped '*' (which would be '\\*') with '.*'\n const wildcardReplaced = escaped.replace(/\\*/g, '.*');\n const regexStr = hasScheme\n ? `^${wildcardReplaced}$`\n : `^https?://${wildcardReplaced}$`;\n return new RegExp(regexStr);\n};\n\nconst debug = createDebug('opble:core:CorsModule');\n\nexport class CorsModule implements Module {\n install(app: App) {\n debug('CORS_ALLOW_ORIGIN:', env.CORS_ALLOW_ORIGIN);\n app.use(\n '/*',\n cors({\n origin: (origin) => {\n for (const allowedOrigin of env.CORS_ALLOW_ORIGIN) {\n if (allowedOrigin === '*') {\n return origin ?? '';\n }\n\n // Direct match\n if (origin === allowedOrigin) {\n return origin;\n }\n\n // Wildcard matching\n if (allowedOrigin.indexOf('*') !== -1) {\n const re = wildcardToRegExp(allowedOrigin);\n if (origin && re.test(origin)) {\n return origin;\n }\n }\n }\n\n return '';\n },\n allowHeaders: env.CORS_ALLOW_HEADERS,\n allowMethods: env.CORS_ALLOW_METHODS,\n })\n );\n }\n}\n","import { createDebug } from '@opble/debug';\nimport { rateLimiter } from 'hono-rate-limiter';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\nconst debug = createDebug('opble:core:rate-limiter');\n\nexport type RateLimiterModuleOptions = {\n paths: string[];\n};\n\nexport class RateLimiterModule implements Module {\n constructor(private options: RateLimiterModuleOptions = { paths: ['/*'] }) {}\n\n install(app: App) {\n debug('Use Rate Limiter:', env.USE_RATE_LIMIT);\n if (!env.USE_RATE_LIMIT) {\n return;\n }\n\n debug('Installing RateLimiterModule with options:', this.options);\n debug(\n `Rate limiting: ${env.RATE_LIMIT} requests per ${env.RATE_LIMIT_WINDOW} ms`\n );\n\n /**\n * Notes:\n * - The rate limiter is applied to the specified paths.\n * - The limit and window are configurable via environment variables.\n * - The key generator uses the \"x-forwarded-for\" header to identify clients behind proxies.\n *\n * Important:\n * - RateLimiterModule must be installed before other modules so it could be executed first.\n */\n const limiter = rateLimiter({\n windowMs: env.RATE_LIMIT_WINDOW,\n limit: env.RATE_LIMIT,\n standardHeaders: 'draft-7',\n keyGenerator: (c) => c.req.header('x-forwarded-for') ?? 'anonymous',\n });\n for (const path of this.options.paths) {\n app.use(path, limiter);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/controller/base.ts","../src/controller/crud.ts","../src/lib/debugger.ts","../src/lib/env.ts","../src/lib/logger.ts","../src/middleware/app.ts","../src/lib/loader.ts","../src/lib/app.ts","../src/lib/auth.ts","../src/middleware/auth.ts","../src/module/service-status.ts","../src/module/cors.ts","../src/module/rate-limiter.ts"],"names":["BaseController","CrudController","factory","repository","context","options","body","result","item","requestId","ResourceNotFoundError","ForbiddenError","debug","createDebug","commaSeparatedToArray","value","s","envSchema","z","val","n","env","createDefaultWinstonTransport","createWinstonLogger","transports","winstonLogger","CoreLogger","metadata","traceId","Timer","level","message","args","LoggerFactory","data","log","logger","toHttpError","err","ZodError","BadRequestError","isHttpError","InternalServerError","setUp","createMiddleware","next","timer","response","tearDown","code","status","ModuleLoader","_ModuleLoader","modules","app","module","createApp","Hono","AppFactory","getCurrentUser","user","systemUser","PublicUserFactory","toHeaderGetter","name","isAuthenticated","PublicUserSchema","auth","requireUser","e","authAllowRole","roles","requireUserRole","authAllowPermission","permissions","requireUserPermission","authAllowKeys","keys","token","extractBearerToken","ServiceStatusModule","handler","ServiceStatusHandler","wildcardToRegExp","pattern","hasScheme","wildcardReplaced","m","regexStr","CorsModule","cors","origin","allowedOrigin","re","RateLimiterModule","limiter","rateLimiter","c","path"],"mappings":"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","file":"index.js","sourcesContent":["export class BaseController {}\n","import { DynamoDBRepository, TableKey } from '@opble/repository-dynamodb';\nimport {\n Factory,\n ForbiddenError,\n HashMap,\n ResourceNotFoundError,\n} from '@opble/types';\nimport { z } from 'zod';\n\nimport { AppContext } from '../lib/types';\n\nimport { BaseController } from './base';\n\ntype View = (data: unknown) => HashMap;\n\ntype BaseOptions = {\n view?: View;\n};\n\ntype PayloadOptions = BaseOptions & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: z.ZodType<unknown, unknown, any>;\n};\n\ntype RequestIdOptions = {\n parseRequestId: (context: AppContext) => TableKey;\n};\n\ntype ResourcePolicyOptions<T extends HashMap> = {\n allow?: (context: AppContext, item: T) => boolean;\n};\n\ntype GetItemOptions = BaseOptions & RequestIdOptions;\ntype DeleteItemOptions = GetItemOptions;\n\ntype CreateItemOptions = PayloadOptions;\ntype UpdateItemOptions = PayloadOptions & RequestIdOptions;\n\nexport class CrudController<T extends HashMap> extends BaseController {\n constructor(\n protected factory: Factory<T>,\n private repository: DynamoDBRepository<T>\n ) {\n super();\n }\n\n createItem = async (context: AppContext, options: CreateItemOptions) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const item = await this.repository.save(this.factory.create(result.data));\n\n return context.json(options.view ? options.view(item) : item, 201);\n };\n\n updateItem = async (\n context: AppContext,\n options: UpdateItemOptions & ResourcePolicyOptions<T>\n ) => {\n const body = await context.req.json();\n const result = await options.schema.safeParseAsync(body);\n if (!result.success) {\n throw result.error;\n }\n\n const requestId = options.parseRequestId(context);\n let item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n item = await this.repository.save(\n this.factory.create({\n ...item,\n ...result.data,\n })\n );\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n getItem = async (\n context: AppContext,\n options: GetItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n return context.json(options.view ? options.view(item) : item);\n };\n\n deleteItem = async (\n context: AppContext,\n options: DeleteItemOptions & ResourcePolicyOptions<T>\n ) => {\n const requestId = options.parseRequestId(context);\n const item = await this.repository.get(requestId);\n if (!item) {\n throw ResourceNotFoundError;\n }\n if (options.allow && !options.allow(context, item)) {\n throw ForbiddenError;\n }\n\n await this.repository.delete(requestId);\n return context.json(options.view ? options.view(item) : item);\n };\n}\n","import { createDebug } from '@opble/debug';\n\nexport const debug = createDebug('opble:core');\n","import { z } from 'zod';\n\nconst commaSeparatedToArray = (value: unknown) => {\n if (typeof value === 'string') {\n const items = value\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return items;\n }\n\n // If undefined or not a string, return empty array by default\n return [] as string[];\n};\n\nconst envSchema = z.object({\n LOGGER_TRANSPORT_DEFAULT: z.enum(['console', 'file']).default('console'),\n LOGGER_TRANSPORT_FILE: z.string().optional(),\n\n APP_BASE_PATH: z.string().optional(),\n\n CORS_ALLOW_ORIGIN: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['*']),\n CORS_ALLOW_HEADERS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['Content-Type', 'Authorization']),\n CORS_ALLOW_METHODS: z\n .preprocess(commaSeparatedToArray, z.array(z.string()))\n .default(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),\n\n USE_RATE_LIMIT: z\n .transform((val) => {\n if (val === 'true' || val === '1') return true;\n if (val === 'false' || val === '0') return false;\n return Boolean(val);\n })\n .default(false),\n RATE_LIMIT_WINDOW: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 15 * 60 * 1000 : n; // default 15 minutes\n }, z.number())\n .default(15 * 60 * 1000),\n RATE_LIMIT: z\n .preprocess((val) => {\n const n = Number(val);\n return isNaN(n) ? 100 : n; // default 100 requests\n }, z.number())\n .default(100),\n});\n\nexport const env = envSchema.parse(process.env);\n","import { Timer } from '@opble/toolkit';\nimport { Factory, StringHashMap } from '@opble/types';\nimport { Logger } from '@opble/types';\nimport { Context } from 'hono';\nimport * as winston from 'winston';\n\nimport { env } from './env';\nimport { CoreEnv } from './types';\n\nconst createDefaultWinstonTransport = (): winston.transport => {\n if (env.LOGGER_TRANSPORT_DEFAULT === 'file' && env.LOGGER_TRANSPORT_FILE) {\n return new winston.transports.File({\n filename: env.LOGGER_TRANSPORT_FILE,\n });\n }\n\n return new winston.transports.Console();\n};\n\nconst createWinstonLogger = (...transports: winston.transport[]) =>\n winston.createLogger({\n level: 'info',\n format: winston.format.combine(\n winston.format.splat(),\n winston.format.timestamp(),\n winston.format.json()\n ),\n transports: transports.length\n ? transports\n : [createDefaultWinstonTransport()],\n });\n\nconst winstonLogger: winston.Logger = createWinstonLogger();\n\nclass CoreLogger implements Logger {\n private readonly logger: winston.Logger;\n private readonly traceId: string;\n private metadata: StringHashMap;\n private readonly timer: Timer;\n\n constructor(metadata: StringHashMap = {}) {\n const traceId = crypto.randomUUID();\n this.traceId = traceId;\n this.metadata = {\n traceId,\n ...metadata,\n };\n this.logger = winstonLogger.child(this.metadata);\n this.timer = new Timer();\n }\n\n private log(level: string, message: string, ...args: unknown[]): void {\n this.logger.log(level, message, ...args, { duration: this.timer.tock() });\n }\n\n debug(message: string, ...args: unknown[]): void {\n this.log('debug', message, ...args);\n }\n\n info(message: string, ...args: unknown[]): void {\n this.log('info', message, ...args);\n }\n\n warn(message: string, ...args: unknown[]): void {\n this.log('warn', message, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n this.log('error', message, ...args);\n }\n}\n\nexport const LoggerFactory: Factory<Logger> = {\n create(data: unknown): Logger {\n return new CoreLogger(data as StringHashMap);\n },\n};\n\nexport function log(context: Context<CoreEnv>): Logger {\n let logger = context.get('logger');\n if (!logger) {\n logger = LoggerFactory.create({});\n context.set('logger', logger);\n }\n\n return logger;\n}\n","import { Timer } from '@opble/toolkit';\nimport {\n BadRequestError,\n HttpError,\n InternalServerError,\n isHttpError,\n} from '@opble/types';\nimport { Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\nimport { ContentfulStatusCode } from 'hono/utils/http-status';\nimport z, { ZodError } from 'zod';\n\nimport { debug } from '../lib/debugger.js';\nimport { log } from '../lib/logger';\nimport { AppContext } from '../lib/types';\n\nfunction toHttpError(context: AppContext, e: unknown): HttpError {\n let err: HttpError;\n if (e instanceof ZodError) {\n err = BadRequestError;\n err.message = z.prettifyError(e);\n } else if (isHttpError(e)) {\n err = e as HttpError;\n } else {\n err = InternalServerError;\n log(context).error('Catch an error. Details: %s', e);\n }\n\n return err;\n}\n\nexport const setUp = createMiddleware(\n async (context: AppContext, next: Next) => {\n const timer = new Timer();\n timer.tick();\n\n try {\n log(context).info('[start] %s %s', context.req.method, context.req.path);\n await next();\n log(context).info('[end]', {\n status: context.res.status,\n duration: timer.tock(),\n });\n } catch (err) {\n const response = tearDown(err, context);\n log(context).info('[end]', {\n status: response.status,\n duration: timer.tock(),\n });\n\n return response;\n }\n }\n);\n\nexport const tearDown = (err: unknown, context: AppContext) => {\n debug('Tear down with error:', err);\n const { code, message, status } = toHttpError(context, err);\n return context.json({ code, message }, status as ContentfulStatusCode);\n};\n","import { debug } from './debugger.js';\nimport { App } from './types';\n\nexport interface Module {\n install(app: App): void;\n}\n\nexport class ModuleLoader {\n private modules: Module[];\n\n constructor(modules: Module[]) {\n this.modules = modules;\n }\n\n static load(app: App, ...modules: Module[]) {\n const loader = new ModuleLoader(modules);\n loader.modules.forEach((module) => {\n module.install(app);\n debug(\n 'Module is loaded => %s',\n `${Object.getPrototypeOf(module).constructor.name}`\n );\n });\n }\n}\n","import { Factory } from '@opble/types';\nimport { Hono } from 'hono';\n\nimport { setUp, tearDown } from '../middleware/app';\n\nimport { debug } from './debugger';\nimport { env } from './env';\nimport { Module, ModuleLoader } from './loader';\nimport { App, CoreEnv } from './types';\n\nfunction createApp(...modules: Module[]): App {\n let app;\n if (env.APP_BASE_PATH) {\n app = new Hono<CoreEnv>().basePath(env.APP_BASE_PATH);\n debug(`App base path set to '${env.APP_BASE_PATH}'`);\n } else {\n app = new Hono<CoreEnv>();\n }\n\n app.use(setUp);\n ModuleLoader.load(app, ...modules);\n app.onError(tearDown);\n\n return app;\n}\n\nexport const AppFactory: Factory<App> = {\n create: (data: unknown): App => {\n if (data && Array.isArray(data)) {\n return createApp(...data);\n }\n\n return createApp();\n },\n};\n","import { PublicUser } from '@opble/entity-auth';\nimport { Context } from 'hono';\n\nimport { CoreEnv } from './types';\n\nexport function getCurrentUser(context: Context<CoreEnv>): PublicUser {\n const user = context.get('user');\n if (!user) {\n throw new Error('User not found');\n }\n return user;\n}\n","import {\n requireUser,\n requireUserRole,\n requireUserPermission,\n extractBearerToken,\n} from '@opble/auth0';\nimport { PublicUserFactory, PublicUserSchema } from '@opble/entity-auth';\nimport { Context, Next } from 'hono';\nimport { createMiddleware } from 'hono/factory';\n\nimport { CoreEnv } from '../lib/types';\n\nimport { tearDown } from './app';\n\nconst systemUser = PublicUserFactory.create({\n id: 'system',\n name: 'System',\n email: 'system@wewise.net',\n role: 'admin',\n emailVerified: true,\n});\nconst toHeaderGetter = (context: Context<CoreEnv>) => {\n return {\n get: (name: string) => context.req.header(name),\n };\n};\n\nfunction isAuthenticated(context: Context<CoreEnv>): boolean {\n const user = context.get('user');\n if (!user) {\n return false;\n }\n\n return PublicUserSchema.safeParse(user).success;\n}\n\nexport const auth = createMiddleware(\n async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n try {\n const user = await requireUser(toHeaderGetter(context));\n context.set('user', user);\n } catch (e) {\n return tearDown(e, context);\n }\n }\n\n await next();\n }\n);\n\nexport const authAllowRole = (...roles: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserRole(toHeaderGetter(context), ...roles)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowPermission = (...permissions: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n context.set(\n 'user',\n await requireUserPermission(toHeaderGetter(context), ...permissions)\n );\n }\n\n await next();\n });\n};\n\nexport const authAllowKeys = (...keys: string[]) => {\n return createMiddleware(async (context: Context<CoreEnv>, next: Next) => {\n if (!isAuthenticated(context)) {\n const token = extractBearerToken(toHeaderGetter(context));\n if (token && keys.includes(token)) {\n context.set('user', systemUser);\n }\n }\n\n await next();\n });\n};\n","import { HashMap } from '@opble/types';\n\nimport { UP } from '../lib/constant';\nimport { Module } from '../lib/loader';\nimport { App, AppContext } from '../lib/types';\n\nexport type ServiceStatusOptions = HashMap;\n\nexport class ServiceStatusModule implements Module {\n private options: ServiceStatusOptions;\n\n constructor(options: ServiceStatusOptions = {}) {\n this.options = options;\n }\n\n install(app: App) {\n const handler = new ServiceStatusHandler();\n app.get('/health', handler.checkHealth);\n }\n}\n\nclass ServiceStatusHandler {\n checkHealth = (context: AppContext) => {\n return context.json({\n status: UP,\n });\n };\n}\n","import { createDebug } from '@opble/debug';\nimport { cors } from 'hono/cors';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\n// Convert wildcard pattern like \"https://*.wewise.net\" into a RegExp\nconst wildcardToRegExp = (pattern: string): RegExp => {\n // If pattern doesn't include scheme, allow http(s)\n const hasScheme = pattern.indexOf('://') !== -1;\n // Escape regexp special chars except '*'\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, (m) => `\\\\${m}`);\n // Now replace escaped '*' (which would be '\\*') with '.*'\n const wildcardReplaced = escaped.replace(/\\*/g, '.*');\n const regexStr = hasScheme\n ? `^${wildcardReplaced}$`\n : `^https?://${wildcardReplaced}$`;\n return new RegExp(regexStr);\n};\n\nconst debug = createDebug('opble:core:CorsModule');\n\nexport class CorsModule implements Module {\n install(app: App) {\n debug('CORS_ALLOW_ORIGIN:', env.CORS_ALLOW_ORIGIN);\n app.use(\n '/*',\n cors({\n origin: (origin) => {\n for (const allowedOrigin of env.CORS_ALLOW_ORIGIN) {\n if (allowedOrigin === '*') {\n return origin ?? '';\n }\n\n // Direct match\n if (origin === allowedOrigin) {\n return origin;\n }\n\n // Wildcard matching\n if (allowedOrigin.indexOf('*') !== -1) {\n const re = wildcardToRegExp(allowedOrigin);\n if (origin && re.test(origin)) {\n return origin;\n }\n }\n }\n\n return '';\n },\n allowHeaders: env.CORS_ALLOW_HEADERS,\n allowMethods: env.CORS_ALLOW_METHODS,\n })\n );\n }\n}\n","import { createDebug } from '@opble/debug';\nimport { rateLimiter } from 'hono-rate-limiter';\n\nimport { env } from '../lib/env';\nimport { Module } from '../lib/loader';\nimport { App } from '../lib/types';\n\nconst debug = createDebug('opble:core:rate-limiter');\n\nexport type RateLimiterModuleOptions = {\n paths: string[];\n};\n\nexport class RateLimiterModule implements Module {\n constructor(private options: RateLimiterModuleOptions = { paths: ['/*'] }) {}\n\n install(app: App) {\n debug('Use Rate Limiter:', env.USE_RATE_LIMIT);\n if (!env.USE_RATE_LIMIT) {\n return;\n }\n\n debug('Installing RateLimiterModule with options:', this.options);\n debug(\n `Rate limiting: ${env.RATE_LIMIT} requests per ${env.RATE_LIMIT_WINDOW} ms`\n );\n\n /**\n * Notes:\n * - The rate limiter is applied to the specified paths.\n * - The limit and window are configurable via environment variables.\n * - The key generator uses the \"x-forwarded-for\" header to identify clients behind proxies.\n *\n * Important:\n * - RateLimiterModule must be installed before other modules so it could be executed first.\n */\n const limiter = rateLimiter({\n windowMs: env.RATE_LIMIT_WINDOW,\n limit: env.RATE_LIMIT,\n standardHeaders: 'draft-7',\n keyGenerator: (c) => c.req.header('x-forwarded-for') ?? 'anonymous',\n });\n for (const path of this.options.paths) {\n app.use(path, limiter);\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opble/core",
|
|
3
3
|
"description": "Provide core utilities and core components.",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.cjs",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"provenance": false
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@opble/
|
|
38
|
-
"@opble/
|
|
37
|
+
"@opble/eslint-config": "0.0.0",
|
|
38
|
+
"@opble/typescript-config": "0.0.0"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@opble/auth0": "^1.0.0",
|