@opble/core 1.0.0

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.
@@ -0,0 +1,115 @@
1
+ import * as hono_utils_http_status from 'hono/utils/http-status';
2
+ import * as hono from 'hono';
3
+ import { Context, Hono } from 'hono';
4
+ import * as hono_utils_types from 'hono/utils/types';
5
+ import { Logger, HashMap, Factory } from '@opble/types';
6
+ import { z } from 'zod';
7
+ import { PublicUser } from '@opble/entity-auth';
8
+ import { DynamoDBRepository, TableKey } from '@opble/repository-dynamodb';
9
+
10
+ declare class BaseController {
11
+ }
12
+
13
+ type CoreVariables = {
14
+ logger?: Logger;
15
+ user?: PublicUser;
16
+ };
17
+ type CoreEnv = {
18
+ Variables: CoreVariables;
19
+ };
20
+ type AppContext = Context<CoreEnv>;
21
+ type App = Hono<CoreEnv>;
22
+
23
+ type View = (data: unknown) => HashMap;
24
+ type BaseOptions = {
25
+ view?: View;
26
+ };
27
+ type PayloadOptions = BaseOptions & {
28
+ schema: z.ZodType<unknown, unknown, any>;
29
+ };
30
+ type RequestIdOptions = {
31
+ parseRequestId: (context: AppContext) => TableKey;
32
+ };
33
+ type ResourcePolicyOptions<T extends HashMap> = {
34
+ allow?: (context: AppContext, item: T) => boolean;
35
+ };
36
+ type GetItemOptions = BaseOptions & RequestIdOptions;
37
+ type DeleteItemOptions = GetItemOptions;
38
+ type CreateItemOptions = PayloadOptions;
39
+ type UpdateItemOptions = PayloadOptions & RequestIdOptions;
40
+ declare class CrudController<T extends HashMap> extends BaseController {
41
+ protected factory: Factory<T>;
42
+ private repository;
43
+ constructor(factory: Factory<T>, repository: DynamoDBRepository<T>);
44
+ createItem: (context: AppContext, options: CreateItemOptions) => Promise<Response & hono.TypedResponse<{
45
+ [x: string]: hono_utils_types.JSONValue;
46
+ }, 201, "json">>;
47
+ updateItem: (context: AppContext, options: UpdateItemOptions & ResourcePolicyOptions<T>) => Promise<Response & hono.TypedResponse<{
48
+ [x: string]: hono_utils_types.JSONValue;
49
+ }, hono_utils_http_status.ContentfulStatusCode, "json">>;
50
+ getItem: (context: AppContext, options: GetItemOptions & ResourcePolicyOptions<T>) => Promise<Response & hono.TypedResponse<{
51
+ [x: string]: hono_utils_types.JSONValue;
52
+ }, hono_utils_http_status.ContentfulStatusCode, "json">>;
53
+ deleteItem: (context: AppContext, options: DeleteItemOptions & ResourcePolicyOptions<T>) => Promise<Response & hono.TypedResponse<{
54
+ [x: string]: hono_utils_types.JSONValue;
55
+ }, hono_utils_http_status.ContentfulStatusCode, "json">>;
56
+ }
57
+
58
+ declare const AppFactory: Factory<App>;
59
+
60
+ declare function getCurrentUser(context: Context<CoreEnv>): PublicUser;
61
+
62
+ interface EventHandler {
63
+ handle(event: string, payload: HashMap): Promise<void>;
64
+ }
65
+
66
+ interface Module {
67
+ install(app: App): void;
68
+ }
69
+ declare class ModuleLoader {
70
+ private modules;
71
+ constructor(modules: Module[]);
72
+ static load(app: App, ...modules: Module[]): void;
73
+ }
74
+
75
+ declare const LoggerFactory: Factory<Logger>;
76
+ declare function log(context: Context<CoreEnv>): Logger;
77
+
78
+ declare const setUp: hono.MiddlewareHandler<CoreEnv, any, {}, Response | (Response & hono.TypedResponse<{
79
+ code: string;
80
+ message: string;
81
+ }, 201 | 100 | 102 | 103 | 200 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | -1, "json">)>;
82
+ declare const tearDown: (err: unknown, context: AppContext) => Response & hono.TypedResponse<{
83
+ code: string;
84
+ message: string;
85
+ }, 201 | 100 | 102 | 103 | 200 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | -1, "json">;
86
+
87
+ declare const auth: hono.MiddlewareHandler<CoreEnv, any, {}, Response | (Response & hono.TypedResponse<{
88
+ code: string;
89
+ message: string;
90
+ }, 201 | 100 | 102 | 103 | 200 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | -1, "json">)>;
91
+ declare const authAllowRole: (...roles: string[]) => hono.MiddlewareHandler<CoreEnv, any, {}, Response>;
92
+ declare const authAllowPermission: (...permissions: string[]) => hono.MiddlewareHandler<CoreEnv, any, {}, Response>;
93
+ declare const authAllowKeys: (...keys: string[]) => hono.MiddlewareHandler<CoreEnv, any, {}, Response>;
94
+
95
+ type ServiceStatusOptions = HashMap;
96
+ declare class ServiceStatusModule implements Module {
97
+ private options;
98
+ constructor(options?: ServiceStatusOptions);
99
+ install(app: App): void;
100
+ }
101
+
102
+ declare class CorsModule implements Module {
103
+ install(app: App): void;
104
+ }
105
+
106
+ type RateLimiterModuleOptions = {
107
+ paths: string[];
108
+ };
109
+ declare class RateLimiterModule implements Module {
110
+ private options;
111
+ constructor(options?: RateLimiterModuleOptions);
112
+ install(app: App): void;
113
+ }
114
+
115
+ export { type App, type AppContext, AppFactory, BaseController, type CoreEnv, type CoreVariables, CorsModule, CrudController, type EventHandler, LoggerFactory, type Module, ModuleLoader, RateLimiterModule, type RateLimiterModuleOptions, ServiceStatusModule, type ServiceStatusOptions, auth, authAllowKeys, authAllowPermission, authAllowRole, getCurrentUser, log, setUp, tearDown };
package/dist/index.js ADDED
@@ -0,0 +1,464 @@
1
+ // src/controller/base.ts
2
+ var BaseController = class {
3
+ };
4
+
5
+ // src/controller/crud.ts
6
+ import {
7
+ ForbiddenError,
8
+ ResourceNotFoundError
9
+ } from "@opble/types";
10
+ var CrudController = class extends BaseController {
11
+ constructor(factory, repository) {
12
+ super();
13
+ this.factory = factory;
14
+ this.repository = repository;
15
+ }
16
+ createItem = async (context, options) => {
17
+ const body = await context.req.json();
18
+ const result = await options.schema.safeParseAsync(body);
19
+ if (!result.success) {
20
+ throw result.error;
21
+ }
22
+ const item = await this.repository.save(this.factory.create(result.data));
23
+ return context.json(options.view ? options.view(item) : item, 201);
24
+ };
25
+ updateItem = async (context, options) => {
26
+ const body = await context.req.json();
27
+ const result = await options.schema.safeParseAsync(body);
28
+ if (!result.success) {
29
+ throw result.error;
30
+ }
31
+ const requestId = options.parseRequestId(context);
32
+ let item = await this.repository.get(requestId);
33
+ if (!item) {
34
+ throw ResourceNotFoundError;
35
+ }
36
+ if (options.allow && !options.allow(context, item)) {
37
+ throw ForbiddenError;
38
+ }
39
+ item = await this.repository.save(
40
+ this.factory.create({
41
+ ...item,
42
+ ...result.data
43
+ })
44
+ );
45
+ return context.json(options.view ? options.view(item) : item);
46
+ };
47
+ getItem = async (context, options) => {
48
+ const requestId = options.parseRequestId(context);
49
+ const item = await this.repository.get(requestId);
50
+ if (!item) {
51
+ throw ResourceNotFoundError;
52
+ }
53
+ if (options.allow && !options.allow(context, item)) {
54
+ throw ForbiddenError;
55
+ }
56
+ return context.json(options.view ? options.view(item) : item);
57
+ };
58
+ deleteItem = async (context, options) => {
59
+ const requestId = options.parseRequestId(context);
60
+ const item = await this.repository.get(requestId);
61
+ if (!item) {
62
+ throw ResourceNotFoundError;
63
+ }
64
+ if (options.allow && !options.allow(context, item)) {
65
+ throw ForbiddenError;
66
+ }
67
+ await this.repository.delete(requestId);
68
+ return context.json(options.view ? options.view(item) : item);
69
+ };
70
+ };
71
+
72
+ // src/lib/app.ts
73
+ import { Hono } from "hono";
74
+
75
+ // src/middleware/app.ts
76
+ import {
77
+ BadRequestError,
78
+ InternalServerError,
79
+ isHttpError
80
+ } from "@opble/types";
81
+ import { Timer as Timer2 } from "@opble/toolkit";
82
+ import { createMiddleware } from "hono/factory";
83
+ import z2, { ZodError } from "zod";
84
+
85
+ // src/lib/debugger.ts
86
+ import { createDebug } from "@opble/debug";
87
+ var debug = createDebug("opble:core");
88
+
89
+ // src/lib/logger.ts
90
+ import { Timer } from "@opble/toolkit";
91
+ import * as winston from "winston";
92
+
93
+ // src/lib/env.ts
94
+ import { z } from "zod";
95
+ var commaSeparatedToArray = (value) => {
96
+ if (typeof value === "string") {
97
+ const items = value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
98
+ return items;
99
+ }
100
+ return [];
101
+ };
102
+ var envSchema = z.object({
103
+ LOGGER_TRANSPORT_DEFAULT: z.enum(["console", "file"]).default("console"),
104
+ LOGGER_TRANSPORT_FILE: z.string().optional(),
105
+ APP_BASE_PATH: z.string().optional(),
106
+ CORS_ALLOW_ORIGIN: z.preprocess(commaSeparatedToArray, z.array(z.string())).default(["*"]),
107
+ CORS_ALLOW_HEADERS: z.preprocess(commaSeparatedToArray, z.array(z.string())).default(["Content-Type", "Authorization"]),
108
+ CORS_ALLOW_METHODS: z.preprocess(commaSeparatedToArray, z.array(z.string())).default(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]),
109
+ USE_RATE_LIMIT: z.transform((val) => {
110
+ if (val === "true" || val === "1") return true;
111
+ if (val === "false" || val === "0") return false;
112
+ return Boolean(val);
113
+ }).default(false),
114
+ RATE_LIMIT_WINDOW: z.preprocess((val) => {
115
+ const n = Number(val);
116
+ return isNaN(n) ? 15 * 60 * 1e3 : n;
117
+ }, z.number()).default(15 * 60 * 1e3),
118
+ RATE_LIMIT: z.preprocess((val) => {
119
+ const n = Number(val);
120
+ return isNaN(n) ? 100 : n;
121
+ }, z.number()).default(100)
122
+ });
123
+ var env = envSchema.parse(process.env);
124
+
125
+ // src/lib/logger.ts
126
+ var createDefaultWinstonTransport = () => {
127
+ if (env.LOGGER_TRANSPORT_DEFAULT === "file" && env.LOGGER_TRANSPORT_FILE) {
128
+ return new winston.transports.File({
129
+ filename: env.LOGGER_TRANSPORT_FILE
130
+ });
131
+ }
132
+ return new winston.transports.Console();
133
+ };
134
+ var createWinstonLogger = (...transports2) => winston.createLogger({
135
+ level: "info",
136
+ format: winston.format.combine(
137
+ winston.format.splat(),
138
+ winston.format.timestamp(),
139
+ winston.format.json()
140
+ ),
141
+ transports: transports2.length ? transports2 : [createDefaultWinstonTransport()]
142
+ });
143
+ var winstonLogger = createWinstonLogger();
144
+ var CoreLogger = class {
145
+ logger;
146
+ traceId;
147
+ metadata;
148
+ timer;
149
+ constructor(metadata = {}) {
150
+ const traceId = crypto.randomUUID();
151
+ this.traceId = traceId;
152
+ this.metadata = {
153
+ traceId,
154
+ ...metadata
155
+ };
156
+ this.logger = winstonLogger.child(this.metadata);
157
+ this.timer = new Timer();
158
+ }
159
+ log(level, message, ...args) {
160
+ this.logger.log(level, message, ...args, { duration: this.timer.tock() });
161
+ }
162
+ debug(message, ...args) {
163
+ this.log("debug", message, ...args);
164
+ }
165
+ info(message, ...args) {
166
+ this.log("info", message, ...args);
167
+ }
168
+ warn(message, ...args) {
169
+ this.log("warn", message, ...args);
170
+ }
171
+ error(message, ...args) {
172
+ this.log("error", message, ...args);
173
+ }
174
+ };
175
+ var LoggerFactory = {
176
+ create(data) {
177
+ return new CoreLogger(data);
178
+ }
179
+ };
180
+ function log(context) {
181
+ let logger = context.get("logger");
182
+ if (!logger) {
183
+ logger = LoggerFactory.create({});
184
+ context.set("logger", logger);
185
+ }
186
+ return logger;
187
+ }
188
+
189
+ // src/middleware/app.ts
190
+ function toHttpError(context, e) {
191
+ let err;
192
+ if (e instanceof ZodError) {
193
+ err = BadRequestError;
194
+ err.message = z2.prettifyError(e);
195
+ } else if (isHttpError(e)) {
196
+ err = e;
197
+ } else {
198
+ err = InternalServerError;
199
+ log(context).error("Catch an error. Details: %s", e);
200
+ }
201
+ return err;
202
+ }
203
+ var setUp = createMiddleware(
204
+ async (context, next) => {
205
+ const timer = new Timer2();
206
+ timer.tick();
207
+ try {
208
+ log(context).info("[start] %s %s", context.req.method, context.req.path);
209
+ await next();
210
+ log(context).info("[end]", {
211
+ status: context.res.status,
212
+ duration: timer.tock()
213
+ });
214
+ } catch (err) {
215
+ const response = tearDown(err, context);
216
+ log(context).info("[end]", {
217
+ status: response.status,
218
+ duration: timer.tock()
219
+ });
220
+ return response;
221
+ }
222
+ }
223
+ );
224
+ var tearDown = (err, context) => {
225
+ debug("Tear down with error:", err);
226
+ const { code, message, status } = toHttpError(context, err);
227
+ return context.json({ code, message }, status);
228
+ };
229
+
230
+ // src/lib/loader.ts
231
+ var ModuleLoader = class _ModuleLoader {
232
+ modules;
233
+ constructor(modules) {
234
+ this.modules = modules;
235
+ }
236
+ static load(app, ...modules) {
237
+ const loader = new _ModuleLoader(modules);
238
+ loader.modules.forEach((module) => {
239
+ module.install(app);
240
+ debug(
241
+ "Module is loaded => %s",
242
+ `${Object.getPrototypeOf(module).constructor.name}`
243
+ );
244
+ });
245
+ }
246
+ };
247
+
248
+ // src/lib/app.ts
249
+ function createApp(...modules) {
250
+ let app;
251
+ if (env.APP_BASE_PATH) {
252
+ app = new Hono().basePath(env.APP_BASE_PATH);
253
+ debug(`App base path set to '${env.APP_BASE_PATH}'`);
254
+ } else {
255
+ app = new Hono();
256
+ }
257
+ app.use(setUp);
258
+ ModuleLoader.load(app, ...modules);
259
+ app.onError(tearDown);
260
+ return app;
261
+ }
262
+ var AppFactory = {
263
+ create: (data) => {
264
+ if (data && Array.isArray(data)) {
265
+ return createApp(...data);
266
+ }
267
+ return new Hono();
268
+ }
269
+ };
270
+
271
+ // src/lib/auth.ts
272
+ function getCurrentUser(context) {
273
+ const user = context.get("user");
274
+ if (!user) {
275
+ throw new Error("User not found");
276
+ }
277
+ return user;
278
+ }
279
+
280
+ // src/middleware/auth.ts
281
+ import {
282
+ requireUser,
283
+ requireUserRole,
284
+ requireUserPermission,
285
+ extractBearerToken
286
+ } from "@opble/auth0";
287
+ import { PublicUserFactory, PublicUserSchema } from "@opble/entity-auth";
288
+ import { createMiddleware as createMiddleware2 } from "hono/factory";
289
+ var systemUser = PublicUserFactory.create({
290
+ id: "system",
291
+ name: "System",
292
+ email: "system@wewise.net",
293
+ role: "admin",
294
+ emailVerified: true
295
+ });
296
+ var toHeaderGetter = (context) => {
297
+ return {
298
+ get: (name) => context.req.header(name)
299
+ };
300
+ };
301
+ function isAuthenticated(context) {
302
+ const user = context.get("user");
303
+ if (!user) {
304
+ return false;
305
+ }
306
+ return PublicUserSchema.safeParse(user).success;
307
+ }
308
+ var auth = createMiddleware2(
309
+ async (context, next) => {
310
+ if (!isAuthenticated(context)) {
311
+ try {
312
+ const user = await requireUser(toHeaderGetter(context));
313
+ context.set("user", user);
314
+ } catch (e) {
315
+ return tearDown(e, context);
316
+ }
317
+ }
318
+ await next();
319
+ }
320
+ );
321
+ var authAllowRole = (...roles) => {
322
+ return createMiddleware2(async (context, next) => {
323
+ if (!isAuthenticated(context)) {
324
+ context.set(
325
+ "user",
326
+ await requireUserRole(toHeaderGetter(context), ...roles)
327
+ );
328
+ }
329
+ await next();
330
+ });
331
+ };
332
+ var authAllowPermission = (...permissions) => {
333
+ return createMiddleware2(async (context, next) => {
334
+ if (!isAuthenticated(context)) {
335
+ context.set(
336
+ "user",
337
+ await requireUserPermission(toHeaderGetter(context), ...permissions)
338
+ );
339
+ }
340
+ await next();
341
+ });
342
+ };
343
+ var authAllowKeys = (...keys) => {
344
+ return createMiddleware2(async (context, next) => {
345
+ if (!isAuthenticated(context)) {
346
+ const token = extractBearerToken(toHeaderGetter(context));
347
+ if (token && keys.includes(token)) {
348
+ context.set("user", systemUser);
349
+ }
350
+ }
351
+ await next();
352
+ });
353
+ };
354
+
355
+ // src/lib/constant.ts
356
+ var UP = "UP";
357
+
358
+ // src/module/service-status.ts
359
+ var ServiceStatusModule = class {
360
+ options;
361
+ constructor(options = {}) {
362
+ this.options = options;
363
+ }
364
+ install(app) {
365
+ const handler = new ServiceStatusHandler();
366
+ app.get("/health", handler.checkHealth);
367
+ }
368
+ };
369
+ var ServiceStatusHandler = class {
370
+ checkHealth = (context) => {
371
+ return context.json({
372
+ status: UP
373
+ });
374
+ };
375
+ };
376
+
377
+ // src/module/cors.ts
378
+ import { createDebug as createDebug2 } from "@opble/debug";
379
+ import { cors } from "hono/cors";
380
+ var wildcardToRegExp = (pattern) => {
381
+ const hasScheme = pattern.indexOf("://") !== -1;
382
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, (m) => `\\${m}`);
383
+ const wildcardReplaced = escaped.replace(/\*/g, ".*");
384
+ const regexStr = hasScheme ? `^${wildcardReplaced}$` : `^https?://${wildcardReplaced}$`;
385
+ return new RegExp(regexStr);
386
+ };
387
+ var debug2 = createDebug2("opble:core:CorsModule");
388
+ var CorsModule = class {
389
+ install(app) {
390
+ debug2("CORS_ALLOW_ORIGIN:", env.CORS_ALLOW_ORIGIN);
391
+ app.use(
392
+ "/*",
393
+ cors({
394
+ origin: (origin) => {
395
+ for (const allowedOrigin of env.CORS_ALLOW_ORIGIN) {
396
+ if (allowedOrigin === "*") {
397
+ return origin ?? "";
398
+ }
399
+ if (origin === allowedOrigin) {
400
+ return origin;
401
+ }
402
+ if (allowedOrigin.indexOf("*") !== -1) {
403
+ const re = wildcardToRegExp(allowedOrigin);
404
+ if (origin && re.test(origin)) {
405
+ return origin;
406
+ }
407
+ }
408
+ }
409
+ return "";
410
+ },
411
+ allowHeaders: env.CORS_ALLOW_HEADERS,
412
+ allowMethods: env.CORS_ALLOW_METHODS
413
+ })
414
+ );
415
+ }
416
+ };
417
+
418
+ // src/module/rate-limiter.ts
419
+ import { createDebug as createDebug3 } from "@opble/debug";
420
+ import { rateLimiter } from "hono-rate-limiter";
421
+ var debug3 = createDebug3("opble:core:rate-limiter");
422
+ var RateLimiterModule = class {
423
+ constructor(options = { paths: ["/*"] }) {
424
+ this.options = options;
425
+ }
426
+ install(app) {
427
+ debug3("Use Rate Limiter:", env.USE_RATE_LIMIT);
428
+ if (!env.USE_RATE_LIMIT) {
429
+ return;
430
+ }
431
+ debug3("Installing RateLimiterModule with options:", this.options);
432
+ debug3(
433
+ `Rate limiting: ${env.RATE_LIMIT} requests per ${env.RATE_LIMIT_WINDOW} ms`
434
+ );
435
+ const limiter = rateLimiter({
436
+ windowMs: env.RATE_LIMIT_WINDOW,
437
+ limit: env.RATE_LIMIT,
438
+ standardHeaders: "draft-7",
439
+ keyGenerator: (c) => c.req.header("x-forwarded-for") ?? "anonymous"
440
+ });
441
+ for (const path of this.options.paths) {
442
+ app.use(path, limiter);
443
+ }
444
+ }
445
+ };
446
+ export {
447
+ AppFactory,
448
+ BaseController,
449
+ CorsModule,
450
+ CrudController,
451
+ LoggerFactory,
452
+ ModuleLoader,
453
+ RateLimiterModule,
454
+ ServiceStatusModule,
455
+ auth,
456
+ authAllowKeys,
457
+ authAllowPermission,
458
+ authAllowRole,
459
+ getCurrentUser,
460
+ log,
461
+ setUp,
462
+ tearDown
463
+ };
464
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/controller/base.ts","../src/controller/crud.ts","../src/lib/app.ts","../src/middleware/app.ts","../src/lib/debugger.ts","../src/lib/logger.ts","../src/lib/env.ts","../src/lib/loader.ts","../src/lib/auth.ts","../src/middleware/auth.ts","../src/lib/constant.ts","../src/module/service-status.ts","../src/module/cors.ts","../src/module/rate-limiter.ts"],"sourcesContent":["export class BaseController {}\n","import {\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';\nimport { DynamoDBRepository, TableKey } from '@opble/repository-dynamodb';\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 { 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 {\n BadRequestError,\n HttpError,\n InternalServerError,\n isHttpError,\n} from '@opble/types';\nimport { Timer } from '@opble/toolkit';\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 { createDebug } from '@opble/debug';\n\nexport const debug = createDebug('opble:core');\n","import { Factory, StringHashMap } from '@opble/types';\nimport { Logger } from '@opble/types';\nimport { Timer } from '@opble/toolkit';\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 { 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 { 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 { 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","export const UP = 'UP';\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"],"mappings":"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","names":["Timer","z","transports","z","Timer","createMiddleware","createMiddleware","createDebug","debug","createDebug","createDebug","debug","createDebug"]}